benches: Switch to iai_callgrind + Bencher

This commit is contained in:
Serial 2024-04-09 15:48:32 -04:00 committed by Alex
parent b110072f84
commit 2f2263378b
4 changed files with 184 additions and 204 deletions

View file

@ -1,45 +1,34 @@
name: Benchmark
name: Continuous Benchmarking with Bencher
on:
push:
paths:
- 'src/**'
- 'benches/**'
- 'ogg_pager/**'
branches:
- main
workflow_dispatch:
push:
paths:
- 'src/**'
- 'benches/**'
- 'ogg_pager/**'
branches:
- main
workflow_dispatch:
jobs:
benchmark:
name: Benchmark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly
- name: Run benchmark
benchmark_with_bencher:
name: Benchmark with Bencher
runs-on: ubuntu-latest
env:
RUSTFLAGS: '--cfg bench'
run: |
cargo bench --all-features -- --output-format bencher | tee output.txt
BENCHER_PROJECT: lofty
BENCHER_BRANCH: main
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@v1
with:
# What benchmark tool the output.txt came from
tool: 'cargo'
# Where the output from the benchmark tool is stored
output-file-path: output.txt
# Show alert with commit comment on detecting possible performance regression
alert-threshold: '200%'
# Workflow will fail when an alert happens
fail-on-alert: true
# GitHub API token to make a commit comment
github-token: ${{ secrets.GITHUB_TOKEN }}
# Enable alert commit comment
comment-on-alert: true
auto-push: true
- name: Install callgrind
run: sudo apt-get install -y valgrind
- name: Install iai-callgrind-runner
run: |
version=$(cargo metadata --format-version=1 |\
jq '.packages[] | select(.name == "iai-callgrind").version' |\
tr -d '"'
)
cargo install iai-callgrind-runner --version $version
- uses: bencherdev/bencher@main
- name: Run Bencher
run: |
bencher run --adapter rust_iai_callgrind --err "cargo bench"

View file

