diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index 06219b9..aa4ae37 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -10,7 +10,7 @@ import { binsFromFootprint } from './utils.js' import ScatterPlot from './plots/Scatter.svelte' import PlotTable from './PlotTable.svelte' - import Roofline from './plots/Roofline.svelte' + import RooflineHeatmap from './plots/RooflineHeatmap.svelte' const { query: initq } = init() @@ -315,7 +315,7 @@ {:else if $rooflineQuery.data && cluster}
{#key $rooflineQuery.data} - import { getContext } from "svelte"; import Refresher from "./joblist/Refresher.svelte"; - import Roofline, { transformPerNodeData } from "./plots/Roofline.svelte"; - import Rooflineuplot from "./plots/Rooflineuplot.svelte"; + import Roofline from "./plots/Roofline.svelte"; import Pie, { colors } from "./plots/Pie.svelte"; import Histogram from "./plots/Histogram.svelte"; import { @@ -17,7 +16,7 @@ Progress, Icon, } from "sveltestrap"; - import { init, convert2uplot } from "./utils.js"; + import { init, convert2uplot, transformPerNodeDataForRoofline } from "./utils.js"; import { scaleNumbers } from "./units.js"; import { queryStore, @@ -33,8 +32,7 @@ let plotWidths = [], colWidth1 = 0, - colWidth2 = 0, - colWidth3 = 0; + colWidth2 = 0 let from = new Date(Date.now() - 5 * 60 * 1000), to = new Date(Date.now()); const topOptions = [ @@ -434,7 +432,7 @@ colorDots={true} showTime={false} cluster={subCluster} - data={transformPerNodeData( + data={transformPerNodeDataForRoofline( $mainQuery.data.nodeMetrics.filter( (data) => data.subCluster == subCluster.name ) @@ -667,13 +665,4 @@ {/key} - - -
- c.name == cluster).subClusters[0]} - /> - - {/if} diff --git a/web/frontend/src/plots/Roofline.svelte b/web/frontend/src/plots/Roofline.svelte index 57482ee..cc65f41 100644 --- a/web/frontend/src/plots/Roofline.svelte +++ b/web/frontend/src/plots/Roofline.svelte @@ -1,16 +1,72 @@ -
- -
+ - - + +{#if data != null} +
+{:else} + Cannot render roofline: No data! +{/if} \ No newline at end of file diff --git a/web/frontend/src/plots/RooflineHeatmap.svelte b/web/frontend/src/plots/RooflineHeatmap.svelte new file mode 100644 index 0000000..be7ec65 --- /dev/null +++ b/web/frontend/src/plots/RooflineHeatmap.svelte @@ -0,0 +1,234 @@ +
+ +
+ + + + diff --git a/web/frontend/src/plots/Rooflineuplot.svelte b/web/frontend/src/plots/Rooflineuplot.svelte deleted file mode 100644 index 01ed489..0000000 --- a/web/frontend/src/plots/Rooflineuplot.svelte +++ /dev/null @@ -1,360 +0,0 @@ - - -{#if data != null} -
-{:else} - Cannot render roofline: No data! -{/if} \ No newline at end of file diff --git a/web/frontend/src/utils.js b/web/frontend/src/utils.js index 0650916..c89afda 100644 --- a/web/frontend/src/utils.js +++ b/web/frontend/src/utils.js @@ -363,3 +363,66 @@ export function binsFromFootprint(weights, scope, values, numBins) { bins: bins } } + +export function transformDataForRoofline(flopsAny, memBw, renderTime) { // Uses Metric Object + const nodes = flopsAny.series.length + const timesteps = flopsAny.series[0].data.length + + /* c will contain values from 0 to 1 representing the time */ + const x = [], y = [], c = [] + + if (flopsAny && memBw) { + for (let i = 0; i < nodes; i++) { + const flopsData = flopsAny.series[i].data + const memBwData = memBw.series[i].data + for (let j = 0; j < timesteps; j++) { + const f = flopsData[j], m = memBwData[j] + const intensity = f / m + if (Number.isNaN(intensity) || !Number.isFinite(intensity)) + continue + + x.push(intensity) + y.push(f) + c.push(renderTime ? j / timesteps : 0) + } + } + } else { + console.warn("transformData: metrics for 'mem_bw' and/or 'flops_any' missing!") + } + + return { + x, y, c, + xLabel: 'Intensity [FLOPS/byte]', + yLabel: 'Performance [GFLOPS]' + } +} + +// Return something to be plotted. The argument shall be the result of the +// `nodeMetrics` GraphQL query. +export function transformPerNodeDataForRoofline(nodes) { + const x = [], y = [], c = [] + for (let node of nodes) { + let flopsAny = node.metrics.find(m => m.name == 'flops_any' && m.scope == 'node')?.metric + let memBw = node.metrics.find(m => m.name == 'mem_bw' && m.scope == 'node')?.metric + if (!flopsAny || !memBw) { + console.warn("transformPerNodeData: metrics for 'mem_bw' and/or 'flops_any' missing!") + continue + } + + let flopsData = flopsAny.series[0].data, memBwData = memBw.series[0].data + const f = flopsData[flopsData.length - 1], m = memBwData[flopsData.length - 1] + const intensity = f / m + if (Number.isNaN(intensity) || !Number.isFinite(intensity)) + continue + + x.push(intensity) + y.push(f) + c.push(0) + } + + return { + x, y, c, + xLabel: 'Intensity [FLOPS/byte]', + yLabel: 'Performance [GFLOPS]' + } +}