Browse / github.com/storytold/lightcraft / patch
Issue #3067: ui-egui test apps render on two workers, not six (peak −22 %)
Every test app starts its own render pool of up to 6 threads: 16 concurrent tests run about 96 render workers on 16 cores Part of #3057. ## Summary Every `LightcraftApp` starts its own render pool. On a machine with 8 or more cores that pool has 6 worker threads. The ui-egui tests build an app in most tests, so the number of render threads grows with the number of tests running at once: - **16 tests at once (plain `cargo test` on 16 cores):** about 96 render workers. - **Shared on top of that:** rayon's global pool and the demo-scene pool, each sized to every core. Even at `RUST_TEST_THREADS=4` the ui-egui tests kept about 13 of 16 cores busy (load average ~21). At 16 tests, the process had 145 threads and a
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- THEtheChad (imported from pull request #3113, open)
- Base
c9860ea7a3fa367451acd9d8cf23538c345192c6- Size
- +39 −2 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
d05217b055658664bdb4767e
How it went
No other operator has reported using it yet.
Diff
raw · crates/ui-egui/src/render.rs crates/ui-egui/src/render/thumbnail_tests.rs
@@ -267,10 +267,28 @@ impl Slot { } } +/// Render workers of an app built by this crate's own tests. Most of them build an app, several+/// run at once, and a test needs a render or two at a time, not the machine's six (issue #3067:+/// sixteen tests at once ran about 96 render threads on 16 cores). A test that needs more asks+/// for them with [`Renderer::with_worker_threads`].+#[cfg(test)]+pub(crate) const TEST_WORKERS: usize = 2;++/// Render workers an app starts with: the machine's job-pool size, at most six (none on wasm).+#[cfg(not(test))]+fn default_workers() -> usize {+ if cfg!(target_arch = "wasm32") { 0 } else { JobPool::<Slot, Finished>::default_threads().min(6) }+}++/// Render workers an app starts with in this crate's tests: [`TEST_WORKERS`].+#[cfg(test)]+fn default_workers() -> usize {+ TEST_WORKERS+}+ impl Default for Renderer { fn default() -> Self {- let threads = if cfg!(target_arch = "wasm32") { 0 } else { JobPool::<Slot, Finished>::default_threads().min(6) };- Self::with_worker_threads(threads)+ Self::with_worker_threads(default_workers()) } } @@ -446,6 +446,25 @@ fn a_panicking_render_is_a_failure_not_a_dead_worker() { assert_eq!(app.renderer.live_workers(), workers); } +/// An app built by this crate's tests renders on two workers, not the machine's six: several+/// tests run at once, and each of them used to start six (issue #3067).+#[test]+fn a_test_app_renders_on_two_workers() {+ let (mut app, _, ctx) = fixture_with(Session::new(), (*photo()).clone());+ app.renderer.offload = None; // the real job pool+ let slot = Slot::Thumb(PhotoId(1));+ let job = app.session.thumb_job(PhotoId(1), 256).unwrap();+ app.renderer.request(slot, job, 30);+ assert_eq!(app.renderer.live_workers(), TEST_WORKERS, "the pool starts all its workers with its first job");+ let t0 = std::time::Instant::now();+ while app.renderer.is_pending(slot) {+ assert!(t0.elapsed() < std::time::Duration::from_secs(20), "the render never answered");+ std::thread::sleep(std::time::Duration::from_millis(5));+ app.renderer.poll(&ctx, &mut app.session);+ }+ assert!(app.renderer.textures.contains_key(&slot), "{:?}", app.renderer.failure(slot));+}+ #[test] fn raw_quick_path_frames_build_no_jobs() { // an unedited raw: the grid shows its embedded preview (held here until released) and stops