From 97befac520781e72b7af8b81c524235db201ecc6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Sep 2024 01:19:36 +0200 Subject: [PATCH] Adds benchmarks for effects and type conversions Benchmarks use the music.wav file, we use *divan* as benchmark harnass. The time needed to load the wav file is excluded from the benchmark by preparing the data into a special test Source. That source also enables converting between formats. In the future *divan* will add support for structured (json) output. Then we could integrate with the bencher service to generate benchmark reports for all PR's and keep a timeseries of performance. --- Cargo.toml | 10 +++++ benches/conversions.rs | 21 +++++++++++ benches/effects.rs | 48 ++++++++++++++++++++++++ benches/shared.rs | 83 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 benches/conversions.rs create mode 100644 benches/effects.rs create mode 100644 benches/shared.rs diff --git a/Cargo.toml b/Cargo.toml index 087fa561..1a0035bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,16 @@ quickcheck = "0.9.2" rstest = "0.18.2" rstest_reuse = "0.6.0" approx = "0.5.1" +dasp_sample = "0.11.0" +divan = "0.1.14" + +[[bench]] +name = "effects" +harness = false + +[[bench]] +name = "conversions" +harness = false [[example]] name = "music_m4a" diff --git a/benches/conversions.rs b/benches/conversions.rs new file mode 100644 index 00000000..b5c89d19 --- /dev/null +++ b/benches/conversions.rs @@ -0,0 +1,21 @@ +use cpal::FromSample; +use divan::Bencher; +use rodio::Source; + +mod shared; +use shared::TestSource; + +fn main() { + divan::main(); +} + +#[divan::bench(types = [i16, u16, f32])] +fn from_i16_to>(bencher: Bencher) { + bencher + .with_inputs(|| TestSource::music_wav()) + .bench_values(|source| { + source + .convert_samples::() + .for_each(divan::black_box_drop) + }) +} diff --git a/benches/effects.rs b/benches/effects.rs new file mode 100644 index 00000000..5f100112 --- /dev/null +++ b/benches/effects.rs @@ -0,0 +1,48 @@ +use std::time::Duration; + +use divan::Bencher; +use rodio::Source; + +mod shared; +use shared::TestSource; + +fn main() { + divan::main(); +} + +#[divan::bench] +fn reverb(bencher: Bencher) { + bencher + .with_inputs(|| TestSource::music_wav()) + .bench_values(|source| { + source + .buffered() + .reverb(Duration::from_secs_f32(0.05), 0.3) + .for_each(divan::black_box_drop) + }) +} + +#[divan::bench] +fn high_pass(bencher: Bencher) { + bencher + .with_inputs(|| TestSource::music_wav().to_f32s()) + .bench_values(|source| source.high_pass(200).for_each(divan::black_box_drop)) +} + +#[divan::bench] +fn fade_out(bencher: Bencher) { + bencher + .with_inputs(|| TestSource::music_wav()) + .bench_values(|source| { + source + .fade_out(Duration::from_secs(5)) + .for_each(divan::black_box_drop) + }) +} + +#[divan::bench] +fn amplify(bencher: Bencher) { + bencher + .with_inputs(|| TestSource::music_wav().to_f32s()) + .bench_values(|source| source.amplify(0.8).for_each(divan::black_box_drop)) +} diff --git a/benches/shared.rs b/benches/shared.rs new file mode 100644 index 00000000..0feff6a4 --- /dev/null +++ b/benches/shared.rs @@ -0,0 +1,83 @@ +use std::io::Cursor; +use std::time::Duration; +use std::vec; + +use rodio::Source; + +pub struct TestSource { + samples: vec::IntoIter, + channels: u16, + sample_rate: u32, + total_duration: Duration, +} + +impl Iterator for TestSource { + type Item = T; + + fn next(&mut self) -> Option { + self.samples.next() + } +} + +impl ExactSizeIterator for TestSource { + fn len(&self) -> usize { + self.samples.len() + } +} + +impl Source for TestSource { + fn current_frame_len(&self) -> Option { + None // forever + } + + fn channels(&self) -> u16 { + self.channels + } + + fn sample_rate(&self) -> u32 { + self.sample_rate + } + + fn total_duration(&self) -> Option { + Some(self.total_duration) + } +} + +impl TestSource { + pub fn music_wav() -> Self { + let data = include_bytes!("../assets/music.wav"); + let cursor = Cursor::new(data); + + let duration = Duration::from_secs(10); + let sound = rodio::Decoder::new(cursor) + .expect("music.wav is correctly encoded & wav is supported") + .take_duration(duration); + + TestSource { + channels: sound.channels(), + sample_rate: sound.sample_rate(), + total_duration: duration, + samples: sound.into_iter().collect::>().into_iter(), + } + } + + #[allow(unused, reason = "not everything from shared is used in all libs")] + pub fn to_f32s(self) -> TestSource { + let TestSource { + samples, + channels, + sample_rate, + total_duration, + } = self; + let samples = samples + .map(|s| cpal::Sample::from_sample(s)) + .collect::>() + .into_iter(); + TestSource { + samples, + channels, + sample_rate, + total_duration, + } + } +}