Skip to content

Commit e8288a7

Browse files
committed
Add a benchmark to be run on main branch CI
Also, add the test video asset using git lfs, so that it is relatively easily accessible, but doesn't pollute the repository itself.
1 parent 37f76d9 commit e8288a7

File tree

7 files changed

+168
-1
lines changed

7 files changed

+168
-1
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
big_buck_bunny_1080p_24fps_h264.h264 filter=lfs diff=lfs merge=lfs -text

.github/workflows/benchmark.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Benchmark
2+
on:
3+
push:
4+
branches: master
5+
jobs:
6+
benchmark_with_bencher:
7+
name: Benchmark with Bencher
8+
runs-on: ubuntu-22.04
9+
env:
10+
BENCHER_PROJECT: h264-reader
11+
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
12+
steps:
13+
- uses: actions/checkout@v4
14+
with:
15+
lfs: true
16+
17+
- name: Install toolchain
18+
uses: dtolnay/[email protected]
19+
20+
- uses: bencherdev/bencher@main
21+
- uses: cargo-bins/cargo-binstall@main
22+
23+
- run: sudo apt-get install valgrind
24+
- run: cargo binstall --no-confirm [email protected]
25+
- run: |
26+
IAI_CALLGRIND_COLOR=never cargo bench --bench ci_bench > perf.txt
27+
- run: |
28+
bencher run \
29+
--branch "$GITHUB_REF_NAME" \
30+
--err \
31+
--adapter rust_iai_callgrind \
32+
--hash "$GITHUB_SHA" \
33+
--file "perf.txt"

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@ log = "0.4"
2121
hex-literal = "0.4.1"
2222
criterion = "0.5"
2323
test-case = "3.0.0"
24+
iai-callgrind = "0.10.2"
2425

2526
[[bench]]
2627
name = "bench"
2728
harness = false
2829

30+
[[bench]]
31+
name = "ci_bench"
32+
harness = false
33+
34+
2935
[profile.bench]
3036
# for profiling,
3137
debug = true

