-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* start benchmark proc-macro * it works with a simple output * rename `threads` to `cores` * Update docs * fix clippy * fix clippy issues * fixing clippy * fmt and small fixes --------- Co-authored-by: drewstone <[email protected]>
- Loading branch information
Showing
12 changed files
with
247 additions
and
9 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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 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 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 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 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 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 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,78 @@ | ||
use proc_macro::TokenStream; | ||
use quote::{format_ident, quote}; | ||
use syn::parse::{Parse, ParseStream}; | ||
use syn::{ItemFn, Token}; | ||
|
||
// Defines custom keywords | ||
mod kw { | ||
syn::custom_keyword!(cores); | ||
syn::custom_keyword!(job_id); | ||
} | ||
|
||
/// `BenchmarkArgs` is a struct that holds the arguments for the `benchmark` macro. | ||
pub(crate) struct BenchmarkArgs { | ||
/// The max number of cores this benchmark should run with. | ||
/// | ||
/// `#[benchmark(cores = 4)]` | ||
cores: syn::LitInt, | ||
/// The job identifier for the benchmark. | ||
/// | ||
/// `#[benchmark(job_id = 1)]` | ||
job_id: syn::LitInt, | ||
} | ||
|
||
pub(crate) fn benchmark_impl(args: &BenchmarkArgs, input: &ItemFn) -> syn::Result<TokenStream> { | ||
let cores = &args.cores; | ||
let job_id = &args.job_id; | ||
let original_name = &input.sig.ident; | ||
let name = format_ident!("{}_benchmark", original_name); | ||
let block = &input.block; | ||
let expanded = quote! { | ||
#[doc(hidden)] | ||
pub fn #name() { | ||
let cores: usize = #cores; | ||
let rt = gadget_sdk::benchmark::tokio::runtime::Builder::new_multi_thread() | ||
.worker_threads(cores) | ||
.max_blocking_threads(cores) | ||
.enable_all() | ||
.build() | ||
.unwrap(); | ||
let _guard = rt.enter(); | ||
let b = gadget_sdk::benchmark::Bencher::new(cores, gadget_sdk::benchmark::TokioRuntime); | ||
b.block_on(async move { #block }); | ||
let summary = b.stop(stringify!(#original_name), #job_id); | ||
eprintln!("{}", summary); | ||
return; | ||
} | ||
}; | ||
Ok(expanded.into()) | ||
} | ||
|
||
impl Parse for BenchmarkArgs { | ||
fn parse(input: ParseStream) -> syn::Result<Self> { | ||
let mut cores = None; | ||
let mut job_id = None; | ||
while !input.is_empty() { | ||
let lookahead = input.lookahead1(); | ||
if lookahead.peek(kw::cores) { | ||
let _ = input.parse::<kw::cores>()?; | ||
let _ = input.parse::<Token![=]>()?; | ||
cores = Some(input.parse()?); | ||
} else if lookahead.peek(kw::job_id) { | ||
let _ = input.parse::<kw::job_id>()?; | ||
let _ = input.parse::<Token![=]>()?; | ||
job_id = Some(input.parse()?); | ||
} else if lookahead.peek(Token![,]) { | ||
let _ = input.parse::<Token![,]>()?; | ||
} else { | ||
return Err(lookahead.error()); | ||
} | ||
} | ||
|
||
let cores = cores.ok_or_else(|| input.error("Missing `cores` argument in attribute"))?; | ||
|
||
let job_id = job_id.ok_or_else(|| input.error("Missing `job_id` argument in attribute"))?; | ||
|
||
Ok(Self { cores, job_id }) | ||
} | ||
} |
This file contains 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 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 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,105 @@ | ||
pub use tokio; | ||
/// The runtime trait that all runtimes must implement. | ||
pub trait Runtime { | ||
/// Runs the given future to completion on the runtime. | ||
fn block_on<F>(&self, future: F) -> F::Output | ||
where | ||
F: std::future::Future; | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub struct TokioRuntime; | ||
|
||
impl Runtime for TokioRuntime { | ||
fn block_on<F>(&self, future: F) -> F::Output | ||
where | ||
F: std::future::Future, | ||
{ | ||
let rt = tokio::runtime::Handle::current(); | ||
rt.block_on(future) | ||
} | ||
} | ||
|
||
/// A benchmarking harness. | ||
#[derive(Debug)] | ||
pub struct Bencher<R> { | ||
/// The runtime to use for running benchmarks. | ||
runtime: R, | ||
/// The time at which the benchmark started. | ||
started_at: std::time::Instant, | ||
/// The max number of cores for this benchmark. | ||
cores: usize, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct BenchmarkSummary { | ||
/// The name of the benchmark. | ||
pub name: String, | ||
/// The job identifier. | ||
pub job_id: u8, | ||
/// The duration of the benchmark. | ||
pub elapsed: std::time::Duration, | ||
/// The number of cores the benchmark was run with. | ||
pub cores: usize, | ||
/// The amount of memory used by the benchmark (in bytes). | ||
pub ram_usage: u64, | ||
} | ||
|
||
impl<R: Runtime> Bencher<R> { | ||
pub fn new(threads: usize, runtime: R) -> Self { | ||
Self { | ||
runtime, | ||
started_at: std::time::Instant::now(), | ||
cores: threads, | ||
} | ||
} | ||
|
||
/// Runs the given future on the runtime. | ||
pub fn block_on<F>(&self, future: F) -> F::Output | ||
where | ||
F: std::future::Future, | ||
{ | ||
self.runtime.block_on(future) | ||
} | ||
|
||
/// Stops the benchmark and returns a summary of the benchmark. | ||
pub fn stop(&self, name: &str, job_id: u8) -> BenchmarkSummary { | ||
let pid = sysinfo::get_current_pid().expect("Failed to get current process ID"); | ||
let s = sysinfo::System::new_all(); | ||
let process = s | ||
.process(pid) | ||
.expect("Failed to get current process from the system"); | ||
let ram_usage = process.memory(); | ||
BenchmarkSummary { | ||
name: name.to_string(), | ||
job_id, | ||
elapsed: self.started_at.elapsed(), | ||
cores: self.cores, | ||
ram_usage, | ||
} | ||
} | ||
} | ||
|
||
impl std::fmt::Display for BenchmarkSummary { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
const KB: f32 = 1024.00; | ||
const MB: f32 = 1024.00 * KB; | ||
const GB: f32 = 1024.00 * MB; | ||
let ram_usage = self.ram_usage as f32; | ||
let (ram_usage, unit) = if ram_usage < KB { | ||
(ram_usage, "B") | ||
} else if ram_usage < MB { | ||
(ram_usage / KB, "KB") | ||
} else if ram_usage < GB { | ||
(ram_usage / MB, "MB") | ||
} else { | ||
(ram_usage / GB, "GB") | ||
}; | ||
|
||
write!( | ||
f, | ||
"Benchmark: {}\nJob ID: {}\nElapsed: {:?}\nvCPU: {}\nRAM Usage: {ram_usage:.2} {unit}\n", | ||
self.name, self.job_id, self.elapsed, self.cores, | ||
) | ||
} | ||
} |
This file contains 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 |
---|---|---|
|
@@ -39,4 +39,6 @@ pub mod network; | |
|
||
pub mod slashing; | ||
|
||
pub mod benchmark; | ||
|
||
pub use gadget_blueprint_proc_macro::*; |