Skip to content

Commit

Permalink
Add visualization of compilation sections
Browse files Browse the repository at this point in the history
  • Loading branch information
Kobzol committed Nov 27, 2023
1 parent 938e468 commit 138dad3
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 8 deletions.
61 changes: 53 additions & 8 deletions site/frontend/src/pages/compare/compile/table/benchmark-detail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import {GraphRenderOpts, renderPlots} from "../../../../graph/render";
import {GraphData, GraphKind, GraphsSelector} from "../../../../graph/data";
import uPlot from "uplot";
import CachegrindCmd from "../../../../components/cachegrind-cmd.vue";
import {COMPILE_DETAIL_RESOLVER} from "./detail-resolver";
import {
COMPILE_DETAIL_RESOLVER,
CompileDetail,
CompileDetailSelector,
} from "./detail-resolver";
import CompileSectionsChart from "./sections-chart.vue";
const props = defineProps<{
testCase: CompileTestCase;
Expand Down Expand Up @@ -96,10 +101,9 @@ function drawCurrentDate(opts: GraphRenderOpts, date: Date) {
};
}
// Render both relative and absolute graphs
async function renderGraphs() {
const {start, end, date} = graphRange.value;
const selector = {
function createSelector(): CompileDetailSelector {
const {start, end} = graphRange.value;
return {
benchmark: props.testCase.benchmark,
profile: props.testCase.profile,
scenario: props.testCase.scenario,
Expand All @@ -108,7 +112,16 @@ async function renderGraphs() {
end,
kinds: ["percentrelative", "raw"] as GraphKind[],
};
const detail = await COMPILE_DETAIL_RESOLVER.loadDetail(selector);
}
async function loadDetail(): Promise<CompileDetail> {
return await COMPILE_DETAIL_RESOLVER.loadDetail(createSelector());
}
// Render both relative and absolute graphs
async function renderGraphs(detail: CompileDetail) {
const selector = createSelector();
const date = graphRange.value.date;
if (detail.commits.length === 0) {
return;
}
Expand Down Expand Up @@ -263,7 +276,13 @@ function changeProfileCommand(event: Event) {
profileCommand.value = target.value as ProfileCommand;
}
onMounted(() => renderGraphs());
const detail: Ref<CompileDetail | null> = ref(null);
onMounted(() => {
loadDetail().then((d) => {
detail.value = d;
renderGraphs(d);
});
});
</script>

<template>
Expand Down Expand Up @@ -296,7 +315,7 @@ onMounted(() => renderGraphs());
<tr v-if="(metadata?.iterations ?? null) !== null">
<td>
Iterations
<Tooltip> How many times is the benchmark executed? </Tooltip>
<Tooltip> How many times is the benchmark executed?</Tooltip>
</td>
<td>{{ metadata.iterations }}</td>
</tr>
Expand Down Expand Up @@ -352,6 +371,32 @@ onMounted(() => renderGraphs());
</ul>
</div>
</div>
<div class="columns">
<div class="rows grow">
<div class="title bold">
Sections
<Tooltip
>Percentual duration of individual compilation sections. This is a
rough estimate that might not necessarily contain all of the
individual parts of the compilation. The sections are calculated
based on the results of self-profile queries and they are metric
agnostic.
</Tooltip>
</div>
<div>
<CompileSectionsChart
v-if="
(detail?.sections_before ?? null) !== null &&
(detail?.sections_after ?? null) !== null
"
:before="detail.sections_before"
:after="detail.sections_after"
/>
<span v-else-if="detail === null">Loading…</span>
<span v-else>Not available</span>
</div>
</div>
</div>
<div class="columns graphs">
<div class="rows center-items grow">
<div class="title">
Expand Down
11 changes: 11 additions & 0 deletions site/frontend/src/pages/compare/compile/table/detail-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ export interface CompileDetailSelector {
kinds: GraphKind[];
}

export interface CompilationSection {
name: string;
value: number;
}

export interface CompilationSections {
sections: CompilationSection[];
}

// Compile benchmark detail received from the server
export interface CompileDetail {
commits: Array<[number, string]>;
// One Series for each GraphKind in the CompileDetailSelector
graphs: Series[];
sections_before: CompilationSections | null;
sections_after: CompilationSections | null;
}

/**
Expand Down
196 changes: 196 additions & 0 deletions site/frontend/src/pages/compare/compile/table/sections-chart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<script setup lang="ts">
import {CompilationSection, CompilationSections} from "./detail-resolver";
import {computed, ComputedRef, Ref, ref} from "vue";
const props = defineProps<{
before: CompilationSections;
after: CompilationSections;
}>();
const maxTotalDuration = computed(() => {
const before = calculateTotalSectionsDuration(props.before);
const after = calculateTotalSectionsDuration(props.after);
return Math.max(before, after);
});
function calculateTotalSectionsDuration(sections: CompilationSections): number {
return sections.sections.reduce((accum, section) => accum + section.value, 0);
}
const SECTIONS_PALETTE = [
"#7768AE",
"#FFCf96",
"#ff8080",
"#29adb2",
"#3BB273",
];
function getSectionColor(index: number): string {
return SECTIONS_PALETTE[index % SECTIONS_PALETTE.length];
}
function calculate_width(value: number): string {
const fraction = value / maxTotalDuration.value;
return `${(fraction * 100).toFixed(2)}%`;
}
function formatPercent(
sections: CompilationSections,
sectionName: string
): string {
const values = sections.sections.filter((s) => s.name === sectionName);
if (values.length === 0) return "??";
const value = values[0].value;
const total = calculateTotalSectionsDuration(sections);
const percent = (value / total) * 100;
return `${percent.toFixed(2)}%`;
}
const chartRows: ComputedRef<Array<[string, CompilationSections]>> = computed(
() => [
["Before", props.before],
["After", props.after],
]
);
const legendItems: ComputedRef<
Array<{section: CompilationSection; color: string}>
> = computed(() => {
const items = [];
for (const section of props.before.sections) {
items.push({
section,
color: getSectionColor(items.length),
});
}
return items;
});
const activeSection: Ref<string | null> = ref(null);
function activate(section: string) {
activeSection.value = section;
}
function deactivate() {
activeSection.value = null;
}
</script>

<template>
<div class="wrapper">
<div class="chart-wrapper">
<div class="chart" v-for="([label, sections], rowIndex) in chartRows">
<span class="label">{{ label }}</span>
<div class="section-wrapper">
<div
v-for="(section, index) in sections.sections"
:class="{section: true, active: activeSection === section.name}"
@mouseenter="activate(section.name)"
@mouseleave="deactivate"
:style="{
width: calculate_width(section.value),
backgroundColor: getSectionColor(index),
}"
>
<div
class="description"
v-if="rowIndex == 1 && activeSection === section.name"
>
<div>
<b>{{ section.name }}</b>
</div>
<div>
{{ formatPercent(props.before, section.name) }} ->
{{ formatPercent(props.after, section.name) }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="legend">
<div
class="item"
v-for="item in legendItems"
@mouseenter="activate(item.section.name)"
@mouseleave="deactivate"
>
<div
:class="{color: true, active: activeSection === item.section.name}"
:style="{backgroundColor: item.color}"
></div>
<div class="name">{{ item.section.name }}</div>
</div>
</div>
</div>
</template>

<style scoped lang="scss">
.wrapper {
display: flex;
}
.chart {
display: flex;
justify-content: flex-end;
width: 600px;
&:first-child {
margin-bottom: 10px;
}
.label {
width: 55px;
margin-right: 5px;
align-self: center;
}
.section-wrapper {
width: calc(100% - 60px);
display: flex;
flex-direction: row;
border-right: 1px dashed #333333;
.section {
height: 30px;
position: relative;
}
}
.description {
position: absolute;
top: 35px;
width: max-content;
z-index: 99;
padding: 10px;
background-color: white;
border: 2px solid black;
}
}
.active {
box-shadow: inset 0 0 1px 2px #000;
}
.section:first-child {
border-radius: 5px 0 0 5px;
}
.section:last-child {
border-radius: 0 5px 5px 0;
}
.legend {
margin-left: 40px;
.item {
display: flex;
margin-bottom: 5px;
.color {
width: 15px;
height: 15px;
}
.name {
margin-left: 5px;
}
}
}
</style>

0 comments on commit 138dad3

Please sign in to comment.