benches/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Benchmarks
2+
3+
There are two benchmarks here,
4+
5+
- `bench.rs`
6+
- [criterion.rs](https://github.com/bheisler/criterion.rs) based benchmark suite that measures throughput of various
7+
h264 parsing setups, reporting on parser throughput (i.e. number of megabytes of h264 data parsed per second).
8+
- Provides a view of how fast the parser is on the system on which the benchmark is executed.
9+
- Run using `cargo criterion --bench bench`
10+
- `bench-ci.rs`
11+
- [iai-callgrind](https://github.com/iai-callgrind/iai-callgrind) based benchmark that counts the number of
12+
instructions executed while parsing a test asset
13+
- Provides an indication of performance that is stable even if run on CPUs of varying speeds, or in the face of
14+
CPU contention from other processes (e.g. in a noisy CI environment like github actions).
15+
- Useful for comparing changes in performance over time, not useful for indicating _absolute_ performance.
16+
- run using `cargo bench --bench ci_bench`
17+
18+
The latter benchmark is run from a github actions workflow on commits to the main branch and the benchmark results are
19+
uploaded to [bencher.dev](https://bencher.dev/perf/h264-reader).

benches/bench.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ where
5252
}
5353

5454
fn h264_reader(c: &mut Criterion) {
55-
let buf = std::fs::read("big_buck_bunny_1080p.h264").expect("reading h264 file failed");
55+
let buf =
56+
std::fs::read("big_buck_bunny_1080p_24fps_h264.h264").expect("reading h264 file failed");
5657
let mut rbsp_len = 0;
5758
let mut rbsp_len_nal_handler = |nal: RefNal<'_>| {
5859
if nal.is_complete() {
@@ -111,6 +112,7 @@ fn h264_reader(c: &mut Criterion) {
111112
Ok(_) => return NalInterest::Ignore,
112113
}
113114
}
115+
UnitType::AccessUnitDelimiter => {}
114116
_ => {
115117
if nal.is_complete() {
116118
panic!("unknown slice type {:?}", nal_hdr)

benches/ci_bench.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use h264_reader::annexb::AnnexBReader;
2+
use h264_reader::nal::pps::PicParameterSet;
3+
use h264_reader::nal::sei::buffering_period::BufferingPeriod;
4+
use h264_reader::nal::sei::pic_timing::PicTiming;
5+
use h264_reader::nal::sei::user_data_registered_itu_t_t35::ItuTT35;
6+
use h264_reader::nal::sei::HeaderType;
7+
use h264_reader::nal::slice::SliceHeader;
8+
use h264_reader::nal::sps::SeqParameterSet;
9+
use h264_reader::nal::Nal;
10+
use h264_reader::nal::{sei, RefNal, UnitType};
11+
use h264_reader::push::NalInterest;
12+
use h264_reader::Context;
13+
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
14+
use std::fs::File;
15+
use std::hint::black_box;
16+
use std::io::Read;
17+
18+
fn setup_video(filename: &str) -> Vec<u8> {
19+
let mut f = File::open(filename).expect("Test file missing.");
20+
let l = f.metadata().unwrap().len() as usize;
21+
let size = l.min(10 * 1024 * 1024);
22+
let mut buf = vec![0; size];
23+
f.read_exact(&mut buf[..]).unwrap();
24+
buf
25+
}
26+
27+
#[library_benchmark]
28+
#[bench::read(setup_video("big_buck_bunny_1080p_24fps_h264.h264"))]
29+
fn reader(buf: Vec<u8>) {
30+
let mut ctx = Context::new();
31+
32+
let mut reader = AnnexBReader::accumulate(|nal: RefNal<'_>| {
33+
if !nal.is_complete() {
34+
return NalInterest::Buffer;
35+
}
36+
37+
let nal_header = nal.header().unwrap();
38+
let nal_unit_type = nal_header.nal_unit_type();
39+
40+
match nal_unit_type {
41+
UnitType::SeqParameterSet => {
42+
let data = SeqParameterSet::from_bits(nal.rbsp_bits()).unwrap();
43+
ctx.put_seq_param_set(data);
44+
}
45+
UnitType::PicParameterSet => {
46+
let data = PicParameterSet::from_bits(&ctx, nal.rbsp_bits()).unwrap();
47+
ctx.put_pic_param_set(data);
48+
}
49+
UnitType::SliceLayerWithoutPartitioningIdr
50+
| UnitType::SliceLayerWithoutPartitioningNonIdr => {
51+
let mut bits = nal.rbsp_bits();
52+
let (header, _seq_params, _pic_params) =
53+
SliceHeader::from_bits(&ctx, &mut bits, nal_header).unwrap();
54+
let _ = black_box(header);
55+
}
56+
UnitType::SEI => {
57+
let mut scratch = vec![];
58+
let mut reader = sei::SeiReader::from_rbsp_bytes(nal.rbsp_bytes(), &mut scratch);
59+
loop {
60+
match reader.next() {
61+
Ok(Some(sei)) => match sei.payload_type {
62+
HeaderType::BufferingPeriod => {
63+
let bp = BufferingPeriod::read(&ctx, &sei);
64+
let _ = black_box(bp);
65+
}
66+
HeaderType::PicTiming => {
67+
let pt =
68+
PicTiming::read(ctx.sps().next().expect("first sps"), &sei);
69+
let _ = black_box(pt);
70+
}
71+
HeaderType::UserDataRegisteredItuTT35 => match ItuTT35::read(&sei) {
72+
Ok(ud) => {
73+
let _ = black_box(ud);
74+
}
75+
Err(e) => {
76+
println!("{:?}", e);
77+
}
78+
},
79+
_ => {}
80+
},
81+
Ok(None) => break,
82+
Err(e) => {
83+
println!("{:?}", e);
84+
}
85+
}
86+
}
87+
}
88+
_ => {
89+
println!("Unhandled: {:?}", nal_unit_type);
90+
}
91+
}
92+
NalInterest::Ignore
93+
});
94+
95+
reader.push(&buf);
96+
}
97+
98+
library_benchmark_group!(
99+
name = ci;
100+
benchmarks = reader
101+
);
102+
103+
main!(library_benchmark_groups = ci);

big_buck_bunny_1080p_24fps_h264.h264

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:e65e19b9c187e94ea0e0c4e2fd371a0a739ed5cd79cc69e88c24322644063409
3+
size 36935320

0 commit comments

Comments
 (0)