mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 09:35:07 +01:00 
			
		
		
		
	Merge branch 'hotfix' into add_detailed_nodelist
This commit is contained in:
		@@ -50,7 +50,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // removed arg "subcluster": input metricconfig and topology now directly derived from subcluster
 | 
			
		||||
  function findThresholds(
 | 
			
		||||
  function findJobAggregationThresholds(
 | 
			
		||||
    subClusterTopology,
 | 
			
		||||
    metricConfig,
 | 
			
		||||
    scope,
 | 
			
		||||
@@ -60,10 +60,16 @@
 | 
			
		||||
  ) {
 | 
			
		||||
 | 
			
		||||
    if (!subClusterTopology || !metricConfig || !scope) {
 | 
			
		||||
      console.warn("Argument missing for findThresholds!");
 | 
			
		||||
      console.warn("Argument missing for findJobAggregationThresholds!");
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // handle special *-stat scopes
 | 
			
		||||
    if (scope.match(/(.*)-stat$/)) {
 | 
			
		||||
      const statParts = scope.split('-');
 | 
			
		||||
      scope = statParts[0]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      (scope == "node" && isShared == false) ||
 | 
			
		||||
      metricConfig?.aggregation == "avg"
 | 
			
		||||
@@ -78,19 +84,20 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (metricConfig?.aggregation == "sum") {
 | 
			
		||||
      let divisor = 1
 | 
			
		||||
      let divisor;
 | 
			
		||||
      if (isShared == true) { // Shared
 | 
			
		||||
        if (numaccs > 0) divisor = subClusterTopology.accelerators.length / numaccs;
 | 
			
		||||
        else if (numhwthreads > 0) divisor = subClusterTopology.node.length / numhwthreads;
 | 
			
		||||
        else if (numhwthreads > 0) divisor = subClusterTopology.core.length / numhwthreads;
 | 
			
		||||
      }
 | 
			
		||||
      else if (scope == 'socket') divisor = subClusterTopology.socket.length;
 | 
			
		||||
      else if (scope == "core") divisor = subClusterTopology.core.length;
 | 
			
		||||
      else if (scope == "accelerator")
 | 
			
		||||
        divisor = subClusterTopology.accelerators.length;
 | 
			
		||||
      else if (scope == "hwthread") divisor = subClusterTopology.node.length;
 | 
			
		||||
      else if (scope == 'node')         divisor = 1; // Use as configured for nodes
 | 
			
		||||
      else if (scope == 'socket')       divisor = subClusterTopology.socket.length;
 | 
			
		||||
      else if (scope == "memoryDomain") divisor = subClusterTopology.memoryDomain.length;
 | 
			
		||||
      else if (scope == "core")         divisor = subClusterTopology.core.length;
 | 
			
		||||
      else if (scope == "hwthread")     divisor = subClusterTopology.core.length; // alt. name for core
 | 
			
		||||
      else if (scope == "accelerator")  divisor = subClusterTopology.accelerators.length;
 | 
			
		||||
      else {
 | 
			
		||||
        // console.log('TODO: how to calc thresholds for ', scope)
 | 
			
		||||
        return null;
 | 
			
		||||
        console.log('Unknown scope, return default aggregation thresholds ', scope)
 | 
			
		||||
        divisor = 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
@@ -130,6 +137,7 @@
 | 
			
		||||
  export let numhwthreads = 0;
 | 
			
		||||
  export let numaccs = 0;
 | 
			
		||||
  export let zoomState = null;
 | 
			
		||||
  export let thresholdState = null;
 | 
			
		||||
 | 
			
		||||
  if (useStatsSeries == null) useStatsSeries = statisticsSeries != null;
 | 
			
		||||
  if (useStatsSeries == false && series == null) useStatsSeries = true;
 | 
			
		||||
@@ -149,7 +157,7 @@
 | 
			
		||||
    caution: "rgba(255, 128, 0, 0.3)",
 | 
			
		||||
    alert: "rgba(255, 0, 0, 0.3)",
 | 
			
		||||
  };
 | 
			
		||||
  const thresholds = findThresholds(
 | 
			
		||||
  const thresholds = findJobAggregationThresholds(
 | 
			
		||||
    subClusterTopology,
 | 
			
		||||
    metricConfig,
 | 
			
		||||
    scope,
 | 
			
		||||
@@ -468,12 +476,14 @@
 | 
			
		||||
                // console.log('Dispatch Zoom with Res from / to', timestep, closest)
 | 
			
		||||
                dispatch('zoom', {
 | 
			
		||||
                  newRes: closest,
 | 
			
		||||
                  lastZoomState: u?.scales
 | 
			
		||||
                  lastZoomState: u?.scales,
 | 
			
		||||
                  lastThreshold: thresholds?.normal
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              dispatch('zoom', {
 | 
			
		||||
                lastZoomState: u?.scales
 | 
			
		||||
                lastZoomState: u?.scales,
 | 
			
		||||
                lastThreshold: thresholds?.normal
 | 
			
		||||
              });
 | 
			
		||||
            };
 | 
			
		||||
          };
 | 
			
		||||
@@ -498,16 +508,19 @@
 | 
			
		||||
  let timeoutId = null;
 | 
			
		||||
 | 
			
		||||
  function render(ren_width, ren_height) {
 | 
			
		||||
    if (!uplot) { // Init uPlot
 | 
			
		||||
    if (!uplot) {
 | 
			
		||||
      opts.width = ren_width;
 | 
			
		||||
      opts.height = ren_height;
 | 
			
		||||
      if (zoomState) {
 | 
			
		||||
      if (zoomState && metricConfig?.aggregation == "avg") {
 | 
			
		||||
        opts.scales = {...zoomState}
 | 
			
		||||
      } else if (zoomState && metricConfig?.aggregation == "sum") {
 | 
			
		||||
        // Allow Zoom In === Ymin changed
 | 
			
		||||
        if (zoomState.y.min !== 0) { // scope change?: only use zoomState if thresholds match
 | 
			
		||||
          if ((thresholdState === thresholds?.normal)) { opts.scales = {...zoomState} };
 | 
			
		||||
        } // else: reset scaling to default
 | 
			
		||||
      }
 | 
			
		||||
      // console.log('Init Sizes ...', { width: opts.width, height: opts.height })
 | 
			
		||||
      uplot = new uPlot(opts, plotData, plotWrapper);
 | 
			
		||||
    } else { // Update size
 | 
			
		||||
      // console.log('Update uPlot ...', { width: ren_width, height: ren_height })
 | 
			
		||||
    } else {
 | 
			
		||||
      uplot.setSize({ width: ren_width, height: ren_height });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
        if (footprintData) {
 | 
			
		||||
            return footprintData.filter(fpd => {
 | 
			
		||||
                if (!jobMetrics.find(m => m.name == fpd.name && m.scope == "node" || fpd.impact == 4)) {
 | 
			
		||||
                    console.warn(`PolarPlot: No metric data (or config) for '${fpd.name}'`)
 | 
			
		||||
                    console.warn(`PolarPlot: No metric data for '${fpd.name}'`)
 | 
			
		||||
                    return false
 | 
			
		||||
                }
 | 
			
		||||
                return true
 | 
			
		||||
@@ -72,6 +72,7 @@
 | 
			
		||||
    const getMetricConfig = getContext("getMetricConfig");
 | 
			
		||||
 | 
			
		||||
    const getValuesForStatGeneric = (getStat) => labels.map(name => {
 | 
			
		||||
        // TODO: Requires Scaling if Shared Job
 | 
			
		||||
        const peak = getMetricConfig(cluster, subCluster, name).peak
 | 
			
		||||
        const metric = jobMetrics.find(m => m.name == name && m.scope == "node")
 | 
			
		||||
        const value = getStat(metric.metric) / peak
 | 
			
		||||
@@ -79,6 +80,7 @@
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    const getValuesForStatFootprint = (getStat) => labels.map(name => {
 | 
			
		||||
        // FootprintData 'Peak' is pre-scaled for Shared Jobs in JobSummary Component
 | 
			
		||||
        const peak = footprintData.find(fpd => fpd.name === name).peak
 | 
			
		||||
        const metric = jobMetrics.find(m => m.name == name && m.scope == "node")
 | 
			
		||||
        const value = getStat(metric.metric) / peak
 | 
			
		||||
@@ -86,14 +88,21 @@
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    function getMax(metric) {
 | 
			
		||||
        let max = 0
 | 
			
		||||
        let max = metric.series[0].statistics.max;
 | 
			
		||||
        for (let series of metric.series)
 | 
			
		||||
            max = Math.max(max, series.statistics.max)
 | 
			
		||||
        return max
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getMin(metric) {
 | 
			
		||||
        let min = metric.series[0].statistics.min;
 | 
			
		||||
        for (let series of metric.series)
 | 
			
		||||
            min = Math.min(min, series.statistics.min)
 | 
			
		||||
        return min
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getAvg(metric) {
 | 
			
		||||
        let avg = 0
 | 
			
		||||
        let avg = 0;
 | 
			
		||||
        for (let series of metric.series)
 | 
			
		||||
            avg += series.statistics.avg
 | 
			
		||||
        return avg / metric.series.length
 | 
			
		||||
@@ -104,6 +113,8 @@
 | 
			
		||||
            return getValuesForStatGeneric(getAvg)
 | 
			
		||||
        } else if (type === 'max') {
 | 
			
		||||
            return getValuesForStatGeneric(getMax)
 | 
			
		||||
        } else if (type === 'min') {
 | 
			
		||||
            return getValuesForStatGeneric(getMin)
 | 
			
		||||
        }
 | 
			
		||||
        console.log('Unknown Type For Polar Data')
 | 
			
		||||
        return []
 | 
			
		||||
@@ -114,6 +125,8 @@
 | 
			
		||||
            return getValuesForStatFootprint(getAvg)
 | 
			
		||||
        } else if (type === 'max') {
 | 
			
		||||
            return getValuesForStatFootprint(getMax)
 | 
			
		||||
        } else if (type === 'min') {
 | 
			
		||||
            return getValuesForStatFootprint(getMin)
 | 
			
		||||
        }
 | 
			
		||||
        console.log('Unknown Type For Polar Data')
 | 
			
		||||
        return []
 | 
			
		||||
@@ -124,25 +137,36 @@
 | 
			
		||||
        datasets: [
 | 
			
		||||
            {
 | 
			
		||||
                label: 'Max',
 | 
			
		||||
                data: footprintData ? loadDataForFootprint('max') : loadDataGeneric('max'), // 
 | 
			
		||||
                data: footprintData ? loadDataForFootprint('max') : loadDataGeneric('max'), // Node Scope Only
 | 
			
		||||
                fill: 1,
 | 
			
		||||
                backgroundColor: 'rgba(0, 102, 255, 0.25)',
 | 
			
		||||
                borderColor: 'rgb(0, 102, 255)',
 | 
			
		||||
                pointBackgroundColor: 'rgb(0, 102, 255)',
 | 
			
		||||
                backgroundColor: 'rgba(0, 0, 255, 0.25)',
 | 
			
		||||
                borderColor: 'rgb(0, 0, 255)',
 | 
			
		||||
                pointBackgroundColor: 'rgb(0, 0, 255)',
 | 
			
		||||
                pointBorderColor: '#fff',
 | 
			
		||||
                pointHoverBackgroundColor: '#fff',
 | 
			
		||||
                pointHoverBorderColor: 'rgb(0, 102, 255)'
 | 
			
		||||
                pointHoverBorderColor: 'rgb(0, 0, 255)'
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                label: 'Avg',
 | 
			
		||||
                data: footprintData ? loadDataForFootprint('avg') : loadDataGeneric('avg'), // getValuesForStat(getAvg)
 | 
			
		||||
                fill: true,
 | 
			
		||||
                backgroundColor: 'rgba(255, 153, 0, 0.25)',
 | 
			
		||||
                borderColor: 'rgb(255, 153, 0)',
 | 
			
		||||
                pointBackgroundColor: 'rgb(255, 153, 0)',
 | 
			
		||||
                data: footprintData ? loadDataForFootprint('avg') : loadDataGeneric('avg'), // Node Scope Only
 | 
			
		||||
                fill: 2,
 | 
			
		||||
                backgroundColor: 'rgba(255, 210, 0, 0.25)',
 | 
			
		||||
                borderColor: 'rgb(255, 210, 0)',
 | 
			
		||||
                pointBackgroundColor: 'rgb(255, 210, 0)',
 | 
			
		||||
                pointBorderColor: '#fff',
 | 
			
		||||
                pointHoverBackgroundColor: '#fff',
 | 
			
		||||
                pointHoverBorderColor: 'rgb(255, 153, 0)'
 | 
			
		||||
                pointHoverBorderColor: 'rgb(255, 210, 0)'
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                label: 'Min',
 | 
			
		||||
                data: footprintData ? loadDataForFootprint('min') : loadDataGeneric('min'), // Node Scope Only
 | 
			
		||||
                fill: true,
 | 
			
		||||
                backgroundColor: 'rgba(255, 0, 0, 0.25)',
 | 
			
		||||
                borderColor: 'rgb(255, 0, 0)',
 | 
			
		||||
                pointBackgroundColor: 'rgb(255, 0, 0)',
 | 
			
		||||
                pointBorderColor: '#fff',
 | 
			
		||||
                pointHoverBackgroundColor: '#fff',
 | 
			
		||||
                pointHoverBorderColor: 'rgb(255, 0, 0)'
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user