Skip to content

Commit 8d9deff

Browse files
committed
move compile detail graph to component
1 parent afcaaf6 commit 8d9deff

File tree

2 files changed

+273
-245
lines changed

2 files changed

+273
-245
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
<script setup lang="ts">
2+
import {computed, onMounted, capitalize, Ref, ref} from "vue";
3+
import {
4+
COMPILE_DETAIL_GRAPHS_RESOLVER,
5+
CompileDetailGraphs,
6+
CompileDetailGraphsSelector,
7+
} from "./detail-resolver";
8+
import {GraphData, GraphKind, GraphsSelector} from "../../../../graph/data";
9+
import {CompileTestCase} from "../common";
10+
import {GraphRenderOpts, renderPlots} from "../../../../graph/render";
11+
import uPlot from "uplot";
12+
import {
13+
daysBetweenDates,
14+
formatDate,
15+
getFutureDate,
16+
getPastDate,
17+
} from "./utils";
18+
import {ArtifactDescription} from "../../types";
19+
20+
const props = defineProps<{
21+
testCase: CompileTestCase;
22+
metric: string;
23+
artifact: ArtifactDescription;
24+
baseArtifact: ArtifactDescription;
25+
}>();
26+
27+
// How many days are shown in the graph
28+
const DAY_RANGE = 30;
29+
30+
function createGraphsSelector(): CompileDetailGraphsSelector {
31+
const {start, end} = graphRange.value;
32+
33+
return {
34+
benchmark: props.testCase.benchmark,
35+
profile: props.testCase.profile,
36+
scenario: props.testCase.scenario,
37+
stat: props.metric,
38+
start,
39+
end,
40+
kinds: ["percentrelative", "percentfromfirst"] as GraphKind[],
41+
};
42+
}
43+
44+
// Render both relative and absolute graphs
45+
async function renderGraphs(detail: CompileDetailGraphs) {
46+
const selector = createGraphsSelector();
47+
const date = graphRange.value.date;
48+
if (detail.commits.length === 0) {
49+
return;
50+
}
51+
52+
function buildGraph(
53+
index: number,
54+
kind: GraphKind
55+
): [GraphData, GraphsSelector] {
56+
const data = {
57+
commits: detail.commits,
58+
benchmarks: {
59+
[selector.benchmark]: {
60+
// The server returns profiles capitalized, so we need to match that
61+
// here, so that the graph code can find the expected profile.
62+
[capitalize(selector.profile)]: {
63+
[selector.scenario]: detail.graphs[index],
64+
},
65+
},
66+
},
67+
};
68+
const graphSelector = {
69+
benchmark: selector.benchmark,
70+
profile: selector.profile,
71+
scenario: selector.scenario,
72+
stat: selector.stat,
73+
start: selector.start,
74+
end: selector.end,
75+
kind,
76+
};
77+
78+
return [data, graphSelector];
79+
}
80+
81+
const [percentRelativeData, percentRelativeSelector] = buildGraph(
82+
0,
83+
"percentrelative"
84+
);
85+
const [percentFromFirstData, percentFromFirstSelector] = buildGraph(
86+
1,
87+
"percentfromfirst"
88+
);
89+
90+
// We want to be able to see noise "blips" vs. a previous artifact.
91+
// The "percent relative from previous commit" graph should be the best to
92+
// see these kinds of changes.
93+
renderGraph(
94+
percentRelativeData,
95+
percentRelativeSelector,
96+
date,
97+
relativeToPreviousChartElement
98+
);
99+
// We also want to see whether a change maintained its value or whether it was noise and has since
100+
// returned to steady state. Here, an absolute graph ("raw") would be best, however small changes
101+
// are hard to observe in it. Therefore, we use "percent from first commit" graph instead, which
102+
// is essentialy a "zoomed-in" version of the raw graph.
103+
renderGraph(
104+
percentFromFirstData,
105+
percentFromFirstSelector,
106+
date,
107+
relativeToFirstChartElement
108+
);
109+
}
110+
111+
async function renderGraph(
112+
graphData: GraphData,
113+
selector: GraphsSelector,
114+
date: Date | null,
115+
chartRef: Ref<HTMLElement | null>
116+
) {
117+
const opts: GraphRenderOpts = {
118+
width: Math.min(window.innerWidth - 40, 465),
119+
renderTitle: false,
120+
};
121+
if (date !== null) {
122+
drawCurrentDate(opts, date);
123+
}
124+
renderPlots(graphData, selector, chartRef.value, opts);
125+
}
126+
127+
async function loadGraphs(): Promise<CompileDetailGraphs> {
128+
return await COMPILE_DETAIL_GRAPHS_RESOLVER.load(createGraphsSelector());
129+
}
130+
131+
function getGraphTitle() {
132+
const {start, end, date} = graphRange.value;
133+
const days = date
134+
? daysBetweenDates(new Date(start), new Date(end))
135+
: DAY_RANGE;
136+
const msg = `${days} day history`;
137+
if (date !== null) {
138+
return `${msg} (${start} → ${end})`;
139+
} else {
140+
return `${msg} (up to benchmarked commit)`;
141+
}
142+
}
143+
144+
type GraphRange = {
145+
start: string;
146+
end: string;
147+
date: Date | null;
148+
};
149+
150+
/**
151+
* Hook into the uPlot drawing machinery to draw a rectangle from the `date` to
152+
* the end of the plot, representing the region that is the date's future.
153+
*/
154+
function drawCurrentDate(opts: GraphRenderOpts, date: Date) {
155+
opts.hooks = {
156+
drawSeries: (u: uPlot) => {
157+
let ctx = u.ctx;
158+
const x = u.valToPos(date.getTime() / 1000, "x", true);
159+
160+
// Draw a translucent rectangle representing the region that is more
161+
// recent than `date`.
162+
ctx.save();
163+
ctx.fillStyle = "rgba(0, 0, 0, 0.07)";
164+
ctx.rect(x, u.bbox.top, u.bbox.width - x + u.bbox.left, u.bbox.height);
165+
ctx.fill();
166+
ctx.restore();
167+
},
168+
};
169+
}
170+
171+
/**
172+
* Calculates the start and end range for a history graph for this benchmark
173+
* and artifact.
174+
*/
175+
function getGraphRange(
176+
artifact: ArtifactDescription,
177+
baseArtifact: ArtifactDescription
178+
): GraphRange {
179+
// If this is a try commit, we don't know its future, so always we just display
180+
// the last `DAY_RANGE` days.
181+
if (artifact.type === "try") {
182+
const date = new Date(artifact.date);
183+
return {
184+
start: formatDate(getPastDate(date, DAY_RANGE)),
185+
end: artifact.commit,
186+
date: null,
187+
};
188+
} else {
189+
let [start_date, end_date] = [baseArtifact, artifact].map(
190+
(c) => new Date(c.date)
191+
);
192+
// If this is a master commit, we attempt to display more than the full history for commit
193+
// ranges. If the commit range is not larger than the `dayRange`, the display will likely be
194+
// "centered" around the commit date.
195+
196+
// Calculate the end of the range, which is the earlier date between
197+
// current date and the commit date + half of the amount of days we
198+
// want to show.
199+
let centered_end = getFutureDate(end_date, DAY_RANGE / 2);
200+
const today = new Date().setUTCHours(0, 0, 0, 0);
201+
if (centered_end.getTime() > today) {
202+
centered_end = new Date(today);
203+
}
204+
const end = formatDate(centered_end);
205+
206+
// Calculate the start of the range, which is the earlier date between
207+
// the base artifact date and the calculated end date - the amount of days
208+
// we want to show.
209+
const centered_start = getPastDate(centered_end, DAY_RANGE);
210+
const start = formatDate(
211+
start_date < centered_start ? start_date : centered_start
212+
);
213+
214+
return {
215+
start,
216+
end,
217+
date: end_date,
218+
};
219+
}
220+
}
221+
222+
const relativeToPreviousChartElement: Ref<HTMLElement | null> = ref(null);
223+
const relativeToFirstChartElement: Ref<HTMLElement | null> = ref(null);
224+
const graphRange = computed(() =>
225+
getGraphRange(props.artifact, props.baseArtifact)
226+
);
227+
228+
onMounted(() => {
229+
loadGraphs().then((d) => {
230+
renderGraphs(d);
231+
});
232+
});
233+
</script>
234+
235+
<template>
236+
<div class="columns graphs">
237+
<div class="rows center-items grow">
238+
<div class="title">
239+
<div class="bold">{{ getGraphTitle() }}</div>
240+
<div style="font-size: 0.8em">
241+
Each plotted value is relative to the first commit of the commit range
242+
</div>
243+
<div style="font-size: 0.8em">
244+
The shaded region shows values that are more recent than the
245+
benchmarked commit
246+
</div>
247+
</div>
248+
<div ref="relativeToFirstChartElement"></div>
249+
</div>
250+
<div class="rows center-items grow">
251+
<div class="title">
252+
<div class="bold">{{ getGraphTitle() }}</div>
253+
<div style="font-size: 0.8em">
254+
Each plotted value is relative to its previous commit
255+
</div>
256+
<div style="font-size: 0.8em">
257+
The shaded region shows values that are more recent than the
258+
benchmarked commit
259+
</div>
260+
</div>
261+
<div ref="relativeToPreviousChartElement"></div>
262+
</div>
263+
</div>
264+
</template>

0 commit comments

Comments
 (0)