Skip to content

Commit 10c1cf8

Browse files
authored
Merge pull request #1087 from rylev/self-profile-artifact-size-on-demand
Fetch self profile data from s3 on demand and parse artifact sizes
2 parents c8e7325 + 7ba0631 commit 10c1cf8

File tree

3 files changed

+161
-29
lines changed

3 files changed

+161
-29
lines changed

site/src/api.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ pub mod self_profile {
296296
pub struct SelfProfile {
297297
pub totals: QueryData,
298298
pub query_data: Vec<QueryData>,
299+
pub artifact_sizes: Option<Vec<ArtifactSize>>,
299300
}
300301

301302
#[derive(Serialize, Deserialize, Clone, Debug)]
@@ -313,10 +314,17 @@ pub mod self_profile {
313314
pub incremental_load_time: u64,
314315
}
315316

317+
#[derive(Serialize, Deserialize, Clone, Debug)]
318+
pub struct ArtifactSize {
319+
pub label: QueryLabel,
320+
pub bytes: u64,
321+
}
322+
316323
#[derive(Serialize, Debug, Clone)]
317324
pub struct SelfProfileDelta {
318325
pub totals: QueryDataDelta,
319326
pub query_data: Vec<QueryDataDelta>,
327+
pub artifact_sizes: Vec<ArtifactSizeDelta>,
320328
}
321329

322330
#[derive(Serialize, Clone, Debug)]
@@ -327,6 +335,11 @@ pub mod self_profile {
327335
// Nanoseconds
328336
pub incremental_load_time: i64,
329337
}
338+
339+
#[derive(Serialize, Clone, Debug)]
340+
pub struct ArtifactSizeDelta {
341+
pub bytes: u64,
342+
}
330343
}
331344

