Step 5 + 6: split two bench binaries into directory form with sibling
helper modules. Cargo auto-discovers src/bin/<name>/main.rs as binary
<name>; no Cargo.toml change needed.
vaapi_import_bench (973 LOC) -> 6 files:
- main.rs main() + mod declarations
- stats.rs BenchArgs + PipelineMode + FrameStats + impl
- software.rs SoftwareEncoder + SwsContext (with Drop) + create_*
+ encode_yuv_frame + finish_encoder
- pipeline_cpu.rs run_cpu_pipeline
- pipeline_gpu.rs import_frame + build_gpu_filter_graph + run_gpu_pipeline
- util.rs output_for_mode + print_detailed_results + print_comparison
sw_encode_bench (547 LOC) -> 2 files:
- main.rs main() + mod declarations (main is ~480 LOC and stays
intact per Oracle/Momis risk note on function
decomposition)
- stats.rs BenchArgs + FrameStats + impl + pix_fmt helper
Both main.rs files use #[path = "../common/mod.rs"] mod common; to keep
sharing src/bin/common/mod.rs (path adjusted for the new directory depth).
DEVATION NOTE on visibility:
The original single-file binaries accessed struct fields across what
became module boundaries (70+ accesses, e.g. encoder.yuv_frame in
run_cpu_pipeline, sws_ctx.0 in run_gpu_pipeline, stats.frames_encoded
in main, stats.mmap_us in main). Rule 2 forbids widening visibility on
struct fields. After 2 build attempts confirmed there is no way to
perform the specified split without widening, the minimum necessary
pub(crate) was applied to:
- vaapi_import_bench/stats.rs: BenchArgs fields, PipelineMode (type
only), FrameStats fields, FrameStats::{avg_ms, avg_total_ms,
achieved_fps, theoretical_fps}
- vaapi_import_bench/software.rs: SoftwareEncoder fields (enc_video,
octx, yuv_frame, codec_name), SwsContext.0, all four functions
- vaapi_import_bench/pipeline_*.rs: run_cpu_pipeline, run_gpu_pipeline,
import_frame (build_gpu_filter_graph kept private)
- vaapi_import_bench/util.rs: output_for_mode, print_detailed_results,
print_comparison
- sw_encode_bench/stats.rs: BenchArgs fields, FrameStats fields,
FrameStats::avg_ms, pix_fmt
No pub (truly public) was used anywhere. All widening is to pub(crate),
keeping these symbols private outside the binary crate.
Verification (all green):
- cargo build --bins / cargo build --release --bins
- cargo test (79 lib + 3 integration = 82 pass, 1 ignored — unchanged)
- cargo clippy --all-targets -- -D warnings
- cargo fmt --check
- --help smoke test on both binaries
77 lines
1.9 KiB
Rust
77 lines
1.9 KiB
Rust
use clap::{Parser, ValueEnum};
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[command(name = "vaapi_import_bench", about = "VAAPI DMA-BUF import benchmark")]
|
|
pub(crate) struct BenchArgs {
|
|
#[arg(short, long)]
|
|
pub(crate) output: String,
|
|
|
|
#[arg(long, default_value_t = 60)]
|
|
pub(crate) frames: u32,
|
|
|
|
#[arg(long, default_value_t = 2560)]
|
|
pub(crate) enc_width: u32,
|
|
|
|
#[arg(long, default_value_t = 1440)]
|
|
pub(crate) enc_height: u32,
|
|
|
|
#[arg(long, default_value = "/dev/dri/renderD128")]
|
|
pub(crate) drm_device: String,
|
|
|
|
#[arg(long, value_enum, default_value_t = PipelineMode::Both)]
|
|
pub(crate) mode: PipelineMode,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
|
|
pub(crate) enum PipelineMode {
|
|
Cpu,
|
|
Gpu,
|
|
Both,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub(crate) struct FrameStats {
|
|
pub(crate) import_us: Vec<u64>,
|
|
pub(crate) filter_us: Vec<u64>,
|
|
pub(crate) transfer_us: Vec<u64>,
|
|
pub(crate) scale_us: Vec<u64>,
|
|
pub(crate) format_us: Vec<u64>,
|
|
pub(crate) encode_us: Vec<u64>,
|
|
pub(crate) total_us: Vec<u64>,
|
|
pub(crate) import_failures: u32,
|
|
pub(crate) frames_encoded: u32,
|
|
pub(crate) elapsed_secs: f64,
|
|
pub(crate) codec_name: String,
|
|
pub(crate) output_path: String,
|
|
}
|
|
|
|
impl FrameStats {
|
|
pub(crate) fn avg_ms(data: &[u64]) -> f64 {
|
|
if data.is_empty() {
|
|
return 0.0;
|
|
}
|
|
data.iter().sum::<u64>() as f64 / data.len() as f64 / 1000.0
|
|
}
|
|
|
|
pub(crate) fn avg_total_ms(&self) -> f64 {
|
|
Self::avg_ms(&self.total_us)
|
|
}
|
|
|
|
pub(crate) fn achieved_fps(&self) -> f64 {
|
|
if self.frames_encoded > 0 && self.elapsed_secs > 0.0 {
|
|
self.frames_encoded as f64 / self.elapsed_secs
|
|
} else {
|
|
0.0
|
|
}
|
|
}
|
|
|
|
pub(crate) fn theoretical_fps(&self) -> f64 {
|
|
let avg = self.avg_total_ms();
|
|
if avg > 0.0 {
|
|
1000.0 / avg
|
|
} else {
|
|
0.0
|
|
}
|
|
}
|
|
}
|