Skip to content

Commit b420aaf

Browse files
authored
Merge pull request #2252 from Kobzol/benchmark-index-in-memory
Do not use the benchmark index when computing benchmark request queue
2 parents 4e9a6bb + 962de49 commit b420aaf

File tree

9 files changed

+195
-199
lines changed

9 files changed

+195
-199
lines changed

database/src/lib.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,29 +1041,23 @@ impl BenchmarkRequest {
10411041
}
10421042

10431043
/// Cached information about benchmark requests in the DB
1044-
/// FIXME: only store non-try requests here
10451044
pub struct BenchmarkRequestIndex {
10461045
/// Tags (SHA or release name) of all known benchmark requests
10471046
all: HashSet<String>,
1048-
/// Tags (SHA or release name) of all benchmark requests in the completed status
1049-
completed: HashSet<String>,
10501047
}
10511048

10521049
impl BenchmarkRequestIndex {
10531050
/// Do we already have a benchmark request for the passed `tag`?
10541051
pub fn contains_tag(&self, tag: &str) -> bool {
10551052
self.all.contains(tag)
10561053
}
1054+
}
10571055

1058-
/// Return tags of already completed benchmark requests.
1059-
pub fn completed_requests(&self) -> &HashSet<String> {
1060-
&self.completed
1061-
}
1062-
1063-
pub fn add_tag(&mut self, tag: &str) {
1064-
self.all.insert(tag.to_string());
1065-
self.completed.insert(tag.to_string());
1066-
}
1056+
/// Contains pending (ArtifactsReady or InProgress) benchmark requests, and a set of their parents
1057+
/// that are already completed.
1058+
pub struct PendingBenchmarkRequests {
1059+
pub requests: Vec<BenchmarkRequest>,
1060+
pub completed_parent_tags: HashSet<String>,
10671061
}
10681062

10691063
#[derive(Debug, Clone, PartialEq)]

database/src/pool.rs

