-
Notifications
You must be signed in to change notification settings - Fork 49
benches: initial implementation #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
04e1f10
add readme
hinto-janai b538272
readme, basic examples
hinto-janai 39fe790
Merge branch 'main' into benches
hinto-janai 7bac741
name changes, bin impl
hinto-janai 24d176f
example, docs
hinto-janai 6525307
book
hinto-janai 897396e
Merge branch 'main' into benches
hinto-janai 185c2ee
add `cuprate-criterion-example`
hinto-janai 9a0b613
docs, tracing
hinto-janai 8c9d159
fix clippy
hinto-janai 828cbba
docs
hinto-janai fe6c395
Merge branch 'main' into benches
hinto-janai cab2011
lib readme
hinto-janai eb617b3
json-rpc benchmarks
hinto-janai 2e3e36c
add to crates.md
hinto-janai 1c462e3
add `fixme`
hinto-janai 1cada33
fix `cargo b` failing
hinto-janai 54354f7
Merge branch 'main' into benches
hinto-janai 250edba
Merge branch 'main' into benches
hinto-janai 12ad029
Merge branch 'main' into benches
hinto-janai e4a10bf
fix cargo.toml
hinto-janai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,5 @@ | ||
| # TODO | ||
| # Benches | ||
| This directory contains Cuprate's benchmarks and benchmarking utilities. | ||
|
|
||
| See the [`Benchmarking` section in the Architecture book](https://architecture.cuprate.org/benchmarking/intro.html) | ||
| to see how to create and run these benchmarks. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| [package] | ||
| name = "cuprate-benchmark" | ||
| version = "0.0.0" | ||
| edition = "2021" | ||
| description = "Cuprate's benchmarking binary" | ||
| license = "MIT" | ||
| authors = ["hinto-janai"] | ||
| repository = "https://github.com/Cuprate/cuprate/tree/main/benches/benchmark/bin" | ||
| keywords = ["cuprate", "benchmarking", "binary"] | ||
|
|
||
| [features] | ||
| # All new benchmarks should be added here! | ||
| all = ["example"] | ||
|
|
||
| # Non-benchmark features. | ||
| default = [] | ||
| json = [] | ||
| trace = [] | ||
| debug = [] | ||
| warn = [] | ||
| info = [] | ||
| error = [] | ||
|
|
||
| # Benchmark features. | ||
| # New benchmarks should be added here! | ||
| example = [ | ||
| "dep:cuprate-benchmark-example" | ||
| ] | ||
|
|
||
| [dependencies] | ||
| cuprate-benchmark-lib = { path = "../lib" } | ||
| cuprate-benchmark-example = { path = "../example", optional = true } | ||
|
|
||
| cfg-if = { workspace = true } | ||
| serde = { workspace = true, features = ["derive"] } | ||
| serde_json = { workspace = true, features = ["std"] } | ||
| tracing = { workspace = true, features = ["std", "attributes"] } | ||
| tracing-subscriber = { workspace = true, features = ["fmt", "std", "env-filter"] } | ||
|
|
||
| [dev-dependencies] | ||
|
|
||
| [lints] | ||
| workspace = true | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ## `cuprate-benchmark` | ||
| This crate links all benchmarks together into a single binary that can be run as: `cuprate-benchmark`. | ||
|
|
||
| `cuprate-benchmark` will run all enabled benchmarks sequentially and print data at the end. | ||
|
|
||
| ## Benchmarks | ||
| Benchmarks are opt-in and enabled via features. | ||
|
|
||
| | Feature | Enables which benchmark crate? | | ||
| |----------|--------------------------------| | ||
| | example | cuprate-benchmark-example | | ||
| | database | cuprate-benchmark-database | | ||
|
|
||
| ## Features | ||
| These are features that aren't for enabling benchmarks, but rather for other things. | ||
|
|
||
| Since `cuprate-benchmark` is built right before it is ran, | ||
| these features almost act like command line arguments. | ||
|
|
||
| | Features | Does what | | ||
| |----------|-----------| | ||
| | json | Prints JSON timings instead of a markdown table | ||
| | trace | Use the `trace` log-level | ||
| | debug | Use the `debug` log-level | ||
| | warn | Use the `warn` log-level | ||
| | info | Use the `info` log-level (default) | ||
| | error | Use the `error` log-level |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| use cfg_if::cfg_if; | ||
| use tracing::{info, instrument, Level}; | ||
| use tracing_subscriber::FmtSubscriber; | ||
|
|
||
| /// Initializes the `tracing` logger. | ||
| #[instrument] | ||
| pub(crate) fn init_logger() { | ||
| const LOG_LEVEL: Level = { | ||
| cfg_if! { | ||
| if #[cfg(feature = "trace")] { | ||
| Level::TRACE | ||
| } else if #[cfg(feature = "debug")] { | ||
| Level::DEBUG | ||
| } else if #[cfg(feature = "warn")] { | ||
| Level::WARN | ||
| } else if #[cfg(feature = "info")] { | ||
| Level::INFO | ||
| } else if #[cfg(feature = "error")] { | ||
| Level::ERROR | ||
| } else { | ||
| Level::INFO | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| FmtSubscriber::builder().with_max_level(LOG_LEVEL).init(); | ||
|
|
||
| info!("Log level: {LOG_LEVEL}"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| #![doc = include_str!("../README.md")] | ||
| #![allow( | ||
| unused_crate_dependencies, | ||
| reason = "this crate imports many potentially unused dependencies" | ||
| )] | ||
|
|
||
| mod log; | ||
| mod print; | ||
| mod run; | ||
| mod timings; | ||
|
|
||
| use cfg_if::cfg_if; | ||
|
|
||
| /// What `main()` does: | ||
| /// 1. Run all enabled benchmarks | ||
| /// 2. Record benchmark timings | ||
| /// 3. Print timing data | ||
| /// | ||
| /// To add a new benchmark to be ran here: | ||
| /// 1. Copy + paste a `cfg_if` block | ||
| /// 2. Change it to your benchmark's feature flag | ||
| /// 3. Change it to your benchmark's type | ||
| #[allow( | ||
| clippy::allow_attributes, | ||
| unused_variables, | ||
| unused_mut, | ||
| unreachable_code, | ||
| reason = "clippy does not account for all cfg()s" | ||
| )] | ||
| fn main() { | ||
| log::init_logger(); | ||
|
|
||
| let mut timings = timings::Timings::new(); | ||
|
|
||
| cfg_if! { | ||
| if #[cfg(not(any(feature = "example")))] { | ||
| println!("No feature specified. Use `--features $BENCHMARK_FEATURE` when building."); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| cfg_if! { | ||
| if #[cfg(feature = "example")] { | ||
| run::run_benchmark::<cuprate_benchmark_example::Example>(&mut timings); | ||
| } | ||
| } | ||
|
|
||
| print::print_timings(&timings); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| #![expect(dead_code, reason = "code hidden behind feature flags")] | ||
|
|
||
| use cfg_if::cfg_if; | ||
|
|
||
| use crate::timings::Timings; | ||
|
|
||
| /// Print the final the final markdown table of benchmark timings. | ||
| pub(crate) fn print_timings(timings: &Timings) { | ||
| println!("\nFinished all benchmarks, printing results:"); | ||
|
|
||
| cfg_if! { | ||
| if #[cfg(feature = "json")] { | ||
| print_timings_json(timings); | ||
| } else { | ||
| print_timings_markdown(timings); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Default timing formatting. | ||
| pub(crate) fn print_timings_markdown(timings: &Timings) { | ||
| let mut s = String::new(); | ||
| s.push_str("| Benchmark | Time (seconds) |\n"); | ||
| s.push_str("|------------------------------------|----------------|"); | ||
|
|
||
| #[expect(clippy::iter_over_hash_type)] | ||
| for (k, v) in timings { | ||
| s += &format!("\n| {k:<34} | {v:<14} |"); | ||
| } | ||
|
|
||
| println!("\n{s}"); | ||
| } | ||
|
|
||
| /// Enabled via `json` feature. | ||
| pub(crate) fn print_timings_json(timings: &Timings) { | ||
| let json = serde_json::to_string_pretty(timings).unwrap(); | ||
| println!("\n{json}"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| use tracing::{info, instrument, trace}; | ||
|
|
||
| use cuprate_benchmark_lib::Benchmark; | ||
|
|
||
| use crate::timings::Timings; | ||
|
|
||
| /// Run a [`Benchmark`] and record its timing. | ||
| #[instrument(skip_all)] | ||
| pub(crate) fn run_benchmark<B: Benchmark>(timings: &mut Timings) { | ||
| // Get the benchmark name. | ||
| let name = B::name(); | ||
| trace!("Running benchmark: {name}"); | ||
|
|
||
| // Setup the benchmark input. | ||
| let input = B::SETUP(); | ||
|
|
||
| // Sleep before running the benchmark. | ||
| trace!("Pre-benchmark, sleeping for: {:?}", B::POST_SLEEP_DURATION); | ||
| std::thread::sleep(B::PRE_SLEEP_DURATION); | ||
|
|
||
| // Run/time the benchmark. | ||
| let now = std::time::Instant::now(); | ||
| B::MAIN(input); | ||
| let time = now.elapsed().as_secs_f32(); | ||
|
|
||
| // Print the benchmark timings. | ||
| info!("{name:>34} ... {time}"); | ||
| assert!( | ||
| timings.insert(name, time).is_none(), | ||
| "There were 2 benchmarks with the same name - this collides the final output: {name}", | ||
| ); | ||
|
|
||
| // Sleep for a cooldown period after the benchmark run. | ||
| trace!("Post-benchmark, sleeping for: {:?}", B::POST_SLEEP_DURATION); | ||
| std::thread::sleep(B::POST_SLEEP_DURATION); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| /// Benchmark timing data. | ||
| /// | ||
| /// - Key = benchmark name | ||
| /// - Value = benchmark time in seconds | ||
| pub(crate) type Timings = std::collections::HashMap<&'static str, f32>; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [package] | ||
| name = "cuprate-benchmark-example" | ||
| version = "0.0.0" | ||
| edition = "2021" | ||
| description = "Example showcasing Cuprate's benchmarking harness" | ||
| license = "MIT" | ||
| authors = ["hinto-janai"] | ||
| repository = "https://github.com/Cuprate/cuprate/tree/main/benches/benchmark/example" | ||
| keywords = ["cuprate", "benchmarking", "example"] | ||
|
|
||
| [dependencies] | ||
| cuprate-benchmark-lib = { path = "../lib" } | ||
|
|
||
| [dev-dependencies] | ||
|
|
||
| [lints] | ||
| workspace = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ## `cuprate-benchmark-example` | ||
| This crate contains a short example benchmark that shows how to implement and use | ||
| `cuprate-benchmark-lib` so that it can be ran by `cuprate-benchmark`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #![doc = include_str!("../README.md")] | ||
|
|
||
| use std::hint::black_box; | ||
|
|
||
| use cuprate_benchmark_lib::Benchmark; | ||
|
|
||
| /// Marker struct that implements [`Benchmark`] | ||
| pub struct Example; | ||
|
|
||
| /// The input to our benchmark function. | ||
| pub type ExampleBenchmarkInput = u64; | ||
|
|
||
| /// The setup function that creates the input. | ||
| pub const fn example_benchmark_setup() -> ExampleBenchmarkInput { | ||
| 1 | ||
| } | ||
|
|
||
| /// The main benchmarking function. | ||
| #[expect(clippy::unit_arg)] | ||
| pub fn example_benchmark_main(input: ExampleBenchmarkInput) { | ||
| // In this case, we're simply benchmarking the | ||
| // performance of simple arithmetic on the input data. | ||
|
|
||
| fn math(input: ExampleBenchmarkInput, number: u64) { | ||
| let x = input; | ||
| let x = black_box(x * number); | ||
| let x = black_box(x / number); | ||
| let x = black_box(x + number); | ||
| let _ = black_box(x - number); | ||
| } | ||
|
|
||
| for number in 1..100_000_000 { | ||
| black_box(math(input, number)); | ||
| } | ||
| } | ||
|
|
||
| // This implementation will be run by `cuprate-benchmark`. | ||
| impl Benchmark for Example { | ||
| type Input = ExampleBenchmarkInput; | ||
| const SETUP: fn() -> Self::Input = example_benchmark_setup; | ||
| const MAIN: fn(Self::Input) = example_benchmark_main; | ||
| } | ||
|
Comment on lines
+38
to
+42
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very simple example |
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| [package] | ||
| name = "cuprate-benchmark-lib" | ||
| version = "0.0.0" | ||
| edition = "2021" | ||
| description = "Cuprate's benchmarking library" | ||
| license = "MIT" | ||
| authors = ["hinto-janai"] | ||
| repository = "https://github.com/Cuprate/cuprate/tree/main/benches/benchmark/lib" | ||
| keywords = ["cuprate", "benchmarking", "library"] | ||
|
|
||
| [features] | ||
|
|
||
| [dependencies] | ||
|
|
||
| [dev-dependencies] | ||
|
|
||
| [lints] | ||
| workspace = true |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these be added to the workspace so we can do
workspace = true