diff --git a/rtiow/Cargo.lock b/rtiow/Cargo.lock index 1e799f4..8a592dc 100644 --- a/rtiow/Cargo.lock +++ b/rtiow/Cargo.lock @@ -384,6 +384,17 @@ dependencies = [ "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core_affinity" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cpuprofiler" version = "0.0.3" @@ -1604,6 +1615,7 @@ dependencies = [ "actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", "askama 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2458,6 +2470,7 @@ dependencies = [ "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" +"checksum core_affinity 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6d162c6e463c31dbf78fefa99d042156c1c74d404e299cfe3df2923cb857595b" "checksum cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "33f07976bb6821459632d7a18d97ccca005cb5c552f251f822c7c1781c1d7035" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" diff --git a/rtiow/Cargo.toml b/rtiow/Cargo.toml index 62e5af3..825be4b 100644 --- a/rtiow/Cargo.toml +++ b/rtiow/Cargo.toml @@ -12,6 +12,7 @@ name = "spheres" actix-web = "0.7.8" askama = "0.7.1" chrono = "*" +core_affinity = "0.5" cpuprofiler = { version = "0.0.3", optional = true } image = "0.19.0" lazy_static = "1.1.0" diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index 02bb4c4..66f18c5 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -14,6 +14,7 @@ use std::sync::Mutex; use std::thread; use std::time; +use core_affinity; #[cfg(feature = "prom")] use lazy_static::lazy_static; use num_cpus; @@ -461,22 +462,36 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i let scene = Arc::new(scene); let pixel_req_rx = Arc::new(Mutex::new(pixel_req_rx)); - info!("Creating {} render threads", num_threads); info!("Adaptive subsampling: {:?}", scene.adaptive_subsampling); - for i in 0..num_threads { - let s = sync::Arc::clone(&scene); - let pixel_req_rx = pixel_req_rx.clone(); - let pixel_resp_tx = pixel_resp_tx.clone(); - thread::spawn(move || { - render_worker(i, &s, pixel_req_rx, &pixel_resp_tx); - }); - } + // Retrieve the IDs of all active CPU cores. + let core_ids = core_affinity::get_core_ids().unwrap(); + let core_ids = if core_ids.len() > num_threads { + core_ids[..num_threads].to_vec() + } else { + core_ids + }; + info!("Creating {} render threads", core_ids.len()); + // Create a thread for each active CPU core. + let mut handles = core_ids + .into_iter() + .enumerate() + .filter(|(i, _id)| *i < num_threads) + .map(|(i, id)| { + let s = sync::Arc::clone(&scene); + let pixel_req_rx = pixel_req_rx.clone(); + let pixel_resp_tx = pixel_resp_tx.clone(); + thread::spawn(move || { + core_affinity::set_for_current(id); + render_worker(i, &s, pixel_req_rx, &pixel_resp_tx); + }) + }) + .collect::>(); drop(pixel_req_rx); drop(pixel_resp_tx); let start_time = time::Instant::now(); let (w, h) = (scene.width, scene.height); - thread::spawn(move || { + handles.push(thread::spawn(move || { let batch_line_requests = true; if batch_line_requests { for y in 0..h { @@ -494,7 +509,7 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i } } drop(pixel_req_tx); - }); + })); info!("Rendering with {} subsamples", scene.subsamples); output::register_image( @@ -509,7 +524,7 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i } let pixel_total = scene.width * scene.height; - thread::spawn(move || { + handles.push(thread::spawn(move || { let mut last_time = time::Instant::now(); let mut last_pixel_count = PIXEL_COUNT.load(Ordering::SeqCst); let mut last_ray_count = RAY_COUNT.load(Ordering::SeqCst); @@ -524,7 +539,7 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i let pixel_diff = pixel_count - last_pixel_count; let ray_diff = ray_count - last_ray_count; info!( - "{} / {} ({}%) pixels {} pixels/s {} rays/s", + "{} / {}pixels ({}%) {}pixels/s {}rays/s", human.format(pixel_count as f64), human.format(pixel_total as f64), 100 * pixel_count / pixel_total, @@ -534,8 +549,11 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i last_time = now; last_pixel_count = pixel_count; last_ray_count = ray_count; + if pixel_count == pixel_total { + return; + } } - }); + })); for resp in pixel_resp_rx { match resp { @@ -549,11 +567,14 @@ pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::i } } } + for thr in handles { + thr.join().expect("thread join"); + } let human = human::Formatter::new(); let time_diff = time::Instant::now() - start_time; let ray_count = RAY_COUNT.load(Ordering::SeqCst); info!( - "{} pixels {} {}s pixels/s {} rays/s", + "{}pixels {:.2}s {}pixels/s {}rays/s", human.format(pixel_total as f64), time_diff.as_secs_f64(), human.format(pixel_total as f64 / time_diff.as_secs_f64()),