mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-11-10 08:57:25 +01:00
Add alternative ver with progress bars
This commit is contained in:
parent
506d112cce
commit
dc86523cce
209
web/frontend/src/JobFootprintBars.svelte
Normal file
209
web/frontend/src/JobFootprintBars.svelte
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
<script>
|
||||||
|
import { getContext } from 'svelte'
|
||||||
|
import {
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Spinner,
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardBody,
|
||||||
|
Progress,
|
||||||
|
Icon,
|
||||||
|
} from "sveltestrap";
|
||||||
|
import { mean, round } from 'mathjs'
|
||||||
|
// import { findThresholds } from './plots/MetricPlot.svelte'
|
||||||
|
// import { formatNumber, scaleNumbers } from './units.js'
|
||||||
|
|
||||||
|
export let job
|
||||||
|
export let jobMetrics
|
||||||
|
|
||||||
|
// export let size = 200
|
||||||
|
|
||||||
|
const footprintMetrics = ['cpu_load', 'flops_any', 'mem_used', 'mem_bw'] // 'acc_utilization' / missing: energy , move to central config before deployment
|
||||||
|
|
||||||
|
console.log('JMs', jobMetrics.filter((jm) => footprintMetrics.includes(jm.name)))
|
||||||
|
|
||||||
|
const footprintMetricConfigs = footprintMetrics.map((fm) => {
|
||||||
|
return getContext('metrics')(job.cluster, fm)
|
||||||
|
}).filter( Boolean ) // Filter only "truthy" vals, see: https://stackoverflow.com/questions/28607451/removing-undefined-values-from-array
|
||||||
|
|
||||||
|
console.log("FMCs", footprintMetricConfigs)
|
||||||
|
|
||||||
|
// const footprintMetricThresholds = footprintMetricConfigs.map((fmc) => { // Only required if scopes smaller than node required
|
||||||
|
// return {name: fmc.name, ...findThresholds(fmc, 'node', job?.subCluster ? job.subCluster : '')} // Merge 2 objects
|
||||||
|
// }).filter( Boolean )
|
||||||
|
|
||||||
|
// console.log("FMTs", footprintMetricThresholds)
|
||||||
|
|
||||||
|
const footprintData = footprintMetrics.map((fm) => {
|
||||||
|
// From JobMetrics: Only Node Scope
|
||||||
|
const jm = jobMetrics.find((jm) => jm.name === fm && jm.scope === 'node')
|
||||||
|
// ... get Mean
|
||||||
|
let mv = null
|
||||||
|
if (jm?.metric?.statisticsSeries) {
|
||||||
|
mv = round(mean(jm.metric.statisticsSeries.mean), 2)
|
||||||
|
} else if (jm?.metric?.series[0]) {
|
||||||
|
mv = jm.metric.series[0].statistics.avg
|
||||||
|
}
|
||||||
|
// ... get Unit
|
||||||
|
let unit = null
|
||||||
|
if (jm?.metric?.unit?.base) {
|
||||||
|
unit = jm.metric.unit.prefix + jm.metric.unit.base
|
||||||
|
} else {
|
||||||
|
unit = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// From MetricConfig: Scope only for scaling -> Not of interest here
|
||||||
|
const metricConfig = footprintMetricConfigs.find((fmc) => fmc.name === fm)
|
||||||
|
// ... get Thresholds
|
||||||
|
const levelNormal = metricConfig.normal - mv
|
||||||
|
const levelCaution = metricConfig.caution - mv
|
||||||
|
const levelAlert = metricConfig.alert - mv
|
||||||
|
|
||||||
|
// Collect
|
||||||
|
if (fm !== 'mem_used') { // Alert if usage is low, peak as maxmimum possible (scaled down for flops_any)
|
||||||
|
if (levelAlert > 0) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: fm === 'flops_any' ? round((metricConfig.peak * 0.85), 0) : metricConfig.peak,
|
||||||
|
color: 'danger',
|
||||||
|
message: 'Metric strongly below common levels!',
|
||||||
|
impact: 3
|
||||||
|
}
|
||||||
|
} else if (levelCaution > 0) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: fm === 'flops_any' ? round((metricConfig.peak * 0.85), 0) : metricConfig.peak,
|
||||||
|
color: 'warning',
|
||||||
|
message: 'Metric below common levels',
|
||||||
|
impact: 2
|
||||||
|
}
|
||||||
|
} else if (levelNormal > 0) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: fm === 'flops_any' ? round((metricConfig.peak * 0.85), 0) : metricConfig.peak,
|
||||||
|
color: 'success',
|
||||||
|
message: 'Metric within common levels',
|
||||||
|
impact: 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: fm === 'flops_any' ? round((metricConfig.peak * 0.85), 0) : metricConfig.peak,
|
||||||
|
color: 'info',
|
||||||
|
message: 'Metric performs better than common levels',
|
||||||
|
impact: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Inverse Logic: Alert if usage is high, Peak is bad and limits execution
|
||||||
|
if (levelAlert <= 0 && levelCaution <= 0 && levelNormal <= 0) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: metricConfig.peak,
|
||||||
|
color: 'danger',
|
||||||
|
message: 'Memory usage extremely above common levels!',
|
||||||
|
impact: 4
|
||||||
|
}
|
||||||
|
} else if (levelAlert > 0 && (levelCaution <= 0 && levelNormal <= 0)) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: metricConfig.peak,
|
||||||
|
color: 'danger',
|
||||||
|
message: 'Memory usage strongly above common levels!',
|
||||||
|
impact: 3
|
||||||
|
}
|
||||||
|
} else if (levelCaution > 0 && levelNormal <= 0) {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: metricConfig.peak,
|
||||||
|
color: 'warning',
|
||||||
|
message: 'Memory usage above common levels',
|
||||||
|
impact: 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
name: fm,
|
||||||
|
unit: unit,
|
||||||
|
avg: mv,
|
||||||
|
max: metricConfig.peak,
|
||||||
|
color: 'success',
|
||||||
|
message: 'Memory usage within common levels',
|
||||||
|
impact: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).filter( Boolean )
|
||||||
|
|
||||||
|
console.log("FPD", footprintData)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Card class="h-auto mt-1">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle class="mb-0 d-flex justify-content-center">
|
||||||
|
Core Metrics Footprint
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardBody>
|
||||||
|
{#each footprintData as fpd}
|
||||||
|
<div class="mb-1 d-flex justify-content-between">
|
||||||
|
<div><b>{fpd.name}</b></div>
|
||||||
|
<div class="cursor-help d-inline-flex" title={fpd.message}>
|
||||||
|
<div class="mx-1">
|
||||||
|
<!-- Alerts Only -->
|
||||||
|
{#if fpd.impact === 3}
|
||||||
|
<Icon name="exclamation-triangle-fill" class="text-danger"/>
|
||||||
|
{:else if fpd.impact === 2}
|
||||||
|
<Icon name="exclamation-triangle" class="text-warning"/>
|
||||||
|
{/if}
|
||||||
|
<!-- Emoji for all states-->
|
||||||
|
{#if fpd.impact === 4}
|
||||||
|
<Icon name="emoji-angry" class="text-danger"/>
|
||||||
|
{:else if fpd.impact === 3}
|
||||||
|
<Icon name="emoji-frown" class="text-danger"/>
|
||||||
|
{:else if fpd.impact === 2}
|
||||||
|
<Icon name="emoji-neutral" class="text-warning"/>
|
||||||
|
{:else if fpd.impact === 1}
|
||||||
|
<Icon name="emoji-smile" class="text-success"/>
|
||||||
|
{:else if fpd.impact === 0}
|
||||||
|
<Icon name="emoji-laughing" class="text-info"/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<!-- Print Values -->
|
||||||
|
{fpd.avg} / {fpd.max} {fpd.unit}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2"> <!-- title={fpd.message} -->
|
||||||
|
<Progress
|
||||||
|
value={fpd.avg}
|
||||||
|
max={fpd.max}
|
||||||
|
color={fpd.color}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cursor-help {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user