Skip to content

Commit

Permalink
Adds benchmarks for effects and type conversions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
github-actions[bot] committed Sep 28, 2024
1 parent a4e12d0 commit 97befac
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
21 changes: 21 additions & 0 deletions benches/conversions.rs
Original file line number Diff line number Diff line change
@@ -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<T: rodio::Sample + FromSample<i16>>(bencher: Bencher) {
bencher
.with_inputs(|| TestSource::music_wav())
.bench_values(|source| {
source
.convert_samples::<T>()
.for_each(divan::black_box_drop)
})
}
48 changes: 48 additions & 0 deletions benches/effects.rs
Original file line number Diff line number Diff line change
@@ -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))
}
83 changes: 83 additions & 0 deletions benches/shared.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use std::io::Cursor;
use std::time::Duration;
use std::vec;

use rodio::Source;

pub struct TestSource<T> {
samples: vec::IntoIter<T>,
channels: u16,
sample_rate: u32,
total_duration: Duration,
}

impl<T> Iterator for TestSource<T> {
type Item = T;

fn next(&mut self) -> Option<Self::Item> {
self.samples.next()
}
}

impl<T> ExactSizeIterator for TestSource<T> {
fn len(&self) -> usize {
self.samples.len()
}
}

impl<T: rodio::Sample> Source for TestSource<T> {
fn current_frame_len(&self) -> Option<usize> {
None // forever
}

fn channels(&self) -> u16 {
self.channels
}

fn sample_rate(&self) -> u32 {
self.sample_rate
}

fn total_duration(&self) -> Option<Duration> {
Some(self.total_duration)
}
}

impl TestSource<i16> {
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::<Vec<_>>().into_iter(),
}
}

#[allow(unused, reason = "not everything from shared is used in all libs")]
pub fn to_f32s(self) -> TestSource<f32> {
let TestSource {
samples,
channels,
sample_rate,
total_duration,
} = self;
let samples = samples
.map(|s| cpal::Sample::from_sample(s))
.collect::<Vec<_>>()
.into_iter();
TestSource {
samples,
channels,
sample_rate,
total_duration,
}
}
}

0 comments on commit 97befac

Please sign in to comment.