Skip to content

Commit 8fd0df4

Browse files
committed
Add support for capturing multiple measurements
Previously, only a single measure type could be requested. Often, we might want to capture multiple measures on a benchmark run as different measurements might provide a more complete picture of a given benchmark iteration.
1 parent 1e1d306 commit 8fd0df4

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

crates/cli/src/benchmark.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rand::{rngs::SmallRng, Rng, SeedableRng};
44
use sightglass_data::{Format, Measurement, Phase};
55
use sightglass_recorder::bench_api::Engine;
66
use sightglass_recorder::cpu_affinity::bind_to_single_core;
7+
use sightglass_recorder::measure::multi::MultiMeasure;
78
use sightglass_recorder::measure::Measurements;
89
use sightglass_recorder::{bench_api::BenchApi, benchmark, measure::MeasureType};
910
use std::{
@@ -80,9 +81,11 @@ pub struct BenchmarkCommand {
8081
output_file: Option<String>,
8182

8283
/// The type of measurement to use (cycles, insts-retired, perf-counters, noop, vtune)
83-
/// when recording the benchmark performance.
84-
#[structopt(long, short, default_value = "cycles")]
85-
measure: MeasureType,
84+
/// when recording the benchmark performance. This option can be specified more than
85+
/// once if to record multiple measurements. If no measures are specified,
86+
/// the "cycles" measure will be used.
87+
#[structopt(long = "measure", short = "m", multiple = true)]
88+
measures: Vec<MeasureType>,
8689

8790
/// Pass this flag to only run benchmarks over "small" workloads (rather
8891
/// than the larger, default workloads).
@@ -194,7 +197,12 @@ impl BenchmarkCommand {
194197
let stdin = None;
195198

196199
let mut measurements = Measurements::new(this_arch(), engine, wasm_file);
197-
let mut measure = self.measure.build();
200+
let mut measure = if self.measures.len() <= 1 {
201+
let measure = self.measures.first().unwrap_or(&MeasureType::Cycles);
202+
measure.build()
203+
} else {
204+
Box::new(MultiMeasure::new(self.measures.iter().map(|m| m.build())))
205+
};
198206

199207
// Create the bench API engine and cache it for reuse across all
200208
// iterations of this benchmark.
@@ -354,8 +362,12 @@ impl BenchmarkCommand {
354362
.arg(self.iterations_per_process.to_string())
355363
.arg("--engine")
356364
.arg(&engine)
357-
.arg("--measure")
358-
.arg(self.measure.to_string())
365+
.args(
366+
self.measures
367+
.iter()
368+
.map(|m| ["--measure".to_string(), m.to_string()])
369+
.flatten(),
370+
)
359371
.arg("--raw")
360372
.arg("--output-format")
361373
// Always use JSON when privately communicating with a

crates/recorder/src/measure/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub mod counters;
8383
pub mod insts;
8484

8585
pub mod cycles;
86+
pub mod multi;
8687
pub mod noop;
8788
pub mod time;
8889
pub mod vtune;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! Multiplexing measurement in order to take multiple measures
2+
//! from a single entry point.
3+
4+
use sightglass_data::Phase;
5+
6+
use super::{Measure, Measurements};
7+
8+
pub struct MultiMeasure {
9+
measures: Vec<Box<dyn Measure>>
10+
}
11+
12+
impl MultiMeasure {
13+
pub fn new<I>(measures: I) -> Self
14+
where I: IntoIterator<Item = Box<dyn Measure>>
15+
{
16+
Self {
17+
measures: measures.into_iter().collect()
18+
}
19+
}
20+
}
21+
22+
impl Measure for MultiMeasure {
23+
fn start(&mut self, phase: Phase) {
24+
for measure in self.measures.iter_mut() {
25+
measure.start(phase)
26+
}
27+
}
28+
29+
fn end(&mut self, phase: Phase, measurements: &mut Measurements) {
30+
for measure in self.measures.iter_mut() {
31+
measure.end(phase, measurements)
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)