cee25393d8
- Fix P15-8-init-cycle-detection.patch: replace visiting+error with seen+silent-skip to eliminate 11 false-positive 'dependency cycle detected' errors on shared deps - Fix P0-daemon-fix-init-notify-unwrap.patch: remove eprintln! for missing INIT_NOTIFY (expected for oneshot_async services, ~7 daemons affected) - Fix driver-manager hotplug loop: add PERMANENTLY_SKIPPED static set shared between hotplug handler and DriverConfig::probe() to stop infinite re-probing of Fatal/NotSupported/deferred-exhausted device+driver pairs (e.g. ided) - Fix driver-manager log_timeline: suppress repeated EPIPE/ENOENT errors with AtomicI32 dedup and AtomicBool one-shot guards for boot timeline JSON - Add driver-manager SIGTERM handler, ACPI bus registration, --status mode, driver reap loop, graceful shutdown, and reduced deferred retries (30→3)
88 lines
3.7 KiB
Diff
88 lines
3.7 KiB
Diff
--- a/src/context/switch.rs
|
|
+++ b/src/context/switch.rs
|
|
@@ -361,6 +361,7 @@
|
|
}
|
|
|
|
/// This is the scheduler function which currently utilises Deficit Weighted Round Robin Scheduler
|
|
+/// with NUMA-aware context selection preference.
|
|
fn select_next_context(
|
|
token: &mut CleanLockToken,
|
|
percpu: &PercpuBlock,
|
|
@@ -386,6 +387,10 @@
|
|
let total_contexts: usize = contexts_list.iter().map(|q| q.len()).sum();
|
|
let mut skipped_contexts = 0;
|
|
|
|
+ // NUMA-aware selection: remember cross-node fallback candidate.
|
|
+ let my_numa_node = percpu.numa_node.get();
|
|
+ let mut cross_node_fallback: Option<(usize, ArcContextLockWriteGuard)> = None;
|
|
+
|
|
'priority: loop {
|
|
i = (i + 1) % 40;
|
|
total_iters += 1;
|
|
@@ -450,11 +455,44 @@
|
|
// Is this context runnable on this CPU?
|
|
let sw = unsafe { update_runnable(&mut next_context_guard, cpu_id, switch_time) };
|
|
if let UpdateResult::CanSwitch = sw {
|
|
- // Cache the new context's priority for MCS lock priority donation.
|
|
- percpu.current_prio.set(next_context_guard.prio);
|
|
- next_context_guard_opt = Some(next_context_guard);
|
|
- balance[i] -= SCHED_PRIO_TO_WEIGHT[20];
|
|
- break 'priority;
|
|
+ // NUMA-aware selection: check if this context's last CPU was on the same node.
|
|
+ let same_node = if my_numa_node != u8::MAX {
|
|
+ next_context_guard.cpu_id
|
|
+ .map(|cid| {
|
|
+ crate::percpu::get_for_cpu(cid)
|
|
+ .map(|p| p.numa_node.get() == my_numa_node)
|
|
+ .unwrap_or(false)
|
|
+ })
|
|
+ .unwrap_or(true) // New context (no last CPU) — treat as same node
|
|
+ } else {
|
|
+ true // No NUMA info — treat all as same node
|
|
+ };
|
|
+
|
|
+ if same_node {
|
|
+ // Cache-warm: select immediately
|
|
+ percpu.current_prio.set(next_context_guard.prio);
|
|
+ next_context_guard_opt = Some(next_context_guard);
|
|
+ balance[i] -= SCHED_PRIO_TO_WEIGHT[20];
|
|
+ break 'priority;
|
|
+ } else {
|
|
+ // Cross-node candidate: save as fallback, keep scanning for same-node
|
|
+ if cross_node_fallback.is_none() {
|
|
+ // Cache the priority and balance for later
|
|
+ cross_node_fallback =
|
|
+ Some((next_context_guard.prio, next_context_guard));
|
|
+ balance[i] -= SCHED_PRIO_TO_WEIGHT[20];
|
|
+ // Don't break — keep looking for a same-node context
|
|
+ continue;
|
|
+ } else {
|
|
+ // Already have a cross-node fallback; push this one back
|
|
+ contexts.push_back(next_context_ref);
|
|
+ skipped_contexts += 1;
|
|
+ if skipped_contexts >= total_contexts {
|
|
+ break 'priority;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
} else {
|
|
if matches!(sw, UpdateResult::Blocked) {
|
|
idle_contexts(token.token()).push_back(next_context_ref);
|
|
@@ -469,6 +507,15 @@
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+ // If we found a cross-node fallback but no same-node context, use it
|
|
+ if next_context_guard_opt.is_none() {
|
|
+ if let Some((prio, guard)) = cross_node_fallback {
|
|
+ percpu.current_prio.set(prio);
|
|
+ next_context_guard_opt = Some(guard);
|
|
+ }
|
|
+ }
|
|
+
|
|
percpu.balance.set(balance);
|
|
percpu.last_queue.set(i);
|
|
|