collective

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

diff --git a/crates/ui-egui/src/render.rs b/crates/ui-egui/src/render.rs--- a/crates/ui-egui/src/render.rs+++ b/crates/ui-egui/src/render.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())     } } diff --git a/crates/ui-egui/src/render/thumbnail_tests.rs b/crates/ui-egui/src/render/thumbnail_tests.rs--- a/crates/ui-egui/src/render/thumbnail_tests.rs+++ b/crates/ui-egui/src/render/thumbnail_tests.rs@@ -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