332345
pub mod github {

site/src/request_handlers/self_profile.rs

Lines changed: 106 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
use std::collections::HashSet;
1+
use std::collections::{BTreeMap, HashSet};
22
use std::io::Read;
33
use std::sync::Arc;
44
use std::time::{Duration, Instant};
55

66
use bytes::Buf;
7+
use database::ArtifactIdNumber;
78
use headers::{ContentType, Header};
89
use hyper::StatusCode;
910

11+
use crate::api::self_profile::ArtifactSizeDelta;
1012
use crate::api::{self_profile, self_profile_processed, self_profile_raw, ServerResult};
1113
use crate::db::ArtifactId;
1214
use crate::load::SiteCtxt;
@@ -142,6 +144,7 @@ pub async fn handle_self_profile_processed_download(
142144
fn get_self_profile_data(
143145
cpu_clock: Option<f64>,
144146
self_profile: Option<crate::selector::SelfProfileData>,
147+
raw_data: Vec<u8>,
145148
) -> ServerResult<self_profile::SelfProfile> {
146149
let profile = self_profile
147150
.as_ref()
@@ -178,6 +181,7 @@ fn get_self_profile_data(
178181
.map(|qd| qd.incremental_load_time)
179182
.sum(),
180183
};
184+
let artifact_sizes = raw_mmprof_data_to_artifact_sizes(raw_data).ok();
181185
let profile = self_profile::SelfProfile {
182186
query_data: profile
183187
.query_data
@@ -195,6 +199,7 @@ fn get_self_profile_data(
195199
})
196200
.collect(),
197201
totals,
202+
artifact_sizes,
198203
};
199204

200205
Ok(profile)
@@ -239,11 +244,11 @@ fn add_uninvoked_base_profile_queries(
239244
fn get_self_profile_delta(
240245
profile: &self_profile::SelfProfile,
241246
base_profile: &Option<self_profile::SelfProfile>,
247+
raw_data: Vec<u8>,
248+
base_raw_data: Option<Vec<u8>>,
242249
) -> Option<self_profile::SelfProfileDelta> {
243-
let base_profile = match base_profile.as_ref() {
244-
Some(bp) => bp,
245-
None => return None,
246-
};
250+
let base_profile = base_profile.as_ref()?;
251+
let base_raw_data = base_raw_data?;
247252

248253
let totals = self_profile::QueryDataDelta {
249254
self_time: profile.totals.self_time as i64 - base_profile.totals.self_time as i64,
@@ -283,7 +288,21 @@ fn get_self_profile_delta(
283288
}
284289
}
285290

286-
Some(self_profile::SelfProfileDelta { totals, query_data })
291+
let first = raw_mmprof_data_to_artifact_sizes(raw_data).unwrap_or_else(|_| Vec::new());
292+
let base = raw_mmprof_data_to_artifact_sizes(base_raw_data).unwrap_or_else(|_| Vec::new());
293+
let artifact_sizes = first
294+
.into_iter()
295+
.zip(base.into_iter())
296+
.map(|(a1, a2)| ArtifactSizeDelta {
297+
bytes: a1.bytes - a2.bytes,
298+
})
299+
.collect();
300+
301+
Some(self_profile::SelfProfileDelta {
302+
totals,
303+
query_data,
304+
artifact_sizes,
305+
})
287306
}
288307

289308
fn sort_self_profile(
@@ -489,10 +508,10 @@ pub async fn handle_self_profile_raw(
489508
) -> ServerResult<self_profile_raw::Response> {
490509
log::info!("handle_self_profile_raw({:?})", body);
491510
let mut it = body.benchmark.rsplitn(2, '-');
492-
let bench_ty = it.next().ok_or(format!("no benchmark type"))?;
511+
let profile = it.next().ok_or(format!("no benchmark type"))?;
493512
let bench_name = it.next().ok_or(format!("no benchmark name"))?;
494513

495-
let cache = body
514+
let scenario = body
496515
.run_name
497516
.parse::<database::Scenario>()
498517
.map_err(|e| format!("invalid run name: {:?}", e))?;
@@ -506,7 +525,7 @@ pub async fn handle_self_profile_raw(
506525
date: database::Date::empty(),
507526
}),
508527
bench_name,
509-
bench_ty,
528+
profile,
510529
&body.run_name,
511530
)
512531
.await;
@@ -526,20 +545,20 @@ pub async fn handle_self_profile_raw(
526545
_ => first_cid,
527546
};
528547

548+
let cids = aids_and_cids
549+
.into_iter()
550+
.map(|(_, cid)| cid)
551+
.collect::<Vec<_>>();
552+
529553
let url_prefix = format!(
530554
"https://perf-data.rust-lang.org/self-profile/{}/{}/{}/{}/self-profile-{}",
531555
aid.0,
532556
bench_name,
533-
bench_ty,
534-
cache.to_id(),
557+
profile,
558+
scenario.to_id(),
535559
cid,
536560
);
537561

538-
let cids = aids_and_cids
539-
.into_iter()
540-
.map(|(_, cid)| cid)
541-
.collect::<Vec<_>>();
542-
543562
return match fetch(&cids, cid, format!("{}.mm_profdata.sz", url_prefix)).await {
544563
Ok(fetched) => Ok(fetched),
545564
Err(new_error) => Err(format!("mm_profdata download failed: {:?}", new_error,)),
@@ -570,6 +589,21 @@ pub async fn handle_self_profile_raw(
570589
}
571590
}
572591

592+
pub async fn fetch_raw_self_profile_data(
593+
aid: ArtifactIdNumber,
594+
benchmark: &str,
595+
profile: &str,
596+
scenario: &str,
597+
cid: i32,
598+
) -> Result<Vec<u8>, Response> {
599+
let url = format!(
600+
"https://perf-data.rust-lang.org/self-profile/{}/{}/{}/{}/self-profile-{}.mm_profdata.sz",
601+
aid.0, benchmark, profile, scenario, cid,
602+
);
603+
604+
get_self_profile_raw_data(&url).await
605+
}
606+
573607
pub async fn handle_self_profile(
574608
body: self_profile::Request,
575609
ctxt: &SiteCtxt,
@@ -653,30 +687,76 @@ pub async fn handle_self_profile(
653687
.await?;
654688
assert_eq!(cpu_responses.len(), 1, "all selectors are exact");
655689
let mut cpu_response = cpu_responses.remove(0).series;
656-
690+
let mut raw_self_profile_data = Vec::new();
691+
let conn = ctxt.conn().await;
692+
for commit in commits.iter() {
693+
let aids_and_cids = conn
694+
.list_self_profile(commit.clone(), bench_name, profile, &body.run_name)
695+
.await;
696+
if let Some((aid, cid)) = aids_and_cids.first() {
697+
match fetch_raw_self_profile_data(*aid, bench_name, profile, &body.run_name, *cid).await
698+
{
699+
Ok(d) => raw_self_profile_data.push(d),
700+
Err(_) => return Err(format!("could not fetch raw profile data")),
701+
};
702+
}
703+
}
704+
let raw_data = raw_self_profile_data.remove(0);
657705
let mut profile = get_self_profile_data(
658706
cpu_response.next().unwrap().1,
659707
sp_response.next().unwrap().1,
708+
raw_data.clone(),
660709
)
661710
.map_err(|e| format!("{}: {}", body.commit, e))?;
662-
let base_profile = if body.base_commit.is_some() {
663-
Some(
664-
get_self_profile_data(
665-
cpu_response.next().unwrap().1,
666-
sp_response.next().unwrap().1,
667-
)
668-
.map_err(|e| format!("{}: {}", body.base_commit.as_ref().unwrap(), e))?,
711+
let (base_profile, base_raw_data) = if body.base_commit.is_some() {
712+
let base_raw_data = raw_self_profile_data.remove(0);
713+
let profile = get_self_profile_data(
714+
cpu_response.next().unwrap().1,
715+
sp_response.next().unwrap().1,
716+
base_raw_data.clone(),
669717
)
718+
.map_err(|e| format!("{}: {}", body.base_commit.as_ref().unwrap(), e))?;
719+
(Some(profile), Some(base_raw_data))
670720
} else {
671-
None
721+
(None, None)
672722
};
673723

674724
add_uninvoked_base_profile_queries(&mut profile, &base_profile);
675-
let mut base_profile_delta = get_self_profile_delta(&profile, &base_profile);
725+
let mut base_profile_delta =
726+
get_self_profile_delta(&profile, &base_profile, raw_data, base_raw_data);
676727
sort_self_profile(&mut profile, &mut base_profile_delta, sort_idx);
677728

678729
Ok(self_profile::Response {
679730
base_profile_delta,
680731
profile,
681732
})
682733
}
734+
735+
fn raw_mmprof_data_to_artifact_sizes(
736+
data: Vec<u8>,
737+
) -> anyhow::Result<Vec<self_profile::ArtifactSize>> {
738+
let profiling_data = analyzeme::ProfilingData::from_paged_buffer(data, None)
739+
.map_err(|_| anyhow::Error::msg("could not parse profiling data"))?;
740+
741+
let mut artifact_sizes: BTreeMap<_, u64> = Default::default();
742+
743+
for event in profiling_data.iter_full() {
744+
// TODO: Use constant from measureme::rustc
745+
if event.event_kind == "ArtifactSize" {
746+
if !event.payload.is_integer() {
747+
anyhow::bail!("Found ArtifactSize payload that is not an integer")
748+
}
749+
750+
let bytes = event.payload.integer().unwrap();
751+
*artifact_sizes.entry(event.label).or_default() += bytes;
752+
}
753+
}
754+
755+
Ok(artifact_sizes
756+
.iter()
757+
.map(|(k, v)| self_profile::ArtifactSize {
758+
label: k[..].into(),
759+
bytes: *v,
760+
})
761+
.collect())
762+
}

site/static/detailed-query.html

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@
5959
border-radius: 3px;
6060
user-select: all;
6161
}
62+
63+
#artifact-table th {
64+
text-align: center;
65+
}
66+
67+
#artifact-table td {
68+
padding: 0 0 0 20px;
69+
}
6270
</style>
6371
</head>
6472

@@ -70,6 +78,18 @@
7078
<div id="content">
7179
<h3 id="title"></h3>
7280
<div id="raw-urls"></div>
81+
<h4>Artifact Size</h4>
82+
<table id="artifact-table">
83+
<thead>
84+
<tr id="table-header">
85+
<th>Artifact</th>
86+
<th>Size</th>
87+
<th>Size delta</th>
88+
</tr>
89+
</thead>
90+
<tbody id="artifact-body">
91+
</tbody>
92+
</table>
7393
<p>'Time (%)' is the percentage of the cpu-clock time spent on this query (we do not use
7494
wall-time as we want to account for parallelism).</p>
7595
<p>Executions do not include cached executions.</p>
@@ -152,7 +172,7 @@ <h3 id="title"></h3>
152172
let processed_url = (commit, bench, run, ty) => {
153173
return `/perf/processed-self-profile?commit=${commit}&benchmark=${bench}&run_name=${run}&type=${ty}`;
154174
};
155-
let processed_link = (commit, {benchmark, run_name}, ty) => {
175+
let processed_link = (commit, { benchmark, run_name }, ty) => {
156176
let url = processed_url(commit, benchmark, run_name, ty);
157177
return `<a href="${url}">${ty}</a>`;
158178
};
@@ -313,7 +333,7 @@ <h3 id="title"></h3>
313333
fmt_delta(
314334
to_seconds(cur.incremental_load_time),
315335
to_seconds(delta.incremental_load_time),
316-
false,
336+
false,
317337
),
318338
true).classList.add("incr");
319339
} else {
@@ -322,6 +342,25 @@ <h3 id="title"></h3>
322342
table.appendChild(row);
323343
idx += 1;
324344
}
345+
346+
let artifactTable = document.getElementById("artifact-body");
347+
function td(row, content) {
348+
let td = document.createElement("td");
349+
td.innerHTML = content;
350+
row.appendChild(td);
351+
return td;
352+
}
353+
for (let [idx, element] of data.profile.artifact_sizes.entries()) {
354+
let row = document.createElement("tr");
355+
const label = td(row, element.label);
356+
label.style.textAlign = "center";
357+
td(row, element.bytes);
358+
if (data.base_profile_delta && data.base_profile_delta.artifact_sizes[idx]) {
359+
td(row, data.base_profile_delta.artifact_sizes[idx].bytes);
360+
}
361+
artifactTable.appendChild(row);
362+
idx += 1;
363+
}
325364
}
326365

327366
function to_object(element) {
@@ -368,4 +407,4 @@ <h3 id="title"></h3>
368407
</script>
369408
</body>
370409

371-
</html>
410+
</html>

0 commit comments

Comments
 (0)