Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add history graph to benchmark detail #1690

Merged
merged 12 commits into from
Aug 9, 2023
16 changes: 16 additions & 0 deletions site/frontend/src/graph/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {GraphData, GraphsSelector} from "./data";
import {getJson} from "../utils/requests";
import {GRAPH_DATA_URL} from "../urls";

export async function loadGraphs(selector: GraphsSelector): Promise<GraphData> {
const params = {
start: selector.start,
end: selector.end,
kind: selector.kind as string,
stat: selector.stat,
benchmark: selector.benchmark,
scenario: selector.scenario,
profile: selector.profile,
};
return await getJson<GraphData>(GRAPH_DATA_URL, params);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import uPlot, {TypedArray} from "uplot";
import {GraphData, GraphsSelector} from "./state";
import {GraphData, GraphsSelector} from "./data";

const commonCacheStateColors = {
full: "#7cb5ec",
Expand Down Expand Up @@ -148,7 +148,6 @@ function tooltipPlugin({
}

function genPlotOpts({
title,
width,
height,
yAxisLabel,
Expand All @@ -159,9 +158,9 @@ function genPlotOpts({
alpha = 0.3,
prox = 5,
absoluteMode,
hooks,
}) {
return {
title,
width,
height,
series,
Expand Down Expand Up @@ -239,6 +238,7 @@ function genPlotOpts({
ctx.stroke();
},
],
...hooks,
},
},
tooltipPlugin({
Expand Down Expand Up @@ -280,13 +280,22 @@ function normalizeData(data: GraphData) {
}
}

// Renders the plots data with the given parameters from the `selector`, into a DOM node optionally
// selected by the `elementSelector` query.
export type GraphRenderOpts = {
renderTitle?: boolean;
hooks?: {drawSeries: (uPlot, number) => void};
};

// Renders the plots data with the given parameters from the `selector` into
// the passed DOM element.
export function renderPlots(
data: GraphData,
selector: GraphsSelector,
elementSelector: string
plotElement: HTMLElement,
opts?: GraphRenderOpts
) {
const renderTitle = opts?.renderTitle ?? true;
const hooks = opts?.hooks ?? {};

normalizeData(data);

const names = Object.keys(data.benchmarks).sort();
Expand Down Expand Up @@ -364,7 +373,6 @@ export function renderPlots(
cacheStates[Object.keys(cacheStates)[0]].interpolated_indices;

let plotOpts = genPlotOpts({
title: benchName + "-" + benchKind,
width: Math.floor(window.innerWidth / 4) - 40,
height: 300,
yAxisLabel,
Expand All @@ -375,13 +383,13 @@ export function renderPlots(
return indices.has(dataIdx);
},
absoluteMode: selector.kind == "raw",
hooks,
});
if (renderTitle) {
plotOpts["title"] = `${benchName}-${benchKind}`;
}

new uPlot(
plotOpts,
plotData as any as TypedArray[],
document.querySelector<HTMLElement>(elementSelector)
);
new uPlot(plotOpts, plotData as any as TypedArray[], plotElement);

i++;
}
Expand Down
29 changes: 29 additions & 0 deletions site/frontend/src/graph/resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {GraphData, GraphsSelector} from "./data";
import {loadGraphs} from "./api";

/**
* Graph API resolver that contains a cache of downloaded graphs.
* This is important for Vue components that download a graph on mount.
* Without a cache, they would download a graph each time they are destroyed
* and recreated.
*/
export class GraphResolver {
private cache: Dict<GraphData> = {};

public async loadGraph(selector: GraphsSelector): Promise<GraphData> {
const key = `${selector.benchmark};${selector.profile};${selector.scenario};${selector.start};${selector.end};${selector.stat};${selector.kind}`;
if (!this.cache.hasOwnProperty(key)) {
this.cache[key] = await loadGraphs(selector);
}

return this.cache[key];
}
}

/**
* This is essentially a global variable, but it makes the code simpler and
* since we currently don't have any unit tests, we don't really need to avoid
* global variables that much. If needed, it could be provided to Vue components
* from a parent via props or context.
*/
export const GRAPH_RESOLVER = new GraphResolver();
Loading