Skip to content

Commit 5ecf93e

Browse files
committed
fix(cargo-codspeed): properly forward stdout compiler messages
1 parent 47c3cdd commit 5ecf93e

File tree

2 files changed

+155
-4
lines changed

2 files changed

+155
-4
lines changed

crates/cargo-codspeed/src/build.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,16 @@ impl BuildOptions<'_> {
4343

4444
let mut built_benches = Vec::new();
4545
for message in Message::parse_stream(reader) {
46-
if let Message::CompilerArtifact(artifact) =
47-
message.expect("Failed to parse compiler message")
48-
{
49-
if artifact.target.is_kind(TargetKind::Bench) {
46+
match message.expect("Failed to parse message") {
47+
Message::CompilerMessage(msg) => {
48+
println!("{}", &msg.message);
49+
}
50+
Message::TextLine(line) => {
51+
println!("{}", line);
52+
}
53+
Message::CompilerArtifact(artifact)
54+
if artifact.target.is_kind(TargetKind::Bench) =>
55+
{
5056
let package = workspace_packages
5157
.iter()
5258
.find(|p| p.id == artifact.package_id)
@@ -71,6 +77,7 @@ impl BuildOptions<'_> {
7177
});
7278
}
7379
}
80+
_ => {}
7481
}
7582
}
7683

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use codspeed::walltime::{BenchmarkMetadata, RawWallTimeData};
2+
use serde::{Deserialize, Serialize};
3+
use statrs::statistics::{Data, Distribution, Max, Min, OrderStatistics};
4+
5+
const IQR_OUTLIER_FACTOR: f64 = 1.5;
6+
const STDEV_OUTLIER_FACTOR: f64 = 3.0;
7+
8+
#[derive(Debug, Serialize, Deserialize)]
9+
struct BenchmarkStats {
10+
min_ns: f64,
11+
max_ns: f64,
12+
mean_ns: f64,
13+
stdev_ns: f64,
14+
15+
q1_ns: f64,
16+
median_ns: f64,
17+
q3_ns: f64,
18+
19+
rounds: u64,
20+
total_time: f64,
21+
iqr_outlier_rounds: u64,
22+
stdev_outlier_rounds: u64,
23+
iter_per_round: u64,
24+
warmup_iters: u64,
25+
}
26+
27+
#[derive(Debug, Serialize, Deserialize, Default)]
28+
struct BenchmarkConfig {
29+
warmup_time_ns: Option<f64>,
30+
min_round_time_ns: Option<f64>,
31+
max_time_ns: Option<f64>,
32+
max_rounds: Option<u64>,
33+
}
34+
35+
#[derive(Debug, Serialize, Deserialize)]
36+
pub struct WalltimeBenchmark {
37+
#[serde(flatten)]
38+
metadata: BenchmarkMetadata,
39+
40+
config: BenchmarkConfig,
41+
stats: BenchmarkStats,
42+
}
43+
44+
impl From<RawWallTimeData> for WalltimeBenchmark {
45+
fn from(value: RawWallTimeData) -> Self {
46+
let times_ns: Vec<f64> = value.times_ns.iter().map(|&t| t as f64).collect();
47+
let mut data = Data::new(times_ns.clone());
48+
let rounds = data.len() as u64;
49+
let total_time = times_ns.iter().sum::<f64>() / 1_000_000_000.0;
50+
51+
let mean_ns = data.mean().unwrap();
52+
let stdev_ns = data.std_dev().unwrap();
53+
54+
let q1_ns = data.quantile(0.25);
55+
let median_ns = data.median();
56+
let q3_ns = data.quantile(0.75);
57+
58+
let iqr_ns = q3_ns - q1_ns;
59+
let iqr_outlier_rounds = data
60+
.iter()
61+
.filter(|&&t| {
62+
t < q1_ns - IQR_OUTLIER_FACTOR * iqr_ns || t > q3_ns + IQR_OUTLIER_FACTOR * iqr_ns
63+
})
64+
.count() as u64;
65+
66+
let stdev_outlier_rounds = data
67+
.iter()
68+
.filter(|&&t| {
69+
t < mean_ns - STDEV_OUTLIER_FACTOR * stdev_ns
70+
|| t > mean_ns + STDEV_OUTLIER_FACTOR * stdev_ns
71+
})
72+
.count() as u64;
73+
74+
let min_ns = data.min();
75+
let max_ns = data.max();
76+
77+
let iter_per_round = value.iter_per_round as u64;
78+
let warmup_iters = 0; // FIXME: add warmup detection
79+
80+
let stats = BenchmarkStats {
81+
min_ns,
82+
max_ns,
83+
mean_ns,
84+
stdev_ns,
85+
q1_ns,
86+
median_ns,
87+
q3_ns,
88+
rounds,
89+
total_time,
90+
iqr_outlier_rounds,
91+
stdev_outlier_rounds,
92+
iter_per_round,
93+
warmup_iters,
94+
};
95+
96+
WalltimeBenchmark {
97+
metadata: BenchmarkMetadata {
98+
name: value.metadata.name,
99+
uri: value.metadata.uri,
100+
},
101+
config: BenchmarkConfig {
102+
max_time_ns: value.max_time_ns.map(|t| t as f64),
103+
..Default::default()
104+
},
105+
stats,
106+
}
107+
}
108+
}
109+
110+
#[derive(Debug, Serialize, Deserialize)]
111+
struct Instrument {
112+
#[serde(rename = "type")]
113+
type_: String,
114+
}
115+
116+
#[derive(Debug, Serialize, Deserialize)]
117+
struct Creator {
118+
name: String,
119+
version: String,
120+
pid: u32,
121+
}
122+
123+
#[derive(Debug, Serialize, Deserialize)]
124+
pub struct WalltimeResults {
125+
creator: Creator,
126+
instrument: Instrument,
127+
benchmarks: Vec<WalltimeBenchmark>,
128+
}
129+
130+
impl WalltimeResults {
131+
pub fn from_benchmarks(benchmarks: Vec<WalltimeBenchmark>) -> Self {
132+
WalltimeResults {
133+
instrument: Instrument {
134+
type_: "walltime".to_string(),
135+
},
136+
creator: Creator {
137+
name: "codspeed-rust".to_string(),
138+
version: env!("CARGO_PKG_VERSION").to_string(),
139+
pid: std::process::id(),
140+
},
141+
benchmarks,
142+
}
143+
}
144+
}

0 commit comments

Comments
 (0)