Lines changed: 47 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::selector::CompileTestCase;
22
use crate::{
33
ArtifactCollection, ArtifactId, ArtifactIdNumber, BenchmarkJob, BenchmarkJobConclusion,
44
BenchmarkRequest, BenchmarkRequestIndex, BenchmarkRequestStatus, BenchmarkRequestWithErrors,
5-
BenchmarkSet, CodegenBackend, CollectorConfig, CompileBenchmark, Target,
5+
BenchmarkSet, CodegenBackend, CollectorConfig, CompileBenchmark, PendingBenchmarkRequests,
6+
Target,
67
};
78
use crate::{CollectionId, Index, Profile, QueuedCommit, Scenario, Step};
89
use chrono::{DateTime, Utc};
@@ -189,7 +190,8 @@ pub trait Connection: Send + Sync {
189190
async fn purge_artifact(&self, aid: &ArtifactId);
190191

191192
/// Add an item to the `benchmark_requests`, if the `benchmark_request`
192-
/// exists an Error will be returned
193+
/// exists an Error will be returned.
194+
/// We require the caller to pass an index, to ensure that it is always kept up-to-date.
193195
async fn insert_benchmark_request(
194196
&self,
195197
benchmark_request: &BenchmarkRequest,
@@ -200,7 +202,9 @@ pub trait Connection: Send + Sync {
200202

201203
/// Load all pending benchmark requests, i.e. those that have artifacts ready, but haven't
202204
/// been completed yet. Pending statuses are `ArtifactsReady` and `InProgress`.
203-
async fn load_pending_benchmark_requests(&self) -> anyhow::Result<Vec<BenchmarkRequest>>;
205+
/// Also returns their parents, so that we can quickly check which requests are ready for being
206+
/// enqueued.
207+
async fn load_pending_benchmark_requests(&self) -> anyhow::Result<PendingBenchmarkRequests>;
204208

205209
/// Update the status of a `benchmark_request` with the given `tag`.
206210
/// If no such request exists in the DB, returns an error.
@@ -426,9 +430,9 @@ mod tests {
426430
use crate::tests::run_postgres_test;
427431
use crate::{tests::run_db_test, BenchmarkRequestType, Commit, CommitType, Date};
428432
use chrono::Utc;
433+
use std::collections::BTreeSet;
429434
use std::str::FromStr;
430435

431-
/// Create a Commit
432436
fn create_commit(commit_sha: &str, time: chrono::DateTime<Utc>, r#type: CommitType) -> Commit {
433437
Commit {
434438
sha: commit_sha.into(),
@@ -437,43 +441,6 @@ mod tests {
437441
}
438442
}
439443

440-
async fn complete_request(
441-
db: &dyn Connection,
442-
request_tag: &str,
443-
collector_name: &str,
444-
benchmark_set: u32,
445-
target: Target,
446-
) {
447-
/* Create job for the request */
448-
db.enqueue_benchmark_job(
449-
request_tag,
450-
target,
451-
CodegenBackend::Llvm,
452-
Profile::Opt,
453-
benchmark_set,
454-
)
455-
.await
456-
.unwrap();
457-
458-
let (job, _) = db
459-
.dequeue_benchmark_job(collector_name, target, BenchmarkSet(benchmark_set))
460-
.await
461-
.unwrap()
462-
.unwrap();
463-
464-
assert_eq!(job.request_tag(), request_tag);
465-
466-
/* Mark the job as complete */
467-
db.mark_benchmark_job_as_completed(job.id(), BenchmarkJobConclusion::Success)
468-
.await
469-
.unwrap();
470-
471-
assert!(db
472-
.maybe_mark_benchmark_request_as_completed(request_tag)
473-
.await
474-
.unwrap());
475-
}
476-
477444
#[tokio::test]
478445
async fn pstat_returns_empty_vector_when_empty() {
479446
run_db_test(|ctx| async {
@@ -559,37 +526,25 @@ mod tests {
559526
async fn multiple_non_completed_try_requests() {
560527
run_postgres_test(|ctx| async {
561528
let db = ctx.db();
562-
let target = Target::X86_64UnknownLinuxGnu;
563-
let collector_name = "collector-1";
564-
let benchmark_set = 1;
565-
566-
db.add_collector_config(collector_name, target, benchmark_set, true)
567-
.await
568-
.unwrap();
569529

570-
// Complete parent
571-
let parent = BenchmarkRequest::create_release("sha-parent-1", Utc::now());
572-
// Complete
573-
let req_a = BenchmarkRequest::create_try_without_artifacts(42, "", "");
574-
// WaitingForArtifacts
575-
let req_b = BenchmarkRequest::create_try_without_artifacts(42, "", "");
576-
let req_c = BenchmarkRequest::create_try_without_artifacts(42, "", "");
577-
578-
db.insert_benchmark_request(&parent).await.unwrap();
579-
db.insert_benchmark_request(&req_a).await.unwrap();
580-
db.attach_shas_to_try_benchmark_request(42, "sha1", "sha-parent-1", Utc::now())
530+
// Insert a try build
531+
ctx.insert_try_request(42).await;
532+
db.attach_shas_to_try_benchmark_request(42, "sha-1", "sha-parent-1", Utc::now())
581533
.await
582534
.unwrap();
583535

584-
complete_request(db, "sha-parent-1", collector_name, benchmark_set, target).await;
585-
complete_request(db, "sha1", collector_name, benchmark_set, target).await;
536+
// Then finish it
537+
ctx.complete_request("sha-1").await;
586538

587-
// This should be fine, req_a was completed
588-
db.insert_benchmark_request(&req_b).await.unwrap();
589-
// This should fail, we can't have two queued requests at once
590-
db.insert_benchmark_request(&req_c).await.expect_err(
591-
"It was possible to record two try benchmark requests without artifacts",
592-
);
539+
// Insert a try build for the same PR again
540+
// This should be fine, because the previous request was already completed
541+
ctx.insert_try_request(42).await;
542+
// But this should fail, as we can't have two queued requests at once
543+
db.insert_benchmark_request(&BenchmarkRequest::create_try_without_artifacts(
544+
42, "", "",
545+
))
546+
.await
547+
.expect_err("It was possible to record two try benchmark requests without artifacts");
593548

594549
Ok(ctx)
595550
})
@@ -629,43 +584,48 @@ mod tests {
629584
async fn load_pending_benchmark_requests() {
630585
run_postgres_test(|ctx| async {
631586
let db = ctx.db();
632-
let time = chrono::DateTime::from_str("2021-09-01T00:00:00.000Z").unwrap();
633-
let target = Target::X86_64UnknownLinuxGnu;
634-
let collector_name = "collector-1";
635-
let benchmark_set = 1;
636-
637-
db.add_collector_config(collector_name, target, benchmark_set, true)
638-
.await
639-
.unwrap();
640587

641588
// ArtifactsReady
642-
let req_a = BenchmarkRequest::create_master("sha-1", "parent-sha-1", 42, time);
589+
let req_a = ctx.insert_master_request("sha-1", "parent-sha-1", 42).await;
643590
// ArtifactsReady
644-
let req_b = BenchmarkRequest::create_release("1.80.0", time);
591+
let req_b = ctx.insert_release_request("1.80.0").await;
645592
// WaitingForArtifacts
646-
let req_c = BenchmarkRequest::create_try_without_artifacts(50, "", "");
593+
ctx.insert_try_request(50).await;
647594
// InProgress
648-
let req_d = BenchmarkRequest::create_master("sha-2", "parent-sha-2", 51, time);
595+
let req_d = ctx.insert_master_request("sha-2", "parent-sha-2", 51).await;
649596
// Completed
650-
let req_e = BenchmarkRequest::create_release("1.79.0", time);
597+
ctx.insert_release_request("1.79.0").await;
651598

652-
for &req in &[&req_a, &req_b, &req_c, &req_d, &req_e] {
653-
db.insert_benchmark_request(req).await.unwrap();
654-
}
655-
656-
complete_request(db, "1.79.0", collector_name, benchmark_set, target).await;
599+
ctx.complete_request("1.79.0").await;
600+
ctx.insert_master_request("parent-sha-1", "grandparent-sha-0", 100)
601+
.await;
602+
ctx.complete_request("parent-sha-1").await;
603+
ctx.insert_master_request("parent-sha-2", "grandparent-sha-1", 101)
604+
.await;
605+
ctx.complete_request("parent-sha-2").await;
657606

658607
db.update_benchmark_request_status("sha-2", BenchmarkRequestStatus::InProgress)
659608
.await
660609
.unwrap();
661610

662-
let requests = db.load_pending_benchmark_requests().await.unwrap();
611+
let pending = db.load_pending_benchmark_requests().await.unwrap();
612+
let requests = pending.requests;
663613

664614
assert_eq!(requests.len(), 3);
665615
for req in &[req_a, req_b, req_d] {
666616
assert!(requests.iter().any(|r| r.tag() == req.tag()));
667617
}
668618

619+
assert_eq!(
620+
pending
621+
.completed_parent_tags
622+
.into_iter()
623+
.collect::<BTreeSet<_>>()
624+
.into_iter()
625+
.collect::<Vec<_>>(),
626+
vec!["parent-sha-1".to_string(), "parent-sha-2".to_string()]
627+
);
628+
669629
Ok(ctx)
670630
})
671631
.await;
@@ -687,6 +647,7 @@ mod tests {
687647
.load_pending_benchmark_requests()
688648
.await
689649
.unwrap()
650+
.requests
690651
.into_iter()
691652
.next()
692653
.unwrap();

database/src/pool/postgres.rs

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use crate::{
55
BenchmarkJobConclusion, BenchmarkJobStatus, BenchmarkRequest, BenchmarkRequestIndex,
66
BenchmarkRequestStatus, BenchmarkRequestType, BenchmarkRequestWithErrors, BenchmarkSet,
77
CodegenBackend, CollectionId, CollectorConfig, Commit, CommitType, CompileBenchmark, Date,
8-
Index, Profile, QueuedCommit, Scenario, Target, BENCHMARK_JOB_STATUS_FAILURE_STR,
9-
BENCHMARK_JOB_STATUS_IN_PROGRESS_STR, BENCHMARK_JOB_STATUS_QUEUED_STR,
10-
BENCHMARK_JOB_STATUS_SUCCESS_STR, BENCHMARK_REQUEST_MASTER_STR, BENCHMARK_REQUEST_RELEASE_STR,
8+
Index, PendingBenchmarkRequests, Profile, QueuedCommit, Scenario, Target,
9+
BENCHMARK_JOB_STATUS_FAILURE_STR, BENCHMARK_JOB_STATUS_IN_PROGRESS_STR,
10+
BENCHMARK_JOB_STATUS_QUEUED_STR, BENCHMARK_JOB_STATUS_SUCCESS_STR,
11+
BENCHMARK_REQUEST_MASTER_STR, BENCHMARK_REQUEST_RELEASE_STR,
1112
BENCHMARK_REQUEST_STATUS_ARTIFACTS_READY_STR, BENCHMARK_REQUEST_STATUS_COMPLETED_STR,
1213
BENCHMARK_REQUEST_STATUS_IN_PROGRESS_STR, BENCHMARK_REQUEST_STATUS_WAITING_FOR_ARTIFACTS_STR,
1314
BENCHMARK_REQUEST_TRY_STR,
@@ -500,6 +501,7 @@ pub struct CachedStatements {
500501
get_compile_test_cases_with_measurements: Statement,
501502
get_last_n_completed_requests_with_errors: Statement,
502503
get_jobs_of_in_progress_benchmark_requests: Statement,
504+
load_pending_benchmark_requests: Statement,
503505
}
504506

505507
pub struct PostgresTransaction<'a> {
@@ -683,7 +685,7 @@ impl PostgresConnection {
683685
where aid = $1
684686
").await.unwrap(),
685687
load_benchmark_request_index: conn.prepare("
686-
SELECT tag, status
688+
SELECT tag
687689
FROM benchmark_request
688690
WHERE tag IS NOT NULL
689691
").await.unwrap(),
@@ -751,6 +753,18 @@ impl PostgresConnection {
751753
-- Only get the jobs of in_progress requests
752754
SELECT * FROM job_queue INNER JOIN requests ON job_queue.request_tag = requests.tag
753755
")).await.unwrap(),
756+
// Load pending benchmark requests, along with information whether their parent is
757+
// completed or not
758+
load_pending_benchmark_requests: conn.prepare(&format!("
759+
WITH pending AS (
760+
SELECT {BENCHMARK_REQUEST_COLUMNS}
761+
FROM benchmark_request AS req
762+
WHERE status IN ('{BENCHMARK_REQUEST_STATUS_ARTIFACTS_READY_STR}', '{BENCHMARK_REQUEST_STATUS_IN_PROGRESS_STR}')
763+
)
764+
SELECT (parent.status = '{BENCHMARK_REQUEST_STATUS_COMPLETED_STR}') AS parent_done, pending.*
765+
FROM pending
766+
LEFT JOIN benchmark_request as parent ON parent.tag = pending.parent_sha
767+
")).await.unwrap(),
754768
}),
755769
conn,
756770
}
@@ -809,7 +823,7 @@ where
809823
None => Date(Utc.with_ymd_and_hms(2001, 1, 1, 0, 0, 0).unwrap()),
810824
}
811825
},
812-
r#type: CommitType::from_str(&row.get::<_, String>(3)).unwrap()
826+
r#type: CommitType::from_str(&row.get::<_, String>(3)).unwrap(),
813827
},
814828
)
815829
})
@@ -1188,13 +1202,13 @@ where
11881202
Some(aid) => aid.get::<_, i32>(0) as u32,
11891203
None => {
11901204
self.conn()
1191-
.query_opt("insert into artifact (name, date, type) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING RETURNING id", &[
1192-
&info.name,
1193-
&info.date,
1194-
&info.kind,
1195-
])
1196-
.await
1197-
.unwrap();
1205+
.query_opt("insert into artifact (name, date, type) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING RETURNING id", &[
1206+
&info.name,
1207+
&info.date,
1208+
&info.kind,
1209+
])
1210+
.await
1211+
.unwrap();
11981212
self.conn()
11991213
.query_one("select id from artifact where name = $1", &[&info.name])
12001214
.await
@@ -1623,18 +1637,11 @@ where
16231637
.await
16241638
.context("Cannot load benchmark request index")?;
16251639

1626-
let mut all = HashSet::with_capacity(requests.len());
1627-
let mut completed = HashSet::with_capacity(requests.len());
1628-
for request in requests {
1629-
let tag = request.get::<_, String>(0);
1630-
let status = request.get::<_, &str>(1);
1631-
1632-
if status == BENCHMARK_REQUEST_STATUS_COMPLETED_STR {
1633-
completed.insert(tag.clone());
1634-
}
1635-
all.insert(tag);
1636-
}
1637-
Ok(BenchmarkRequestIndex { all, completed })
1640+
let all = requests
1641+
.into_iter()
1642+
.map(|row| row.get::<_, String>(0))
1643+
.collect();
1644+
Ok(BenchmarkRequestIndex { all })
16381645
}
16391646

16401647
async fn update_benchmark_request_status(
@@ -1705,25 +1712,30 @@ where
17051712
Ok(())
17061713
}
17071714

1708-
async fn load_pending_benchmark_requests(&self) -> anyhow::Result<Vec<BenchmarkRequest>> {
1709-
let query = format!(
1710-
r#"
1711-
SELECT {BENCHMARK_REQUEST_COLUMNS}
1712-
FROM benchmark_request
1713-
WHERE status IN('{BENCHMARK_REQUEST_STATUS_ARTIFACTS_READY_STR}', '{BENCHMARK_REQUEST_STATUS_IN_PROGRESS_STR}')"#
1714-
);
1715-
1715+
async fn load_pending_benchmark_requests(&self) -> anyhow::Result<PendingBenchmarkRequests> {
17161716
let rows = self
17171717
.conn()
1718-
.query(&query, &[])
1718+
.query(&self.statements().load_pending_benchmark_requests, &[])
17191719
.await
17201720
.context("Failed to get pending benchmark requests")?;
17211721

1722-
let requests = rows
1723-
.into_iter()
1724-
.map(|it| row_to_benchmark_request(&it, None))
1725-
.collect();
1726-
Ok(requests)
1722+
let mut completed_parent_tags = HashSet::new();
1723+
let mut requests = Vec::with_capacity(rows.len());
1724+
for row in rows {
1725+
let parent_done = row.get::<_, Option<bool>>(0);
1726+
let request = row_to_benchmark_request(&row, Some(1));
1727+
if let Some(true) = parent_done {
1728+
if let Some(parent) = request.parent_sha() {
1729+
completed_parent_tags.insert(parent.to_string());
1730+
}
1731+
}
1732+
requests.push(request);
1733+
}
1734+
1735+
Ok(PendingBenchmarkRequests {
1736+
requests,
1737+
completed_parent_tags,
1738+
})
17271739
}
17281740

17291741
async fn enqueue_benchmark_job(

0 commit comments

Comments
 (0)