( i: usize, progress_index: usize, progress_total: usize, ixon_env: &IxonEnv, lookups: &IxonIngressLookups, names: &[Name], expect_pass: &[bool], ungrounded: &FxHashMap<Name, String>,
| 2278 | let mut handles: Vec<thread::JoinHandle<()>> = |
| 2279 | Vec::with_capacity(worker_count); |
| 2280 | for worker_idx in 0..worker_count { |
| 2281 | let env = Arc::clone(&env); |
| 2282 | let work = Arc::clone(&work); |
| 2283 | let next_index = Arc::clone(&next_index); |
| 2284 | let passed = Arc::clone(&passed); |
| 2285 | let failed = Arc::clone(&failed); |
| 2286 | let sinks = Arc::clone(&sinks); |
| 2287 | let handle = thread::Builder::new() |
| 2288 | .name(format!("ix-kernel-profile-{worker_idx}")) |
| 2289 | .stack_size(KERNEL_CHECK_STACK_SIZE) |
| 2290 | .spawn(move || { |
| 2291 | let mut kenv = KEnv::<Anon>::new(); |
| 2292 | kenv.profile_sink = Some(ProfileSink::new(isolate)); |
| 2293 | let clear_every = kernel_check_clear_every(); |
| 2294 | let mut checks_since_clear = clear_every; |
| 2295 | loop { |
| 2296 | let work_idx = next_index.fetch_add(1, Ordering::Relaxed); |
| 2297 | if work_idx >= work_total { |
| 2298 | break; |
| 2299 | } |
| 2300 | // `clear_releasing_memory` preserves `profile_sink`, so recording |
| 2301 | // accumulates across scheduled-block boundaries. |
| 2302 | if checks_since_clear >= clear_every { |
| 2303 | kenv.clear_releasing_memory(); |
| 2304 | checks_since_clear = 0; |
| 2305 | } |
| 2306 | let primary_addr = match &work[work_idx] { |
| 2307 | AnonWorkItem::Standalone { addr, .. } => addr.clone(), |
| 2308 | AnonWorkItem::Block { primary_addr, .. } => primary_addr.clone(), |
| 2309 | }; |
| 2310 | let kid = KId::<Anon>::new(primary_addr, ()); |
| 2311 | let res = { |
| 2312 | let mut tc = |
| 2313 | TypeChecker::<Anon>::new_with_lazy_anon(&mut kenv, &env); |
| 2314 | let r = tc.check_const(&kid); |
| 2315 | // The TypeChecker is recreated per work item, so the final |
| 2316 | // constant's record would never be flushed by a trailing reset — |
| 2317 | // flush it explicitly. |
| 2318 | tc.finish_constant_accounting(); |
| 2319 | r |
| 2320 | }; |
| 2321 | if res.is_ok() { |
| 2322 | passed.fetch_add(1, Ordering::Relaxed); |
| 2323 | } else { |
| 2324 | failed.fetch_add(1, Ordering::Relaxed); |
| 2325 | } |
| 2326 | checks_since_clear += 1; |
| 2327 | } |
| 2328 | if let Some(sink) = kenv.profile_sink.take() { |
| 2329 | sinks.lock().unwrap().push(sink); |
| 2330 | } |
| 2331 | }) |
| 2332 | .map_err(|e| format!("spawn profile worker: {e}"))?; |
| 2333 | handles.push(handle); |
| 2334 | } |
| 2335 | |
| 2336 | let mut panicked = false; |
| 2337 | for h in handles { |
no test coverage detected