Skip to content

Commit 0ee9f0c

Browse files
authored
Merge pull request #2400 from Kobzol/runtime-pstat-detection
Implement granular runtime benchmark result detection
2 parents 4f636c8 + a6091d2 commit 0ee9f0c

File tree

6 files changed

+138
-212
lines changed

6 files changed

+138
-212
lines changed

collector/src/bin/collector.rs

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -444,19 +444,11 @@ struct BenchRustcOption {
444444
bench_rustc: bool,
445445
}
446446

447-
#[derive(Clone, Debug, clap::ValueEnum)]
448-
enum PurgeMode {
449-
/// Purge all old data associated with the artifact
450-
Old,
451-
/// Purge old data of failed benchmarks associated with the artifact
452-
Failed,
453-
}
454-
455447
#[derive(Debug, clap::Args)]
456448
struct PurgeOption {
457449
/// Removes old data for the specified artifact prior to running the benchmarks.
458450
#[arg(long = "purge")]
459-
purge: Option<PurgeMode>,
451+
purge: bool,
460452
}
461453

462454
#[derive(Debug, clap::Args)]
@@ -872,7 +864,9 @@ fn main_result() -> anyhow::Result<i32> {
872864
r#type: CommitType::Master,
873865
});
874866

875-
rt.block_on(purge_old_data(conn.as_mut(), &artifact_id, purge.purge));
867+
if purge.purge {
868+
rt.block_on(conn.purge_artifact(&artifact_id));
869+
}
876870

