Skip to content

Commit 61466f7

Browse files
authored
Merge pull request #1027 from tgnottingham/show-uninvoked-self-profile-queries
Show data for queries present only in one profile in comparison
2 parents 44e8c23 + a69edea commit 61466f7

File tree

3 files changed

+118
-70
lines changed

3 files changed

+118
-70
lines changed

site/src/api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ pub mod self_profile {
311311
#[derive(Serialize, Debug, Clone)]
312312
pub struct SelfProfileDelta {
313313
pub totals: QueryDataDelta,
314-
pub query_data: Vec<Option<QueryDataDelta>>,
314+
pub query_data: Vec<QueryDataDelta>,
315315
}
316316

317317
#[derive(Serialize, Clone, Debug)]

site/src/request_handlers/self_profile.rs

Lines changed: 91 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22
use std::io::Read;
33
use std::sync::Arc;
44
use std::time::{Duration, Instant};
@@ -190,6 +190,42 @@ fn get_self_profile_data(
190190
Ok(profile)
191191
}
192192

193+
// Add query data entries to `profile` for any queries in `base_profile` which are not present in
194+
// `profile` (i.e. queries not invoked during the compilation that generated `profile`). This is
195+
// bit of a hack to enable showing rows for these queries in the table on the self-profile page.
196+
fn add_uninvoked_base_profile_queries(
197+
profile: &mut self_profile::SelfProfile,
198+
base_profile: &Option<self_profile::SelfProfile>,
199+
) {
200+
let base_profile = match base_profile.as_ref() {
201+
Some(bp) => bp,
202+
None => return,
203+
};
204+
205+
let profile_queries: HashSet<_> = profile
206+
.query_data
207+
.iter()
208+
.map(|qd| qd.label.as_str())
209+
.collect();
210+
211+
for qd in &base_profile.query_data {
212+
if !profile_queries.contains(qd.label.as_str()) {
213+
let uninvoked_query_data = self_profile::QueryData {
214+
label: qd.label,
215+
self_time: 0,
216+
percent_total_time: 0.0,
217+
number_of_cache_misses: 0,
218+
number_of_cache_hits: 0,
219+
invocation_count: 0,
220+
blocked_time: 0,
221+
incremental_load_time: 0,
222+
};
223+
224+
profile.query_data.push(uninvoked_query_data);
225+
}
226+
}
227+
}
228+
193229
fn get_self_profile_delta(
194230
profile: &self_profile::SelfProfile,
195231
base_profile: &Option<self_profile::SelfProfile>,
@@ -223,10 +259,16 @@ fn get_self_profile_delta(
223259
- base_qd.incremental_load_time as i64,
224260
};
225261

226-
query_data.push(Some(delta));
262+
query_data.push(delta);
227263
}
228264
None => {
229-
query_data.push(None);
265+
let delta = self_profile::QueryDataDelta {
266+
self_time: qd.self_time as i64,
267+
invocation_count: qd.invocation_count as i32,
268+
incremental_load_time: qd.incremental_load_time as i64,
269+
};
270+
271+
query_data.push(delta);
230272
}
231273
}
232274
}
@@ -239,60 +281,58 @@ fn sort_self_profile(
239281
base_profile_delta: &mut Option<self_profile::SelfProfileDelta>,
240282
sort_idx: i32,
241283
) {
242-
let queries = std::mem::take(&mut profile.query_data);
243-
244-
let deltas = match base_profile_delta.as_mut() {
245-
Some(bpd) => std::mem::take(&mut bpd.query_data),
246-
None => vec![None; queries.len()],
247-
};
248-
249-
let mut query_data: Vec<_> = queries.into_iter().zip(deltas).collect();
250-
251-
loop {
252-
match sort_idx.abs() {
253-
1 => query_data.sort_by_key(|qd| qd.0.label.clone()),
254-
2 => query_data.sort_by_key(|qd| qd.0.self_time),
255-
3 => query_data.sort_by_key(|qd| qd.0.number_of_cache_misses),
256-
4 => query_data.sort_by_key(|qd| qd.0.number_of_cache_hits),
257-
5 => query_data.sort_by_key(|qd| qd.0.invocation_count),
258-
6 => query_data.sort_by_key(|qd| qd.0.blocked_time),
259-
7 => query_data.sort_by_key(|qd| qd.0.incremental_load_time),
260-
9 => query_data.sort_by_key(|qd| {
261-
// convert to displayed percentage
262-
((qd.0.number_of_cache_hits as f64 / qd.0.invocation_count as f64) * 10_000.0)
263-
as u64
264-
}),
265-
10 => query_data.sort_by(|a, b| {
266-
a.0.percent_total_time
267-
.partial_cmp(&b.0.percent_total_time)
268-
.unwrap()
269-
}),
270-
11 if base_profile_delta.is_some() => {
271-
query_data.sort_by_key(|qd| qd.1.as_ref().map(|delta| delta.self_time));
284+
let qd = &mut profile.query_data;
285+
let qd_deltas = base_profile_delta.as_mut().map(|bpd| &mut bpd.query_data);
286+
let mut indices: Vec<_> = (0..qd.len()).collect();
287+
288+
match sort_idx.abs() {
289+
1 => indices.sort_by_key(|&i| qd[i].label.clone()),
290+
2 => indices.sort_by_key(|&i| qd[i].self_time),
291+
3 => indices.sort_by_key(|&i| qd[i].number_of_cache_misses),
292+
4 => indices.sort_by_key(|&i| qd[i].number_of_cache_hits),
293+
5 => indices.sort_by_key(|&i| qd[i].invocation_count),
294+
6 => indices.sort_by_key(|&i| qd[i].blocked_time),
295+
7 => indices.sort_by_key(|&i| qd[i].incremental_load_time),
296+
9 => indices.sort_by_key(|&i| {
297+
// convert to displayed percentage
298+
((qd[i].number_of_cache_hits as f64 / qd[i].invocation_count as f64) * 10_000.0) as u64
299+
}),
300+
10 => indices.sort_by(|&a, &b| {
301+
qd[a]
302+
.percent_total_time
303+
.partial_cmp(&qd[b].percent_total_time)
304+
.unwrap()
305+
}),
306+
11 => {
307+
if let Some(ref deltas) = qd_deltas {
308+
indices.sort_by_key(|&i| deltas[i].self_time);
272309
}
273-
12 if base_profile_delta.is_some() => {
274-
query_data.sort_by_key(|qd| qd.1.as_ref().map(|delta| delta.invocation_count));
275-
}
276-
13 if base_profile_delta.is_some() => {
277-
query_data.sort_by_key(|qd| qd.1.as_ref().map(|delta| delta.incremental_load_time));
310+
}
311+
12 => {
312+
if let Some(ref deltas) = qd_deltas {
313+
indices.sort_by_key(|&i| deltas[i].invocation_count);
278314
}
279-
_ => break,
280315
}
281-
282-
// Only apply this if at least one of the conditions above was met
283-
if sort_idx < 0 {
284-
query_data.reverse();
316+
13 => {
317+
if let Some(ref deltas) = qd_deltas {
318+
indices.sort_by_key(|&i| deltas[i].incremental_load_time);
319+
}
285320
}
286-
287-
break;
321+
_ => return,
288322
}
289323

290-
let (queries, deltas) = query_data.into_iter().unzip();
291-
292-
profile.query_data = queries;
324+
profile.query_data = if sort_idx < 0 {
325+
indices.iter().map(|&i| qd[i].clone()).rev().collect()
326+
} else {
327+
indices.iter().map(|&i| qd[i].clone()).collect()
328+
};
293329

294-
if let Some(bpd) = base_profile_delta {
295-
bpd.query_data = deltas;
330+
if let Some(deltas) = qd_deltas {
331+
base_profile_delta.as_mut().unwrap().query_data = if sort_idx < 0 {
332+
indices.iter().map(|&i| deltas[i].clone()).rev().collect()
333+
} else {
334+
indices.iter().map(|&i| deltas[i].clone()).collect()
335+
};
296336
}
297337
}
298338

@@ -681,6 +721,7 @@ pub async fn handle_self_profile(
681721
None
682722
};
683723

724+
add_uninvoked_base_profile_queries(&mut profile, &base_profile);
684725
let mut base_profile_delta = get_self_profile_delta(&profile, &base_profile);
685726
sort_self_profile(&mut profile, &mut base_profile_delta, sort_idx);
686727

site/static/detailed-query.html

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,31 +91,37 @@ <h3 id="title"></h3>
9191
return time / 1000000000;
9292
}
9393

94-
function fmt_delta(to, delta) {
94+
function fmt_delta(to, delta, is_integral_delta) {
9595
let from = to - delta;
9696
let pct = (to - from) / from * 100;
9797
if (from == to) {
9898
pct = 0;
9999
}
100+
let classes;
101+
if (pct > 1) {
102+
classes = "positive";
103+
} else if (pct < -1) {
104+
classes = "negative";
105+
} else {
106+
classes = "neutral";
107+
}
108+
// some arbitrary "small" value
109+
// ignore this because it's not too interesting likely
110+
if (Math.abs(delta) <= 0.05) {
111+
classes = "neutral";
112+
}
113+
let text;
114+
if (is_integral_delta) {
115+
text = delta.toString();
116+
} else {
117+
text = delta.toFixed(3);
118+
}
100119
if (pct != Infinity && pct != -Infinity) {
101-
let classes;
102-
if (pct > 1) {
103-
classes = "positive";
104-
} else if (pct < -1) {
105-
classes = "negative";
106-
} else {
107-
classes = "neutral";
108-
}
109-
// some arbitrary "small" value
110-
// ignore this because it's not too interesting likely
111-
if (Math.abs(delta) <= 0.05) {
112-
classes = "neutral";
113-
}
114-
let text = delta.toFixed(3) + `(${pct.toFixed(1)}%)`.padStart(10, ' ');
115-
return `<span class="${classes}" title="${from.toFixed(3)} to ${to.toFixed(3)}${delta.toFixed(3)}">${text}</span>`;
120+
text += `(${pct.toFixed(1)}%)`.padStart(10, ' ');
116121
} else {
117-
return `<span title="error pct=${pct}" style="color: orange;">-</span>`;
122+
text += `-`.padStart(10, ' ');
118123
}
124+
return `<span class="${classes}" title="${from.toFixed(3)} to ${to.toFixed(3)}${delta.toFixed(3)}">${text}</span>`;
119125
}
120126

121127
function populate_data(data, state) {
@@ -259,13 +265,13 @@ <h3 id="title"></h3>
259265
}
260266
td(row, to_seconds(cur.self_time).toFixed(3));
261267
if (delta) {
262-
td(row, fmt_delta(to_seconds(cur.self_time), to_seconds(delta.self_time)), true);
268+
td(row, fmt_delta(to_seconds(cur.self_time), to_seconds(delta.self_time), false), true);
263269
} else {
264270
td(row, "-", true);
265271
}
266272
td(row, cur.invocation_count);
267273
if (delta) {
268-
td(row, fmt_delta(cur.invocation_count, delta.invocation_count), true);
274+
td(row, fmt_delta(cur.invocation_count, delta.invocation_count, true), true);
269275
} else {
270276
td(row, "-", true);
271277
}
@@ -276,6 +282,7 @@ <h3 id="title"></h3>
276282
fmt_delta(
277283
to_seconds(cur.incremental_load_time),
278284
to_seconds(delta.incremental_load_time),
285+
false,
279286
),
280287
true).classList.add("incr");
281288
} else {

0 commit comments

Comments
 (0)