Skip to content

Commit 779deae

Browse files
committed
Add a cache to self-profile downloads
1 parent 41f480b commit 779deae

File tree

5 files changed

+101
-5
lines changed

5 files changed

+101
-5
lines changed

Cargo.lock

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ uuid = { version = "1.3.0", features = ["v4"] }
4848
tera = "1.18"
4949
rust-embed = { version = "6.6.0", features = ["include-exclude", "interpolate-folder-path"] }
5050
humansize = "2"
51+
lru = "0.12.0"
5152

5253
[target.'cfg(unix)'.dependencies]
5354
jemallocator = "0.5"

site/src/load.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ use arc_swap::{ArcSwap, Guard};
88
use chrono::{Duration, Utc};
99
use lazy_static::lazy_static;
1010
use log::error;
11+
use parking_lot::Mutex;
1112
use regex::Regex;
1213
use serde::{Deserialize, Serialize};
1314

1415
use crate::db;
16+
use crate::self_profile::SelfProfileCache;
1517
use collector::compile::benchmark::category::Category;
1618
use collector::{Bound, MasterCommit};
1719
use database::Pool;
@@ -116,6 +118,9 @@ impl MasterCommitCache {
116118
}
117119
}
118120

121+
// How many analyzed self profiles should be stored in memory
122+
const CACHED_SELF_PROFILE_COUNT: usize = 1000;
123+
119124
/// Site context object that contains global data
120125
pub struct SiteCtxt {
121126
/// Site configuration
@@ -126,6 +131,8 @@ pub struct SiteCtxt {
126131
pub index: ArcSwap<crate::db::Index>,
127132
/// Cached master-branch Rust commits
128133
pub master_commits: Arc<ArcSwap<MasterCommitCache>>, // outer Arc enables mutation in background task
134+
/// Cache for self profile data
135+
pub self_profile_cache: Mutex<SelfProfileCache>,
129136
/// Database connection pool
130137
pub pool: Pool,
131138
}
@@ -174,6 +181,7 @@ impl SiteCtxt {
174181
master_commits: Arc::new(ArcSwap::new(Arc::new(master_commits))),
175182
pool,
176183
landing_page: ArcSwap::new(Arc::new(None)),
184+
self_profile_cache: Mutex::new(SelfProfileCache::new(CACHED_SELF_PROFILE_COUNT)),
177185
})
178186
}
179187

site/src/request_handlers/self_profile.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
use std::collections::HashSet;
22
use std::io::Read;
3-
use std::num::NonZeroUsize;
43
use std::sync::Arc;
54
use std::time::Instant;
65

76
use bytes::Buf;
87
use database::CommitType;
98
use headers::{ContentType, Header};
109
use hyper::StatusCode;
11-
use lru::LruCache;
1210

1311
use crate::api::self_profile::ArtifactSizeDelta;
1412
use crate::api::{self_profile, self_profile_processed, self_profile_raw, ServerResult};
@@ -17,7 +15,8 @@ use crate::db::ArtifactId;
1715
use crate::load::SiteCtxt;
1816
use crate::selector::{self};
1917
use crate::self_profile::{
20-
download_and_analyze_self_profile, get_self_profile_raw_data, SelfProfileWithAnalysis,
18+
download_and_analyze_self_profile, get_self_profile_raw_data, SelfProfileKey,
19+
SelfProfileWithAnalysis,
2120
};
2221
use crate::server::{Response, ResponseHeaders};
2322

@@ -535,7 +534,35 @@ pub async fn handle_self_profile(
535534
assert_eq!(cpu_responses.len(), 1, "all selectors are exact");
536535
let mut cpu_response = cpu_responses.remove(0).series;
537536

538-
let mut self_profile = download_and_analyze_self_profile(
537+
async fn get_from_cache(
538+
ctxt: &SiteCtxt,
539+
aid: ArtifactId,
540+
benchmark: &str,
541+
profile: &str,
542+
scenario: database::Scenario,
543+
metric: Option<f64>,
544+
) -> ServerResult<SelfProfileWithAnalysis> {
545+
let key = SelfProfileKey {
546+
aid: aid.clone(),
547+
benchmark: benchmark.to_string(),
548+
profile: profile.to_string(),
549+
scenario,
550+
};
551+
let cache_result = ctxt.self_profile_cache.lock().get(&key);
552+
match cache_result {
553+
Some(res) => Ok(res),
554+
None => {
555+
let profile = download_and_analyze_self_profile(
556+
ctxt, aid, benchmark, profile, scenario, metric,
557+
)
558+
.await?;
559+
ctxt.self_profile_cache.lock().insert(key, profile.clone());
560+
Ok(profile)
561+
}
562+
}
563+
}
564+
565+
let mut self_profile = get_from_cache(
539566
ctxt,
540567
commits.get(0).unwrap().clone(),
541568
bench_name,
@@ -546,7 +573,7 @@ pub async fn handle_self_profile(
546573
.await?;
547574
let base_self_profile = match commits.get(1) {
548575
Some(aid) => Some(
549-
download_and_analyze_self_profile(
576+
get_from_cache(
550577
ctxt,
551578
aid.clone(),
552579
bench_name,

site/src/self_profile.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use crate::load::SiteCtxt;
77
use anyhow::Context;
88
use bytes::Buf;
99
use database::ArtifactId;
10+
use lru::LruCache;
11+
use std::num::NonZeroUsize;
1012
use std::time::Duration;
1113
use std::{collections::HashMap, io::Read, time::Instant};
1214

@@ -122,6 +124,38 @@ pub(crate) async fn get_self_profile_raw_data(url: &str) -> anyhow::Result<Vec<u
122124
extract(&compressed)
123125
}
124126

127+
#[derive(Hash, Eq, PartialEq)]
128+
pub struct SelfProfileKey {
129+
pub aid: ArtifactId,
130+
pub benchmark: String,
131+
pub profile: String,
132+
pub scenario: database::Scenario,
133+
}
134+
135+
/// Stores a cache of N most recently used self profiles.
136+
/// The profiles are downloaded from S3 and analysed on each request to the detailed compare result
137+
/// page, but the post-processed results aren't very large in memory (~50 KiB), so it makes sense
138+
/// to cache them.
139+
pub struct SelfProfileCache {
140+
profiles: LruCache<SelfProfileKey, SelfProfileWithAnalysis>,
141+
}
142+
143+
impl SelfProfileCache {
144+
pub fn new(cache_size: usize) -> Self {
145+
Self {
146+
profiles: LruCache::new(NonZeroUsize::new(cache_size).unwrap()),
147+
}
148+
}
149+
150+
pub fn get(&mut self, key: &SelfProfileKey) -> Option<SelfProfileWithAnalysis> {
151+
self.profiles.get(key).cloned()
152+
}
153+
154+
pub fn insert(&mut self, key: SelfProfileKey, profile: SelfProfileWithAnalysis) {
155+
self.profiles.put(key, profile);
156+
}
157+
}
158+
125159
#[derive(Clone)]
126160
pub struct SelfProfileWithAnalysis {
127161
pub profile: self_profile::SelfProfile,

0 commit comments

Comments
 (0)