877871
let runtime_suite = rt.block_on(load_runtime_benchmarks(
878872
conn.as_mut(),
@@ -1028,7 +1022,9 @@ fn main_result() -> anyhow::Result<i32> {
10281022

10291023
let rt = build_async_runtime();
10301024
let mut conn = rt.block_on(pool.connection());
1031-
rt.block_on(purge_old_data(conn.as_mut(), &artifact_id, purge.purge));
1025+
if purge.purge {
1026+
rt.block_on(conn.purge_artifact(&artifact_id));
1027+
}
10321028

10331029
let shared = SharedBenchmarkConfig {
10341030
toolchain,
@@ -2047,28 +2043,6 @@ fn log_db(db_option: &DbOption) {
20472043
println!("Using database `{}`", db_option.db);
20482044
}
20492045

2050-
async fn purge_old_data(
2051-
conn: &mut dyn Connection,
2052-
artifact_id: &ArtifactId,
2053-
purge_mode: Option<PurgeMode>,
2054-
) {
2055-
match purge_mode {
2056-
Some(PurgeMode::Old) => {
2057-
// Delete everything associated with the artifact
2058-
conn.purge_artifact(artifact_id).await;
2059-
}
2060-
Some(PurgeMode::Failed) => {
2061-
// Delete all benchmarks that have an error for the given artifact
2062-
let artifact_row_id = conn.artifact_id(artifact_id).await;
2063-
let errors = conn.get_error(artifact_row_id).await;
2064-
for krate in errors.keys() {
2065-
conn.collector_remove_step(artifact_row_id, krate).await;
2066-
}
2067-
}
2068-
None => {}
2069-
}
2070-
}
2071-
20722046
/// Record a collection entry into the database, specifying which benchmark steps will be executed.
20732047
async fn init_collection(
20742048
connection: &mut dyn Connection,
@@ -2233,8 +2207,6 @@ async fn bench_compile(
22332207
print_intro: &dyn Fn(),
22342208
measure: F,
22352209
) {
2236-
collector.start_compile_step(conn, benchmark_name).await;
2237-
22382210
let mut tx = conn.transaction().await;
22392211
let (supports_stable, category) = category.db_representation();
22402212
tx.conn()
@@ -2261,7 +2233,6 @@ async fn bench_compile(
22612233
)
22622234
.await;
22632235
};
2264-
collector.end_compile_step(tx.conn(), benchmark_name).await;
22652236
tx.commit().await.expect("committed");
22662237
}
22672238

collector/src/lib.rs

Lines changed: 28 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ mod self_profile;
1515
pub mod toolchain;
1616
pub mod utils;
1717

18-
use crate::compile::benchmark::{Benchmark, BenchmarkName};
18+
use crate::compile::benchmark::Benchmark;
1919
use crate::runtime::{BenchmarkGroup, BenchmarkSuite};
2020
pub use crate::self_profile::{
2121
LocalSelfProfileStorage, S3SelfProfileStorage, SelfProfileId, SelfProfileStorage,
2222
};
23-
use database::selector::CompileTestCase;
23+
use database::selector::{CompileTestCase, RuntimeTestCase};
2424
use database::{ArtifactId, ArtifactIdNumber, Connection};
2525
use hashbrown::HashSet;
2626
use process::Stdio;
@@ -342,27 +342,22 @@ impl CollectorStepBuilder {
342342
) -> CollectorCtx {
343343
// Make sure there is no observable time when the artifact ID is available
344344
// but the in-progress steps are not.
345-
let artifact_row_id = {
346-
let mut tx = conn.transaction().await;
347-
let artifact_row_id = tx.conn().artifact_id(artifact_id).await;
348-
if self.job_id.is_none() {
349-
tx.conn()
350-
.collector_start(artifact_row_id, &self.steps)
351-
.await;
352-
}
353-
tx.commit().await.unwrap();
354-
artifact_row_id
355-
};
345+
let artifact_row_id = conn.artifact_id(artifact_id).await;
356346
// Find out which tests cases were already computed
357347
let measured_compile_test_cases = conn
358348
.get_compile_test_cases_with_measurements(&artifact_row_id)
359349
.await
360350
.expect("cannot fetch measured compile test cases from DB");
351+
let measured_runtime_benchmarks = conn
352+
.get_runtime_benchmarks_with_measurements(&artifact_row_id)
353+
.await
354+
.expect("cannot fetch measured runtime benchmarks from DB");
361355

362356
CollectorCtx {
363357
artifact_row_id,
364358
artifact_id: artifact_id.clone(),
365359
measured_compile_test_cases,
360+
measured_runtime_benchmarks,
366361
job_id: self.job_id,
367362
}
368363
}
@@ -372,53 +367,32 @@ impl CollectorStepBuilder {
372367
pub struct CollectorCtx {
373368
pub artifact_row_id: ArtifactIdNumber,
374369
pub artifact_id: ArtifactId,
375-
/// Which tests cases were already computed **before** this collection began?
370+
/// Which compile test cases were already computed **before** this collection began?
376371
pub measured_compile_test_cases: HashSet<CompileTestCase>,
372+
/// Which runtime benchmarks were already computed **before** this collection began?
373+
pub measured_runtime_benchmarks: HashSet<RuntimeTestCase>,
377374
pub job_id: Option<u32>,
378375
}
379376

380377
impl CollectorCtx {
381-
pub fn is_from_job_queue(&self) -> bool {
382-
self.job_id.is_some()
383-
}
384-
385-
pub async fn start_compile_step(&self, conn: &dyn Connection, benchmark_name: &BenchmarkName) {
386-
if !self.is_from_job_queue() {
387-
conn.collector_start_step(self.artifact_row_id, &benchmark_name.0)
388-
.await;
389-
}
390-
}
391-
392-
pub async fn end_compile_step(&self, conn: &dyn Connection, benchmark_name: &BenchmarkName) {
393-
if !self.is_from_job_queue() {
394-
conn.collector_end_step(self.artifact_row_id, &benchmark_name.0)
395-
.await;
396-
}
397-
}
398-
399-
/// Starts a new runtime benchmark collector step.
400-
/// If this step was already computed, returns None.
401-
/// Otherwise returns Some(<name of step>).
402-
pub async fn start_runtime_step(
378+
/// Returns the names of benchmarks in the group that have not yet been measured
379+
/// for the given target.
380+
pub fn get_unmeasured_runtime_benchmarks<'a>(
403381
&self,
404-
conn: &dyn Connection,
405-
group: &BenchmarkGroup,
406-
) -> Option<String> {
407-
let step_name = runtime_group_step_name(&group.name);
408-
if self.is_from_job_queue() {
409-
Some(step_name)
410-
} else {
411-
conn.collector_start_step(self.artifact_row_id, &step_name)
412-
.await
413-
.then_some(step_name)
414-
}
415-
}
416-
417-
pub async fn end_runtime_step(&self, conn: &dyn Connection, group: &BenchmarkGroup) {
418-
if !self.is_from_job_queue() {
419-
conn.collector_end_step(self.artifact_row_id, &runtime_group_step_name(&group.name))
420-
.await;
421-
}
382+
group: &'a BenchmarkGroup,
383+
target: database::Target,
384+
) -> Vec<&'a str> {
385+
group
386+
.benchmark_names
387+
.iter()
388+
.filter(|name| {
389+
!self.measured_runtime_benchmarks.contains(&RuntimeTestCase {
390+
benchmark: database::Benchmark::from(name.as_str()),
391+
target,
392+
})
393+
})
394+
.map(|s| s.as_str())
395+
.collect()
422396
}
423397
}
424398

collector/src/runtime/mod.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::process::{Command, Stdio};
66
use anyhow::Context;
77
use thousands::Separable;
88

9+
use benchlib::benchmark::passes_filter;
910
use benchlib::comm::messages::{BenchmarkMessage, BenchmarkResult, BenchmarkStats};
1011
pub use benchmark::{
1112
get_runtime_benchmark_groups, prepare_runtime_benchmark_suite, runtime_benchmark_dir,
@@ -14,6 +15,7 @@ pub use benchmark::{
1415
};
1516
use database::{ArtifactIdNumber, CollectionId, Connection};
1617

18+
use crate::runtime_group_step_name;
1719
use crate::utils::git::get_rustc_perf_commit;
1820
use crate::{command_output, CollectorCtx};
1921

@@ -38,24 +40,56 @@ pub async fn bench_runtime(
3840
iterations: u32,
3941
target: Target,
4042
) -> anyhow::Result<()> {
41-
let filtered = suite.filtered_benchmark_count(&filter);
43+
let db_target: database::Target = target.into();
44+
45+
// Compute the total number of benchmarks to run, excluding already-measured ones.
46+
let filtered: u64 = suite
47+
.groups
48+
.iter()
49+
.flat_map(|group| collector.get_unmeasured_runtime_benchmarks(group, db_target))
50+
.filter(|name| passes_filter(name, &filter.exclude, &filter.include))
51+
.count() as u64;
4252
println!("Executing {filtered} benchmarks\n");
4353

4454
let rustc_perf_version = get_rustc_perf_commit();
4555
let mut benchmark_index = 0;
4656
for group in suite.groups {
47-
let Some(step_name) = collector.start_runtime_step(conn, &group).await else {
57+
let unmeasured = collector.get_unmeasured_runtime_benchmarks(&group, db_target);
58+
if unmeasured.is_empty() {
4859
eprintln!("skipping {} -- already benchmarked", group.name);
4960
continue;
50-
};
61+
}
62+
63+
// Construct a filter that excludes already-measured benchmarks, combined with the
64+
// user-provided filter.
65+
let mut group_filter =
66+
RuntimeBenchmarkFilter::new(filter.exclude.clone(), filter.include.clone());
67+
for name in &group.benchmark_names {
68+
if !unmeasured.contains(&name.as_str()) {
69+
group_filter.exclude.push(name.clone());
70+
}
71+
}
72+
73+
// Check if any benchmarks remain after filtering
74+
let has_benchmarks = group
75+
.benchmark_names
76+
.iter()
77+
.any(|name| passes_filter(name, &group_filter.exclude, &group_filter.include));
78+
if !has_benchmarks {
79+
eprintln!("skipping {} -- already benchmarked", group.name);
80+
continue;
81+
}
82+
83+
let step_name = runtime_group_step_name(&group.name);
5184

5285
let mut tx = conn.transaction().await;
5386

5487
// Async block is used to easily capture all results, it basically simulates a `try` block.
5588
// Extracting this into a separate function would be annoying, as there would be many
5689
// parameters.
5790
let result = async {
58-
let messages = execute_runtime_benchmark_binary(&group.binary, &filter, iterations)?;
91+
let messages =
92+
execute_runtime_benchmark_binary(&group.binary, &group_filter, iterations)?;
5993
for message in messages {
6094
let message = message.map_err(|err| {
6195
anyhow::anyhow!(
@@ -101,7 +135,6 @@ pub async fn bench_runtime(
101135
.await;
102136
};
103137

104-
collector.end_runtime_step(tx.conn(), &group).await;
105138
tx.commit()
106139
.await
107140
.expect("Cannot commit runtime benchmark group results");

database/src/pool.rs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::selector::CompileTestCase;
1+
use crate::selector::{CompileTestCase, RuntimeTestCase};
22
use crate::{
33
ArtifactId, ArtifactIdNumber, BenchmarkJob, BenchmarkJobConclusion, BenchmarkJobKind,
44
BenchmarkRequest, BenchmarkRequestIndex, BenchmarkRequestInsertResult, BenchmarkRequestStatus,
@@ -123,20 +123,6 @@ pub trait Connection: Send + Sync {
123123
) -> Vec<Vec<Option<f64>>>;
124124
async fn get_error(&self, artifact_row_id: ArtifactIdNumber) -> HashMap<String, String>;
125125

126-
// Collector status API
127-
128-
// TODO: these functions should be removed. The only useful user of them currently are runtime
129-
// benchmarks, which should switch to something similar to
130-
// `get_compile_test_cases_with_measurements`.
131-
async fn collector_start(&self, aid: ArtifactIdNumber, steps: &[String]);
132-
133-
// Returns `true` if the step was started, i.e., it did not previously have
134-
// an end. Otherwise returns false, indicating that we can skip it.
135-
async fn collector_start_step(&self, aid: ArtifactIdNumber, step: &str) -> bool;
136-
async fn collector_end_step(&self, aid: ArtifactIdNumber, step: &str);
137-
138-
async fn collector_remove_step(&self, aid: ArtifactIdNumber, step: &str);
139-
140126
/// Returns the SHA of the parent of the given SHA commit, if available.
141127
async fn parent_of(&self, sha: &str) -> Option<String>;
142128

@@ -221,6 +207,13 @@ pub trait Connection: Send + Sync {
221207
artifact_row_id: &ArtifactIdNumber,
222208
) -> anyhow::Result<HashSet<CompileTestCase>>;
223209

210+
/// Returns a set of runtime benchmark names that already have measurements
211+
/// for the given artifact in the runtime_pstat table.
212+
async fn get_runtime_benchmarks_with_measurements(
213+
&self,
214+
artifact_row_id: &ArtifactIdNumber,
215+
) -> anyhow::Result<HashSet<RuntimeTestCase>>;
216+
224217
/// Add the confiuguration for a collector
225218
async fn add_collector_config(
226219
&self,

0 commit comments

Comments
 (0)