fix: x2APIC ICR format + build system durability docs
- Fix LocalX2Apic handler: use local_apic.x2 to select correct ICR format (<<32 for x2APIC, <<56 for xAPIC) instead of hardcoded <<32 - Promote x2APIC/xAPIC detection from debug! to info! for bootlog - Document build system durability in AGENTS.md: cardinal rule, two-layer architecture, correct workflow, anti-patterns
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
--- src/context/switch.rs
|
||||
+++ 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);
|
||||
|
||||
Reference in New Issue
Block a user