@ -36,14 +36,14 @@ hound = { git = "https://github.com/ruuda/hound.git", rev = "02e66effb33683d
# tag_writer example
structopt = { version = "0.3.26", default-features = false }
tempfile = "3.9.0"
# Pretty heavy dependency, we don't want this compiling for test/doc runs
[target.'cfg(bench)'.dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports"] }
iai-callgrind = "0.10.2"
[lib]
bench = false
[profile.bench]
debug = true
[[bench]]
name = "read_file"
path = "benches/read_file.rs"

View file

@ -7,126 +7,120 @@ use lofty::mp4::Ilst;
use lofty::ogg::VorbisComments;
use lofty::{Accessor, MimeType, Picture, PictureType, TagExt, WriteOptions};
use criterion::{criterion_group, criterion_main, Criterion};
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
const ENCODER: &str = "Lavf57.56.101";
macro_rules! bench_tag_write {
($c:ident, [$(($NAME:literal, $tag:ty, |$tag_:ident| $extra_block:block)),+ $(,)?]) => {
let mut g = $c.benchmark_group("Tag writing");
([$(($NAME:ident, $tag:ty, |$tag_:ident| $extra_block:block)),+ $(,)?]) => {
$(
g.bench_function(
$NAME,
|b| b.iter(|| {
let mut v = Vec::new();
let mut $tag_ = <$tag>::default();
#[library_benchmark]
fn $NAME() {
let mut v = Vec::new();
let mut $tag_ = <$tag>::default();
$tag_.set_artist(String::from("Dave Eddy"));
$tag_.set_title(String::from("TempleOS Hymn Risen (Remix)"));
$tag_.set_album(String::from("Summer"));
$tag_.set_year(2017);
$tag_.set_track(1);
$tag_.set_genre(String::from("Electronic"));
$extra_block
$tag_.dump_to(&mut v, WriteOptions::default()).unwrap();
})
);
$tag_.set_artist(String::from("Dave Eddy"));
$tag_.set_title(String::from("TempleOS Hymn Risen (Remix)"));
$tag_.set_album(String::from("Summer"));
$tag_.set_year(2017);
$tag_.set_track(1);
$tag_.set_genre(String::from("Electronic"));
$extra_block;
$tag_.dump_to(&mut v, WriteOptions::default()).unwrap();
}
)+
}
}
fn bench_write(c: &mut Criterion) {
bench_tag_write!(
c,
[
("AIFF Text Chunks", AIFFTextChunks, |tag| {}),
("APEv2", ApeTag, |tag| {
use lofty::ape::ApeItem;
use lofty::ItemValue;
bench_tag_write!([
(aiff_text_chunks, AIFFTextChunks, |tag| {}),
(apev2, ApeTag, |tag| {
use lofty::ape::ApeItem;
use lofty::ItemValue;
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
tag.insert(
ApeItem::new(
String::from("Cover (Front)"),
ItemValue::Binary(picture.as_ape_bytes()),
)
.unwrap(),
);
tag.insert(
ApeItem::new(
String::from("Encoder"),
ItemValue::Text(String::from(ENCODER)),
)
.unwrap(),
);
}),
("ID3v2", Id3v2Tag, |tag| {
use lofty::id3::v2::{Frame, FrameFlags, TextInformationFrame};
use lofty::TextEncoding;
tag.insert(
ApeItem::new(
String::from("Cover (Front)"),
ItemValue::Binary(picture.as_ape_bytes()),
)
.unwrap(),
);
tag.insert(
ApeItem::new(
String::from("Encoder"),
ItemValue::Text(String::from(ENCODER)),
)
.unwrap(),
);
}),
(id3v2, Id3v2Tag, |tag| {
use lofty::id3::v2::{Frame, FrameFlags, TextInformationFrame};
use lofty::TextEncoding;
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
tag.insert_picture(picture);
tag.insert(
Frame::new(
"TSSE",
TextInformationFrame {
encoding: TextEncoding::Latin1,
value: String::from(ENCODER),
},
FrameFlags::default(),
)
.unwrap(),
);
}),
("ID3v1", Id3v1Tag, |tag| {}),
("MP4 Ilst", Ilst, |tag| {
use lofty::mp4::{Atom, AtomData, AtomIdent};
tag.insert_picture(picture);
tag.insert(
Frame::new(
"TSSE",
TextInformationFrame {
encoding: TextEncoding::Latin1,
value: String::from(ENCODER),
},
FrameFlags::default(),
)
.unwrap(),
);
}),
(id3v1, Id3v1Tag, |tag| {}),
(ilst, Ilst, |tag| {
use lofty::mp4::{Atom, AtomData, AtomIdent};
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
tag.insert_picture(picture);
tag.insert(Atom::new(
AtomIdent::Fourcc(*b"\xa9too"),
AtomData::UTF8(String::from(ENCODER)),
));
}),
("RIFF INFO", RIFFInfoList, |tag| {
tag.insert(String::from("ISFT"), String::from(ENCODER));
}),
("Vorbis Comments", VorbisComments, |tag| {
use lofty::ogg::OggPictureStorage;
tag.insert_picture(picture);
tag.insert(Atom::new(
AtomIdent::Fourcc(*b"\xa9too"),
AtomData::UTF8(String::from(ENCODER)),
));
}),
(riff_info, RIFFInfoList, |tag| {
tag.insert(String::from("ISFT"), String::from(ENCODER));
}),
(vorbis_comments, VorbisComments, |tag| {
use lofty::ogg::OggPictureStorage;
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
let picture = Picture::new_unchecked(
PictureType::CoverFront,
Some(MimeType::Jpeg),
None,
include_bytes!("../benches_assets/cover.jpg").to_vec(),
);
let _ = tag.insert_picture(picture, None).unwrap();
tag.push(String::from("ENCODER"), String::from(ENCODER));
}),
]
);
}
let _ = tag.insert_picture(picture, None).unwrap();
tag.push(String::from("ENCODER"), String::from(ENCODER));
}),
]);
criterion_group!(benches, bench_write);
criterion_main!(benches);
library_benchmark_group!(
name = tag_writing;
benchmarks = aiff_text_chunks, apev2, id3v2, id3v1, ilst, riff_info, vorbis_comments
);
main!(library_benchmark_groups = tag_writing);

View file

@ -1,68 +1,65 @@
use lofty::{ParseOptions, Probe};
use criterion::{criterion_group, criterion_main, Criterion};
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use std::hint::black_box;
use std::io::Cursor;
macro_rules! test_read_file {
($c:ident, [$(($NAME:ident, $path:expr)),+ $(,)?]) => {
let mut g = $c.benchmark_group("File reading (Inferred from Content)");
([$(($NAME:ident, $path:expr)),+ $(,)?]) => {
$(
const $NAME: &[u8] = include_bytes!($path);
paste::paste! {
#[library_benchmark]
fn [<$NAME:lower>]() {
const $NAME: &[u8] = include_bytes!($path);
g.bench_function(
stringify!($NAME),
|b| b.iter(|| {
Probe::new(Cursor::new($NAME))
.options(ParseOptions::new())
.guess_file_type()
.unwrap()
.read()
.unwrap()
})
);
black_box(Probe::new(Cursor::new($NAME))
.options(ParseOptions::new())
.guess_file_type()
.unwrap()
.read()
.unwrap());
}
}
)+
}
}
fn content_infer_read(c: &mut Criterion) {
test_read_file!(
c,
[
(AAC, "../benches_assets/01 TempleOS Hymn Risen (Remix).aac"),
(
AIFF,
"../benches_assets/01 TempleOS Hymn Risen (Remix).aiff"
),
(APE, "../benches_assets/01 TempleOS Hymn Risen (Remix).ape"),
(
FLAC,
"../benches_assets/01 TempleOS Hymn Risen (Remix).flac"
),
(MP4, "../benches_assets/01 TempleOS Hymn Risen (Remix).m4a"),
(MP3, "../benches_assets/01 TempleOS Hymn Risen (Remix).mp3"),
(MPC, "../benches_assets/01 TempleOS Hymn Risen (Remix).mpc"),
(
OPUS,
"../benches_assets/01 TempleOS Hymn Risen (Remix).opus"
),
(RIFF, "../benches_assets/01 TempleOS Hymn Risen (Remix).wav"),
(
SPEEX,
"../benches_assets/01 TempleOS Hymn Risen (Remix).spx"
),
(
VORBIS,
"../benches_assets/01 TempleOS Hymn Risen (Remix).ogg"
),
(
WAVPACK,
"../benches_assets/01 TempleOS Hymn Risen (Remix).wv"
),
]
);
}
test_read_file!([
(AAC, "../benches_assets/01 TempleOS Hymn Risen (Remix).aac"),
(
AIFF,
"../benches_assets/01 TempleOS Hymn Risen (Remix).aiff"
),
(APE, "../benches_assets/01 TempleOS Hymn Risen (Remix).ape"),
(
FLAC,
"../benches_assets/01 TempleOS Hymn Risen (Remix).flac"
),
(MP4, "../benches_assets/01 TempleOS Hymn Risen (Remix).m4a"),
(MP3, "../benches_assets/01 TempleOS Hymn Risen (Remix).mp3"),
(MPC, "../benches_assets/01 TempleOS Hymn Risen (Remix).mpc"),
(
OPUS,
"../benches_assets/01 TempleOS Hymn Risen (Remix).opus"
),
(RIFF, "../benches_assets/01 TempleOS Hymn Risen (Remix).wav"),
(
SPEEX,
"../benches_assets/01 TempleOS Hymn Risen (Remix).spx"
),
(
VORBIS,
"../benches_assets/01 TempleOS Hymn Risen (Remix).ogg"
),
(
WAVPACK,
"../benches_assets/01 TempleOS Hymn Risen (Remix).wv"
),
]);
criterion_group!(benches, content_infer_read);
criterion_main!(benches);
library_benchmark_group!(
name = file_reading;
benchmarks = aac, aiff, ape, flac, mp4, mp3, mpc, opus, riff, speex, vorbis, wavpack
);
main!(library_benchmark_groups = file_reading);