mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-26 19:17:13 -06:00
51 lines
2.3 KiB
Rust
51 lines
2.3 KiB
Rust
//! Keep the throughput gate in its own executable so parallel correctness tests do not
|
||
//! contend for CPU frequency, caches, or memory bandwidth during its timed workload.
|
||
//! Cargo runs integration-test executables sequentially; the threshold is unchanged.
|
||
|
||
use filmcraft_render::{SourceMap, mixer};
|
||
|
||
#[path = "support/mixer.rs"]
|
||
mod support;
|
||
use support::{SR, busy_rig};
|
||
|
||
/// 24 tracks × 3 inserts (EQ, Dynamics, Studio Reverb) + a compressed submix at 48 kHz, one core.
|
||
#[test]
|
||
// Off Unix there is no per-thread CPU clock (`thread_cpu_secs`), so the timing falls back to wall
|
||
// time, which a loaded CI host (Windows runners run the suite in parallel) can push under the
|
||
// threshold: genuinely timing-flaky there. On Unix it measures this thread's CPU time and stays on.
|
||
#[cfg_attr(not(unix), ignore = "wall-clock timing without a thread CPU clock is load-dependent; run with --ignored")]
|
||
fn perf_24_tracks_3_effects_realtime_factor() {
|
||
let r = busy_rig(24);
|
||
let secs = if cfg!(debug_assertions) { 2.0 } else { 10.0 };
|
||
let n = (secs * SR as f64) as usize;
|
||
let pool = rayon::ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||
// warm up (fresh graph + pre-roll), then time steady-state playback-sized blocks
|
||
pool.install(|| r.mix_cut(0, 4_800, &[1024], None));
|
||
// Thread CPU time, not wall clock: only work done on this one thread matters.
|
||
// The separate executable also avoids interference from this crate's correctness tests.
|
||
let el = pool.install(|| {
|
||
let t0 = thread_cpu_secs();
|
||
let w0 = std::time::Instant::now();
|
||
r.mix_cut(4_800, n, &[1024], None);
|
||
t0.map(|t0| thread_cpu_secs().unwrap_or(t0) - t0).unwrap_or_else(|| w0.elapsed().as_secs_f64())
|
||
});
|
||
let rt = secs / el;
|
||
eprintln!("mixer perf: 24 tracks x 3 inserts + submix, {secs} s of 48 kHz stereo in {el:.3} s of CPU on one core = {rt:.1}x realtime");
|
||
let min = if cfg!(debug_assertions) { 1.0 } else { 4.0 };
|
||
assert!(rt > min, "realtime factor {rt:.2}");
|
||
}
|
||
|
||
/// CPU seconds used by the calling thread (None where there is no thread clock; callers fall back
|
||
/// to wall time).
|
||
fn thread_cpu_secs() -> Option<f64> {
|
||
#[cfg(unix)]
|
||
{
|
||
let t = rustix::time::clock_gettime(rustix::time::ClockId::ThreadCPUTime);
|
||
Some(t.tv_sec as f64 + t.tv_nsec as f64 * 1e-9)
|
||
}
|
||
#[cfg(not(unix))]
|
||
{
|
||
None
|
||
}
|
||
}
|