Files
RedBear-OS/local/patches/kernel/P17-1-numa-selection.patch
T
vasilito cee25393d8 fix: boot process improvements — dependency cycle, INIT_NOTIFY, probing loop, and log spam fixes
- 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)
2026-05-17 12:34:02 +03:00

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);