From 34da1364d00583c230af80b9b7f6e8fde0c330f6 Mon Sep 17 00:00:00 2001 From: Jonathan Dickinson Date: Sat, 16 Nov 2024 19:29:55 -0800 Subject: [PATCH] bench: switch to criterion Switches the benchmark framework to Criterion. The default Rust std test framework has a hardcoded goal execution time of 1ms for each benchmark. This makes it unsuitable for sample-based profiling because the benchmark doesn't run for very long. Adds a utility script to run tests under a profiler. --- benches/.gitignore | 4 ++ benches/Cargo.toml | 7 +++ benches/measure.sh | 14 ++++++ benches/src/lib.rs | 105 +++++++++++++++++++++++---------------------- 4 files changed, 79 insertions(+), 51 deletions(-) create mode 100644 benches/.gitignore create mode 100755 benches/measure.sh diff --git a/benches/.gitignore b/benches/.gitignore new file mode 100644 index 00000000..571b775f --- /dev/null +++ b/benches/.gitignore @@ -0,0 +1,4 @@ +target +perf.data +perf.data.old +Cargo.lock diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 7263060b..45018f56 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -7,6 +7,13 @@ edition = "2018" harfbuzz_rs = { git = "https://github.com/harfbuzz/harfbuzz_rs/", rev = "43f0fb5" } rustybuzz = { path = "../" } +[dev-dependencies] +criterion = "0.3" +criterion-macro = "0.3" + [features] default = ["hb"] hb = [] + +[profile.bench] +debug = 2 diff --git a/benches/measure.sh b/benches/measure.sh new file mode 100755 index 00000000..4e3363e2 --- /dev/null +++ b/benches/measure.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +export HARFBUZZ_SYS_NO_PKG_CONFIG="" + +# Using jq here would be best, however it's not installed by default on many systems, and this isn't a critical script. +TEST_EXECUTABLE=$( + cargo +nightly bench \ + --message-format=json \ + --no-default-features --no-run | \ + sed -n 's/^{"reason":"compiler-artifact".*"executable":"\([^"]*\)".*}$/\1/p' +) + +exec perf record --call-graph dwarf -- "$TEST_EXECUTABLE" --bench --profile-time 5 "$@" diff --git a/benches/src/lib.rs b/benches/src/lib.rs index 1b8c128a..1229de8a 100644 --- a/benches/src/lib.rs +++ b/benches/src/lib.rs @@ -1,9 +1,13 @@ #![feature(test)] #![allow(dead_code)] #![allow(unused_imports)] +#![feature(custom_test_frameworks)] +#![test_runner(criterion::runner)] extern crate test; +use criterion::{black_box, Criterion}; +use criterion_macro::criterion; use rustybuzz::ttf_parser::Tag; struct CustomVariation { @@ -29,34 +33,34 @@ macro_rules! simple_bench { use super::*; use test::Bencher; - #[bench] - fn rb(bencher: &mut Bencher) { + #[criterion] + fn rb(c: &mut Criterion) { let font_data = std::fs::read($font_path).unwrap(); let text = std::fs::read_to_string($text_path).unwrap().trim().to_string(); - bencher.iter(|| { - test::black_box({ - let face = rustybuzz::Face::from_slice(&font_data, 0).unwrap(); - let mut buffer = rustybuzz::UnicodeBuffer::new(); - buffer.push_str(&text); - buffer.reset_clusters(); - rustybuzz::shape(&face, &[], buffer); - }); - }) - } - #[cfg(feature = "hb")] - #[bench] - fn hb(bencher: &mut Bencher) { - let font_data = std::fs::read($font_path).unwrap(); - let text = std::fs::read_to_string($text_path).unwrap().trim().to_string(); - bencher.iter(|| { - test::black_box({ - let face = harfbuzz_rs::Face::from_bytes(&font_data, 0); - let font = harfbuzz_rs::Font::new(face); + c.bench_function(&format!("{}::{}", module_path!(), "rb"), |bencher| { + let face = rustybuzz::Face::from_slice(&font_data, 0).unwrap(); + + bencher.iter(|| { + black_box({ + let mut buffer = rustybuzz::UnicodeBuffer::new(); + buffer.push_str(&text); + buffer.reset_clusters(); + rustybuzz::shape(&face, &[], buffer); + }); + }) + }); + + #[cfg(feature = "hb")] + c.bench_function(&format!("{}::{}", module_path!(), "hb"), |bencher| { + let face = harfbuzz_rs::Face::from_bytes(&font_data, 0); + let font = harfbuzz_rs::Font::new(face); + + bencher.iter(|| { let buffer = harfbuzz_rs::UnicodeBuffer::new().add_str(&text); - harfbuzz_rs::shape(&font, buffer, &[]) - }); - }) + black_box({ harfbuzz_rs::shape(&font, buffer, &[]) }); + }) + }); } } }; @@ -67,36 +71,35 @@ macro_rules! simple_bench { use super::*; use test::Bencher; - #[bench] - fn rb(bencher: &mut Bencher) { - let font_data = std::fs::read($font_path).unwrap(); - let text = std::fs::read_to_string($text_path).unwrap().trim().to_string(); - bencher.iter(|| { - test::black_box({ - let mut face = rustybuzz::Face::from_slice(&font_data, 0).unwrap(); - face.set_variations($variations); - let mut buffer = rustybuzz::UnicodeBuffer::new(); - buffer.push_str(&text); - buffer.reset_clusters(); - rustybuzz::shape(&face, &[], buffer); - }); - }) - } - - #[cfg(feature = "hb")] - #[bench] - fn hb(bencher: &mut Bencher) { + #[criterion] + fn rb(c: &mut Criterion) { let font_data = std::fs::read($font_path).unwrap(); let text = std::fs::read_to_string($text_path).unwrap().trim().to_string(); - bencher.iter(|| { - test::black_box({ - let face = harfbuzz_rs::Face::from_bytes(&font_data, 0); - let mut font = harfbuzz_rs::Font::new(face); - font.set_variations($variations); + c.bench_function(&format!("{}::{}", module_path!(), "rb"), |bencher| { + let mut face = rustybuzz::Face::from_slice(&font_data, 0).unwrap(); + face.set_variations($variations); + + bencher.iter(|| { + black_box({ + let mut buffer = rustybuzz::UnicodeBuffer::new(); + buffer.push_str(&text); + buffer.reset_clusters(); + rustybuzz::shape(&face, &[], buffer); + }); + }) + }); + + #[cfg(feature = "hb")] + c.bench_function(&format!("{}::{}", module_path!(), "hb"), |bencher| { + let face = harfbuzz_rs::Face::from_bytes(&font_data, 0); + let mut font = harfbuzz_rs::Font::new(face); + font.set_variations($variations); + + bencher.iter(|| { let buffer = harfbuzz_rs::UnicodeBuffer::new().add_str(&text); - harfbuzz_rs::shape(&font, buffer, &[]) - }); - }) + black_box({ harfbuzz_rs::shape(&font, buffer, &[]) }); + }) + }); } } };