Skip to content

Commit

Permalink
Add a benchmark to be run on main branch CI
Browse files Browse the repository at this point in the history
Also, add the test video asset using git lfs, so that it is relatively easily
accessible, but doesn't pollute the repository itself.
  • Loading branch information
dholroyd committed Feb 29, 2024
1 parent 37f76d9 commit e8288a7
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
big_buck_bunny_1080p_24fps_h264.h264 filter=lfs diff=lfs merge=lfs -text
33 changes: 33 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Benchmark
on:
push:
branches: master
jobs:
benchmark_with_bencher:
name: Benchmark with Bencher
runs-on: ubuntu-22.04
env:
BENCHER_PROJECT: h264-reader
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
lfs: true

- name: Install toolchain
uses: dtolnay/[email protected]

- uses: bencherdev/bencher@main
- uses: cargo-bins/cargo-binstall@main

- run: sudo apt-get install valgrind
- run: cargo binstall --no-confirm [email protected]
- run: |
IAI_CALLGRIND_COLOR=never cargo bench --bench ci_bench > perf.txt
- run: |
bencher run \
--branch "$GITHUB_REF_NAME" \
--err \
--adapter rust_iai_callgrind \
--hash "$GITHUB_SHA" \
--file "perf.txt"
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@ log = "0.4"
hex-literal = "0.4.1"
criterion = "0.5"
test-case = "3.0.0"
iai-callgrind = "0.10.2"

[[bench]]
name = "bench"
harness = false

[[bench]]
name = "ci_bench"
harness = false


[profile.bench]
# for profiling,
debug = true
19 changes: 19 additions & 0 deletions benches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Benchmarks

There are two benchmarks here,

- `bench.rs`
- [criterion.rs](https://github.com/bheisler/criterion.rs) based benchmark suite that measures throughput of various
h264 parsing setups, reporting on parser throughput (i.e. number of megabytes of h264 data parsed per second).
- Provides a view of how fast the parser is on the system on which the benchmark is executed.
- Run using `cargo criterion --bench bench`
- `bench-ci.rs`
- [iai-callgrind](https://github.com/iai-callgrind/iai-callgrind) based benchmark that counts the number of
instructions executed while parsing a test asset
- Provides an indication of performance that is stable even if run on CPUs of varying speeds, or in the face of
CPU contention from other processes (e.g. in a noisy CI environment like github actions).
- Useful for comparing changes in performance over time, not useful for indicating _absolute_ performance.
- run using `cargo bench --bench ci_bench`

The latter benchmark is run from a github actions workflow on commits to the main branch and the benchmark results are
uploaded to [bencher.dev](https://bencher.dev/perf/h264-reader).
4 changes: 3 additions & 1 deletion benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ where
}

fn h264_reader(c: &mut Criterion) {
let buf = std::fs::read("big_buck_bunny_1080p.h264").expect("reading h264 file failed");
let buf =
std::fs::read("big_buck_bunny_1080p_24fps_h264.h264").expect("reading h264 file failed");
let mut rbsp_len = 0;
let mut rbsp_len_nal_handler = |nal: RefNal<'_>| {
if nal.is_complete() {
Expand Down Expand Up @@ -111,6 +112,7 @@ fn h264_reader(c: &mut Criterion) {
Ok(_) => return NalInterest::Ignore,
}
}
UnitType::AccessUnitDelimiter => {}
_ => {
if nal.is_complete() {
panic!("unknown slice type {:?}", nal_hdr)
Expand Down
103 changes: 103 additions & 0 deletions benches/ci_bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use h264_reader::annexb::AnnexBReader;
use h264_reader::nal::pps::PicParameterSet;
use h264_reader::nal::sei::buffering_period::BufferingPeriod;
use h264_reader::nal::sei::pic_timing::PicTiming;
use h264_reader::nal::sei::user_data_registered_itu_t_t35::ItuTT35;
use h264_reader::nal::sei::HeaderType;
use h264_reader::nal::slice::SliceHeader;
use h264_reader::nal::sps::SeqParameterSet;
use h264_reader::nal::Nal;
use h264_reader::nal::{sei, RefNal, UnitType};
use h264_reader::push::NalInterest;
use h264_reader::Context;
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use std::fs::File;
use std::hint::black_box;
use std::io::Read;

fn setup_video(filename: &str) -> Vec<u8> {
let mut f = File::open(filename).expect("Test file missing.");
let l = f.metadata().unwrap().len() as usize;
let size = l.min(10 * 1024 * 1024);
let mut buf = vec![0; size];
f.read_exact(&mut buf[..]).unwrap();
buf
}

#[library_benchmark]
#[bench::read(setup_video("big_buck_bunny_1080p_24fps_h264.h264"))]
fn reader(buf: Vec<u8>) {
let mut ctx = Context::new();

let mut reader = AnnexBReader::accumulate(|nal: RefNal<'_>| {
if !nal.is_complete() {
return NalInterest::Buffer;
}

let nal_header = nal.header().unwrap();
let nal_unit_type = nal_header.nal_unit_type();

match nal_unit_type {
UnitType::SeqParameterSet => {
let data = SeqParameterSet::from_bits(nal.rbsp_bits()).unwrap();
ctx.put_seq_param_set(data);
}
UnitType::PicParameterSet => {
let data = PicParameterSet::from_bits(&ctx, nal.rbsp_bits()).unwrap();
ctx.put_pic_param_set(data);
}
UnitType::SliceLayerWithoutPartitioningIdr
| UnitType::SliceLayerWithoutPartitioningNonIdr => {
let mut bits = nal.rbsp_bits();
let (header, _seq_params, _pic_params) =
SliceHeader::from_bits(&ctx, &mut bits, nal_header).unwrap();
let _ = black_box(header);
}
UnitType::SEI => {
let mut scratch = vec![];
let mut reader = sei::SeiReader::from_rbsp_bytes(nal.rbsp_bytes(), &mut scratch);
loop {
match reader.next() {
Ok(Some(sei)) => match sei.payload_type {
HeaderType::BufferingPeriod => {
let bp = BufferingPeriod::read(&ctx, &sei);
let _ = black_box(bp);
}
HeaderType::PicTiming => {
let pt =
PicTiming::read(ctx.sps().next().expect("first sps"), &sei);
let _ = black_box(pt);
}
HeaderType::UserDataRegisteredItuTT35 => match ItuTT35::read(&sei) {
Ok(ud) => {
let _ = black_box(ud);
}
Err(e) => {
println!("{:?}", e);
}
},
_ => {}
},
Ok(None) => break,
Err(e) => {
println!("{:?}", e);
}
}
}
}
_ => {
println!("Unhandled: {:?}", nal_unit_type);
}
}
NalInterest::Ignore
});

reader.push(&buf);
}

library_benchmark_group!(
name = ci;
benchmarks = reader
);

main!(library_benchmark_groups = ci);
3 changes: 3 additions & 0 deletions big_buck_bunny_1080p_24fps_h264.h264
Git LFS file not shown

0 comments on commit e8288a7

Please sign in to comment.