use rusty_h264_common::YuvFrame;
use rusty_h264_decoder::Decoder;
use rusty_h264_encoder::{Encoder, EncoderConfig};
fn make_clip(w: usize, h: usize, n: usize) -> Vec<YuvFrame> {
let bg: Vec<u8> = (0..w * h)
.map(|idx| {
let (i, j) = (idx % w, idx / w);
(((i * 3 + j * 2) ^ ((i * 7) & (j * 5)) ^ (i * j >> 5)) & 0xff) as u8
})
.collect();
let (cw, ch) = (w / 2, h / 2);
(0..n)
.map(|t| {
let mut y = vec![0u8; w * h];
for j in 0..h {
for i in 0..w {
y[j * w + i] = bg[j * w + ((i + t * 3) % w)];
}
}
for (k, &(sx, sy, sp)) in [(40, 30, 5usize), (150, 90, 7), (250, 180, 4), (80, 200, 6)]
.iter()
.enumerate()
{
let bx = (sx + t * sp) % (w - 40);
let by = (sy + t * sp.saturating_sub(2)) % (h - 40);
let base = (40 + k * 50) as u8;
for dy in 0..36 {
for dx in 0..36 {
y[(by + dy) * w + (bx + dx)] = base ^ (((dx ^ dy) & 0x1f) as u8);
}
}
}
let chroma = |off: usize| -> Vec<u8> {
(0..cw * ch)
.map(|idx| (128 + (((idx + t + off) >> 3) & 0x0f) as i32 - 8) as u8)
.collect()
};
YuvFrame {
width: w,
height: h,
y,
u: chroma(0),
v: chroma(5),
}
})
.collect()
}
#[test]
#[ignore = "perf instrument: run with --release [--features profile] -- --ignored --nocapture"]
fn profile_decode() {
let (w, h, n) = (1280, 720, 10);
let frames = make_clip(w, h, n);
let mut cfg = EncoderConfig::new(w, h);
cfg.gop_size = n as u32;
cfg.qp = 26;
let mut enc = Encoder::new(cfg).expect("encoder init");
let aus: Vec<Vec<u8>> = frames.iter().map(|f| enc.encode(f)).collect();
let stream_bytes: usize = aus.iter().map(|a| a.len()).sum();
const REPS: usize = 5;
let mut best = std::time::Duration::MAX;
let mut px = 0usize;
for _ in 0..REPS {
let mut dec = Decoder::new();
let t = std::time::Instant::now();
let mut p = 0;
for au in &aus {
if let Some(fr) = dec.decode(au).expect("decode") {
p += fr.width * fr.height;
}
}
best = best.min(t.elapsed());
px = p;
}
let mpx_s = px as f64 / best.as_secs_f64() / 1e6;
eprintln!(
"\n=== profile_decode — {w}x{h} x{n} frames (1 IDR + {} P), {} KiB stream ===",
n - 1,
stream_bytes / 1024
);
eprintln!(
"throughput: {:.1} Mpx/s (best of {REPS}: {:.1} ms/run, {px} luma px)",
mpx_s,
best.as_secs_f64() * 1e3
);
eprintln!(" measure throughput WITHOUT --features profile; the breakdown below needs it ON");
rusty_h264_common::prof::reset();
let mut dec = Decoder::new();
for au in &aus {
let _ = dec.decode(au).expect("decode");
}
rusty_h264_common::prof::dump();
}
#[test]
#[ignore = "perf instrument: run with --release --features profile -- --ignored --nocapture"]
fn profile_decode_meticulous() {
use rusty_h264_common::prof;
let (w, h, n) = (1280, 720, 10);
let frames = make_clip(w, h, n);
let mut cfg = EncoderConfig::new(w, h);
cfg.gop_size = n as u32;
cfg.qp = 26;
let mut enc = Encoder::new(cfg).expect("encoder init");
let aus: Vec<Vec<u8>> = frames.iter().map(|f| enc.encode(f)).collect();
let px: usize = n * w * h;
let decode_all = |aus: &[Vec<u8>]| {
let mut dec = Decoder::new();
for au in aus {
let _ = dec.decode(au).expect("decode");
}
};
let mut wall_best = f64::MAX;
for _ in 0..15 {
let t = std::time::Instant::now();
decode_all(&aus);
wall_best = wall_best.min(t.elapsed().as_secs_f64() * 1e3);
}
const M: usize = 8_000_000;
prof::reset();
let t = std::time::Instant::now();
for _ in 0..M {
let g = prof::scope(prof::Stage::Neighbors);
std::hint::black_box(&g);
}
let scope_ns = t.elapsed().as_nanos() as f64 / M as f64;
const PREPS: usize = 31;
let mut runs: Vec<[(f64, u64); rusty_h264_common::prof::N]> = Vec::with_capacity(PREPS);
for _ in 0..PREPS {
prof::reset();
decode_all(&aus);
runs.push(prof::snapshot());
}
prof::reset();
let n_stages = rusty_h264_common::prof::N;
let sub = n_stages - 1; let median = |vals: &mut Vec<f64>| -> f64 {
vals.sort_by(|a, b| a.partial_cmp(b).unwrap());
vals[vals.len() / 2]
};
let stat = |i: usize| -> (f64, f64, f64, u64) {
let mut v: Vec<f64> = runs.iter().map(|r| r[i].0).collect();
let (mn, mx) = (
v.iter().cloned().fold(f64::MAX, f64::min),
v.iter().cloned().fold(0.0, f64::max),
);
let calls = runs[0][i].1;
(median(&mut v), mn, mx, calls)
};
let profile_on = stat(sub).0 > 1.0; eprintln!("\n=== profile_decode_meticulous — {w}x{h} x{n} ({PREPS} passes, median) ===");
if !profile_on {
eprintln!(" (profiler OFF — this IS the honest wall; rerun with --features profile for the breakdown)");
eprintln!(" profiler-OFF wall: {wall_best:.1} ms ({:.1} Mpx/s)", px as f64 / (wall_best / 1e3) / 1e6);
return;
}
let total = stat(sub);
let total_calls: u64 = (0..sub).map(|i| runs[0][i].1).sum();
let overhead_ms = total_calls as f64 * scope_ns / 1e6;
let sub_ms_sum: f64 = (0..sub).map(|i| stat(i).0).sum();
let mgmt = (total.0 - sub_ms_sum).max(0.0);
eprintln!(
" per-scope timer overhead: {scope_ns:.1} ns → {total_calls} scope entries = {overhead_ms:.1} ms of the profile",
);
eprintln!(" {:<15} {:>8} {:>8} {:>8} {:>7} {:>12}", "stage", "med ms", "min", "max", "% tot", "calls");
let mut ordered: Vec<usize> = (0..sub).collect();
ordered.sort_by(|&a, &b| stat(b).0.partial_cmp(&stat(a).0).unwrap());
for &i in &ordered {
let (med, mn, mx, calls) = stat(i);
eprintln!(
" {:<15} {:>8.2} {:>8.2} {:>8.2} {:>6.1}% {:>12}",
prof::name(i), med, mn, mx, 100.0 * med / total.0, calls,
);
}
eprintln!(
" {:<15} {:>8.2} {:>29.1}% ({:.1} ms overhead + {:.1} ms real glue)",
"mgmt/other", mgmt, 100.0 * mgmt / total.0,
overhead_ms.min(mgmt), (mgmt - overhead_ms).max(0.0),
);
eprintln!(" {:<15} {:>8.2} {:>29.1}% (profile-ON wall {wall_best:.1} ms)", "TOTAL (on)", total.0, 100.0);
let real = total.0 - overhead_ms;
eprintln!(
"\n real decode ≈ TOTAL_on {:.1} − timer overhead {:.1} = {:.1} ms = {:.1} Mpx/s",
total.0, overhead_ms, real, px as f64 / (real / 1e3) / 1e6,
);
eprintln!(" (confirm vs the profiler-OFF throughput from the plain `profile_decode` test)");
eprintln!(" the REAL per-stage levers are the median-ms column, ranked above.");
}
fn probe_clip(w: usize, h: usize, n: usize) -> Vec<YuvFrame> {
let (cw, ch) = (w / 2, h / 2);
(0..n)
.map(|t| {
let y = (0..w * h)
.map(|i| {
let (x, j) = (i % w, i / w);
(((x * 7 + j * 5 + t * 13) ^ (x.wrapping_mul(j) >> 4) ^ (t * 29)) & 0xff) as u8
})
.collect();
let chroma = |o: usize| -> Vec<u8> {
(0..cw * ch)
.map(|i| {
let (x, j) = (i % cw, i / cw);
(((x * 11 + j * 3 + t * 7 + o) ^ (t * 5)) & 0xff) as u8
})
.collect()
};
YuvFrame { width: w, height: h, y, u: chroma(0), v: chroma(64) }
})
.collect()
}
#[test]
#[ignore = "Phase 0 cache probe (see docs/decode-locality-plan.md)"]
fn cache_probe() {
eprintln!("\n=== cache probe — per-pixel decode throughput vs frame size ===");
eprintln!("(working set ~= 3 frames: rec + reference + grids; this machine L2≈2 MiB, L3≈24 MiB)");
eprintln!(" if Mpx/s DROPS as the frame grows, the glue is cache-bound → tiles help\n");
for &(w, h) in &[
(256usize, 256usize),
(384, 384),
(512, 512),
(768, 768),
(1024, 1024),
(1536, 1536),
(1920, 1088),
] {
let n = (8_000_000 / (w * h)).clamp(4, 32);
let frames = probe_clip(w, h, n);
let mut cfg = EncoderConfig::new(w, h);
cfg.gop_size = n as u32; cfg.qp = 26;
let mut enc = Encoder::new(cfg).expect("enc");
let aus: Vec<Vec<u8>> = frames.iter().map(|f| enc.encode(f)).collect();
const REPS: usize = 5;
let mut best = std::time::Duration::MAX;
let mut px = 0usize;
for _ in 0..REPS {
let mut dec = Decoder::new();
let t = std::time::Instant::now();
let mut p = 0;
for au in &aus {
if let Some(fr) = dec.decode(au).expect("dec") {
p += fr.width * fr.height;
}
}
best = best.min(t.elapsed());
px = p;
}
let mpx_s = px as f64 / best.as_secs_f64() / 1e6;
let work_mib = (w * h + 2 * (w / 2) * (h / 2)) * 3 / (1024 * 1024);
eprintln!(
" {w:>4}x{h:<4} ({n:>2} frames, working set ~{work_mib:>2} MiB): {mpx_s:>6.1} Mpx/s",
);
}
}