Skip to content

Commit 4f6c008

Browse files
committed
core: Allow caller to decide whether or not IRQ cores should be reserved
If the system is not configured to pin IRQ handling, or doesn't have enough cores, reserving those is wasteful. So let the caller choose. Also: - Make fields of `TokioCores` `pub`, needed to create an extra runtime - Re-export `CoreId`
1 parent c871610 commit 4f6c008

1 file changed

Lines changed: 18 additions & 15 deletions

File tree

crates/core/src/startup.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use core_affinity::CoreId;
21
use crossbeam_queue::ArrayQueue;
32
use itertools::Itertools;
43
use spacetimedb_paths::server::{ConfigToml, LogsDir};
@@ -16,6 +15,8 @@ use tracing_subscriber::{reload, EnvFilter};
1615
use crate::config::{ConfigFile, LogConfig};
1716
use crate::util::jobs::JobCores;
1817

18+
pub use core_affinity::CoreId;
19+
1920
pub struct TracingOptions {
2021
pub config: LogConfig,
2122
/// Whether or not to periodically reload the log config in the background.
@@ -196,6 +197,13 @@ pub struct CoreReservations {
196197
///
197198
/// Default: 1/8
198199
pub rayon: f64,
200+
/// Cores to reserve for IRQ handling.
201+
///
202+
/// This will be the first `n` [`CoreId`]s in the list.
203+
/// Only make use of this if you're configuring the machine for IRQ pinning!
204+
///
205+
/// Default: 0
206+
pub irq: usize,
199207
/// Extra reserved cores.
200208
///
201209
/// If greater than zero, this many cores will be reserved _before_
@@ -211,6 +219,7 @@ impl Default for CoreReservations {
211219
databases: 1.0 / 8.0,
212220
tokio_workers: 4.0 / 8.0,
213221
rayon: 1.0 / 8.0,
222+
irq: 0,
214223
reserved: 0,
215224
}
216225
}
@@ -221,13 +230,15 @@ impl CoreReservations {
221230
///
222231
/// Returns the allocated cores in the order:
223232
///
233+
/// - irq
224234
/// - reserved
225235
/// - databases
226236
/// - tokio_workers
227237
/// - rayon
228238
///
229239
/// Left public for testing and debugging purposes.
230-
pub fn apply(&self, cores: &mut Vec<CoreId>) -> [Vec<CoreId>; 4] {
240+
pub fn apply(&self, cores: &mut Vec<CoreId>) -> [Vec<CoreId>; 5] {
241+
let irq = cores.drain(..self.irq).collect_vec();
231242
let reserved = cores.drain(..self.reserved).collect_vec();
232243

233244
let total = cores.len() as f64;
@@ -240,7 +251,7 @@ impl CoreReservations {
240251
let tokio_workers = claim(cores, frac(self.tokio_workers)).collect_vec();
241252
let rayon = claim(cores, frac(self.rayon)).collect_vec();
242253

243-
[reserved, databases, tokio_workers, rayon]
254+
[irq, reserved, databases, tokio_workers, rayon]
244255
}
245256
}
246257

@@ -273,7 +284,7 @@ impl Cores {
273284
fn get(reservations: CoreReservations) -> Option<Self> {
274285
let mut cores = Self::get_core_ids()?;
275286

276-
let [reserved, databases, tokio_workers, rayon] = reservations.apply(&mut cores);
287+
let [_irq, reserved, databases, tokio_workers, rayon] = reservations.apply(&mut cores);
277288

278289
let reserved = (!reserved.is_empty()).then(|| reserved.into());
279290
let databases = databases.into_iter().collect::<JobCores>();
@@ -306,20 +317,12 @@ impl Cores {
306317

307318
/// Get the cores of the local host, as reported by the operating system.
308319
///
309-
/// Cores 0 and 1 are not included in the returned vec, as we reserve them
310-
/// for the operating system.
311-
///
312-
/// Returns `None` if `num_cpus - 2` is less than 8.
320+
/// Returns `None` if `num_cpus` is less than 8.
313321
/// If `Some` is returned, the `Vec` is non-empty.
314322
pub fn get_core_ids() -> Option<Vec<CoreId>> {
315323
let cores = core_affinity::get_core_ids()
316324
.filter(|cores| cores.len() >= 10)?
317325
.into_iter()
318-
// We reserve the first two cores for the OS.
319-
// This allows us to pin interrupt handlers (IRQs) to these cores,
320-
// particularly those for incoming network traffic,
321-
// preventing them from preempting the main reducer threads.
322-
.filter(|core_id| core_id.id > 1)
323326
.collect_vec();
324327

325328
(!cores.is_empty()).then_some(cores)
@@ -328,14 +331,14 @@ impl Cores {
328331

329332
#[derive(Default)]
330333
pub struct TokioCores {
331-
workers: Option<Vec<CoreId>>,
334+
pub workers: Option<Vec<CoreId>>,
332335
// For blocking threads, we don't want to limit them to a specific number
333336
// and pin them to their own cores - they're supposed to run concurrently
334337
// with each other. However, `core_affinity` doesn't support affinity masks,
335338
// so we just use the Linux-specific API, since this is only a slight boost
336339
// and we don't care enough about performance on other platforms.
337340
#[cfg(target_os = "linux")]
338-
blocking: Option<nix::sched::CpuSet>,
341+
pub blocking: Option<nix::sched::CpuSet>,
339342
}
340343

341344
impl TokioCores {

0 commit comments

Comments
 (0)