From 61e4a4b3c3eac052bbace8cf713a667b2290d53b Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Fri, 16 Oct 2026 04:10:21 +0000 Subject: [PATCH 1/2] refactor(code-index): drop the activation prewarm CPU knob set_injected_activation_prewarm_cpu spun CPU beside the prewarm so a test could show the debug long-poll guard no longer failed the worker (#4022). With long polls counted instead of failed, the test passes whether or not the prewarm runs on a worker, so the knob and its test go. The prewarm stays on the blocking pool. --- .../code_index_scheduler/graph_activation.rs | 33 ++++------------- .../code_index_scheduler/tests/residency.rs | 35 ------------------- 2 files changed, 7 insertions(+), 61 deletions(-) diff --git a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/graph_activation.rs b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/graph_activation.rs index 1fc7989930..90fc32338a 100644 --- a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/graph_activation.rs +++ b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/graph_activation.rs @@ -46,9 +46,6 @@ struct InjectedActivationFaultsV1 { publication_deadlines: std::collections::BTreeSet, terminal_failures: std::collections::BTreeSet, gates: std::collections::BTreeMap>, - /// CPU time the memory activation spends beside its prewarm, standing in - /// for a prewarm that runs long on a loaded host. - prewarm_cpu: std::collections::BTreeMap, catalog_warm_gates: std::collections::BTreeMap>, } @@ -178,13 +175,6 @@ pub fn injected_activation_attempt_count(worktree_id: &WorktreeId) -> usize { .unwrap_or(0) } -#[cfg(test)] -pub fn set_injected_activation_prewarm_cpu(worktree_id: &WorktreeId, cpu: std::time::Duration) { - injected_faults() - .prewarm_cpu - .insert(worktree_id.as_str().to_owned(), cpu); -} - #[cfg(test)] pub fn set_injected_resident_memory_refusal(worktree_id: &WorktreeId, refused: bool) { set_injected_flag( @@ -643,22 +633,13 @@ impl CodeGraphActivationAuthorityV1 { ), )); } - let prewarm_cpu = injected_faults().prewarm_cpu.remove(worktree_id.as_str()); - native_runtime::spawn_blocking(move || { - if let Some(cpu) = prewarm_cpu { - let spun = std::time::Instant::now(); - while spun.elapsed() < cpu { - std::hint::spin_loop(); - } - } - latest.prewarm_serving_derivations(); - }) - .await - .map_err(|error| { - CodeIndexSchedulerErrorV1::GraphActivation(format!( - "code graph activation task failed: {error}" - )) - })?; + native_runtime::spawn_blocking(move || latest.prewarm_serving_derivations()) + .await + .map_err(|error| { + CodeIndexSchedulerErrorV1::GraphActivation(format!( + "code graph activation task failed: {error}" + )) + })?; Ok(None) } } diff --git a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/residency.rs b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/residency.rs index 2e5e7e6b00..114b5106f1 100644 --- a/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/residency.rs +++ b/crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests/residency.rs @@ -2093,38 +2093,3 @@ async fn readers_of_a_build_waiting_for_memory_do_not_spin_the_worker() { registry.shutdown().await; } - -/// A memory activation whose prewarm outlasts the CPU one native poll may -/// spend still seats the generation a reader demanded. The prewarm is -/// synchronous: run inside the worker's poll, the debug long-poll guard fails -/// the worker and the seat never arrives (#4016). -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn a_memory_activation_longer_than_one_native_poll_still_seats() { - let fixture = GitFixture::new(ALPHA_LIB_V1); - let store = TempDir::new().expect("store root"); - let registry = CodeIndexSchedulerRegistryV1::with_background_reconcile_permits(1, 1); - let first_pass = registry - .background_reconcile_admission() - .acquire_owned() - .await - .expect("hold the worker before its first activation"); - registry - .mount_worktree( - test_project_id(), - fixture.path(), - store.path().to_path_buf(), - ) - .await - .expect("mount"); - let scope = registry - .serving_code_scope(fixture.path()) - .await - .expect("mounted scope"); - super::super::graph_activation::set_injected_activation_prewarm_cpu( - &scope.worktree_id, - tracedecay_runtime_core::native_runtime::LONG_POLL_CPU * 4, - ); - drop(first_pass); - wait_for_live_complete_generation(®istry, fixture.path()).await; - registry.shutdown().await; -} From 83dc99b06fc8b0303fcebe43d7a50bbdec86f6c9 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Fri, 16 Oct 2026 04:10:25 +0000 Subject: [PATCH 2/2] refactor(store-runtime): drop the convergence trim CPU knob inject_registered_schema_convergence_trim_cpu_for_test spun CPU beside malloc_trim for the same guard-only test (#4027). It goes with that test. The trim stays on the blocking pool. --- .../src/session_registry/maintenance.rs | 36 +----------------- .../src/daemon/store_runtime_tests.rs | 38 ------------------- 2 files changed, 1 insertion(+), 73 deletions(-) diff --git a/crates/tracedecay-store-runtime/src/session_registry/maintenance.rs b/crates/tracedecay-store-runtime/src/session_registry/maintenance.rs index 9b2fc7085d..256f3e87c6 100644 --- a/crates/tracedecay-store-runtime/src/session_registry/maintenance.rs +++ b/crates/tracedecay-store-runtime/src/session_registry/maintenance.rs @@ -77,10 +77,6 @@ pub(super) struct RegisteredSchemaConvergenceMaintenance { execution_count: Arc, #[cfg(any(test, feature = "test-helpers"))] gate: StdMutex>>, - /// CPU time spent beside the allocator trim, standing in for a trim of - /// a large heap. - #[cfg(any(test, feature = "test-helpers"))] - trim_cpu: StdMutex>, } enum SchemaConvergenceTarget { @@ -183,8 +179,6 @@ impl RegisteredSchemaConvergenceMaintenance { execution_count: Arc::new(std::sync::atomic::AtomicUsize::new(0)), #[cfg(any(test, feature = "test-helpers"))] gate: StdMutex::new(None), - #[cfg(any(test, feature = "test-helpers"))] - trim_cpu: StdMutex::new(None), } } @@ -317,11 +311,6 @@ impl RegisteredSchemaConvergenceMaintenance { .lock() .expect("registered schema convergence test gate lock remains healthy") .clone(); - #[cfg(any(test, feature = "test-helpers"))] - let trim_cpu = *self - .trim_cpu - .lock() - .expect("registered schema convergence trim cost lock remains healthy"); let statuses = Arc::clone(&self.statuses); let foreground_project_opens = Arc::clone(&self.foreground_project_opens); let concurrency = Arc::clone(&self.concurrency); @@ -372,17 +361,7 @@ impl RegisteredSchemaConvergenceMaintenance { } // `malloc_trim` walks every glibc arena: up to 0.8 s of CPU on a // large heap, which would stall this native worker's I/O. - let _ = native_runtime::spawn_blocking(move || { - #[cfg(any(test, feature = "test-helpers"))] - if let Some(cpu) = trim_cpu { - let spun = std::time::Instant::now(); - while spun.elapsed() < cpu { - std::hint::spin_loop(); - } - } - release_process_allocator_memory_v1() - }) - .await; + let _ = native_runtime::spawn_blocking(release_process_allocator_memory_v1).await; drop(permit); let status = match result { Ok(()) => { @@ -507,14 +486,6 @@ impl RegisteredSchemaConvergenceMaintenance { } } - #[cfg(any(test, feature = "test-helpers"))] - pub(super) fn inject_trim_cpu(&self, cpu: std::time::Duration) { - *self - .trim_cpu - .lock() - .expect("registered schema convergence trim cost lock remains healthy") = Some(cpu); - } - #[cfg(any(test, feature = "test-helpers"))] pub(super) fn install_gate(&self) -> RegisteredSchemaConvergenceTestGate { let state = Arc::new(RegisteredSchemaConvergenceTestGateState { @@ -783,11 +754,6 @@ impl DaemonSessionRuntimeRegistryV1 { self.registered_schema_convergence.install_gate() } - #[cfg(any(test, feature = "test-helpers"))] - pub fn inject_registered_schema_convergence_trim_cpu_for_test(&self, cpu: std::time::Duration) { - self.registered_schema_convergence.inject_trim_cpu(cpu); - } - #[cfg(any(test, feature = "test-helpers"))] pub fn registered_schema_convergence_schedule_count_for_test(&self) -> usize { self.registered_schema_convergence diff --git a/crates/tracedecay/src/daemon/store_runtime_tests.rs b/crates/tracedecay/src/daemon/store_runtime_tests.rs index bc63b09e25..ae6975a853 100644 --- a/crates/tracedecay/src/daemon/store_runtime_tests.rs +++ b/crates/tracedecay/src/daemon/store_runtime_tests.rs @@ -1349,44 +1349,6 @@ async fn schema_convergence_is_reported_and_completes_after_admission() { ); } -/// Convergence ends with a glibc `malloc_trim`, which walks every arena and -/// measured up to 0.8 s of CPU in a loaded test process. Run inside the -/// convergence task's poll, it stalls every socket wake on that native worker, -/// and the debug long-poll guard fails the task as it completes (#4023). -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn schema_convergence_completes_when_its_allocator_trim_outlasts_a_native_poll() { - let (_temporary, identity, project_id, project_root, _sessions_path, _database_scope) = - project_sessions_pending_convergence("project.schema-long-trim").await; - let shard_id = StoreShardIdV1::project_sessions( - identity.brain_id().clone(), - identity.profile_id().clone(), - project_id.clone(), - ); - let registry = DaemonSessionRuntimeRegistryV1::open_with_session_maintenance(identity, true) - .await - .expect("session runtime registry"); - registry.inject_registered_schema_convergence_trim_cpu_for_test( - tracedecay_runtime_core::native_runtime::LONG_POLL_CPU * 4, - ); - - registry - .project_sessions(project_id, [project_root]) - .await - .expect("project sessions admission"); - - assert_eq!( - wait_for_schema_convergence(®istry, &shard_id).await, - RegisteredSchemaConvergenceStatus::Complete - ); - tokio::time::timeout( - MUST_NOT_BLOCK, - registry.shutdown_terminal_tasks(&tracedecay_runtime_core::native_runtime::cx().unwrap()), - ) - .await - .expect("terminal shutdown joins the finished convergence task") - .expect("the convergence task must finish without failing"); -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn foreground_project_open_defers_historical_convergence_until_full_publication() { let (_temporary, identity, project_id, project_root, _sessions_path, _database_scope) =