@@ -43,6 +43,7 @@ import (
4343 "github.com/kubewharf/katalyst-core/pkg/config/generic"
4444 "github.com/kubewharf/katalyst-core/pkg/consts"
4545 "github.com/kubewharf/katalyst-core/pkg/metaserver"
46+ malachitetypes "github.com/kubewharf/katalyst-core/pkg/metaserver/agent/metric/provisioner/malachite/types"
4647 "github.com/kubewharf/katalyst-core/pkg/metrics"
4748 schedutil "github.com/kubewharf/katalyst-core/pkg/scheduler/util"
4849 "github.com/kubewharf/katalyst-core/pkg/util"
@@ -303,6 +304,13 @@ func (p *nodeMetricsReporterPlugin) getNodeMetricInfo() (*nodeapis.NodeMetricInf
303304 nmi .GenericUsage .CPU = cpuUsage
304305 }
305306
307+ memoryBandwidthUsage , err := p .getNodeMemoryBandwidthUsage ()
308+ if err != nil {
309+ errList = append (errList , err )
310+ } else {
311+ nmi .GenericUsage .MemoryBandwidth = memoryBandwidthUsage
312+ }
313+
306314 for numaID := 0 ; numaID < p .metaServer .NumNUMANodes ; numaID ++ {
307315 numaUsage := nodeapis.NUMAMetricInfo {NUMAId : numaID , Usage : & nodeapis.ResourceMetric {}}
308316 memoryUsage , err := p .getNodeNUMAMemoryUsage (numaID )
@@ -319,6 +327,13 @@ func (p *nodeMetricsReporterPlugin) getNodeMetricInfo() (*nodeapis.NodeMetricInf
319327 numaUsage .Usage .CPU = numaCpuUsage
320328 }
321329
330+ numaMemoryBandwidthUsage , err := p .getNodeNUMAMemoryBandwidthUsage (numaID )
331+ if err != nil {
332+ errList = append (errList , err )
333+ } else {
334+ numaUsage .Usage .MemoryBandwidth = numaMemoryBandwidthUsage
335+ }
336+
322337 nmi .NUMAUsage = append (nmi .NUMAUsage , numaUsage )
323338 }
324339 return nmi , errors .NewAggregate (errList )
@@ -394,6 +409,7 @@ func (p *nodeMetricsReporterPlugin) getPodUsage(pod *v1.Pod) (v1.ResourceList, m
394409 }
395410 podCPUUsage := .0
396411 podMemUsage := .0
412+ podMemoryBandwidthUsage := resource .NewQuantity (0 , resource .BinarySI )
397413 for _ , container := range containers {
398414 if container .RampUp {
399415 rampUp = true
@@ -460,19 +476,46 @@ func (p *nodeMetricsReporterPlugin) getPodUsage(pod *v1.Pod) (v1.ResourceList, m
460476 usages [v1 .ResourceMemory ] = memUsage
461477 numaUsage [numaID ] = usages
462478 }
479+
480+ containerNUMAMBWUsage , containerTotalMBW , err := p .getContainerNUMAMemoryBandwidthUsage (string (pod .UID ), container .ContainerName )
481+ if err != nil {
482+ errList = append (errList , fmt .Errorf ("failed to get container NUMA memory bandwidth usage, podUID=%v, containerName=%v, err=%v" ,
483+ pod .UID , container .ContainerName , err ))
484+ } else {
485+ podMemoryBandwidthUsage .Add (* containerTotalMBW )
486+ for numaID , mbw := range containerNUMAMBWUsage {
487+ usages , ok := numaUsage [numaID ]
488+ if ! ok {
489+ usages = make (v1.ResourceList )
490+ }
491+
492+ mbwUsage , ok := usages [apiconsts .ResourceMemoryBandwidth ]
493+ if ! ok {
494+ mbwUsage = * resource .NewQuantity (0 , resource .BinarySI )
495+ }
496+ mbwUsage .Add (mbw )
497+ usages [apiconsts .ResourceMemoryBandwidth ] = mbwUsage
498+ numaUsage [numaID ] = usages
499+ }
500+ }
463501 }
464502
465503 cpu := resource .NewMilliQuantity (int64 (podCPUUsage * 1000 ), resource .DecimalSI )
466504 memory := resource .NewQuantity (int64 (podMemUsage ), resource .BinarySI )
467505
468- return v1.ResourceList {v1 .ResourceMemory : * memory , v1 .ResourceCPU : * cpu }, numaUsage , assignedNUMAs , rampUp , errors .NewAggregate (errList )
506+ return v1.ResourceList {
507+ v1 .ResourceMemory : * memory ,
508+ v1 .ResourceCPU : * cpu ,
509+ apiconsts .ResourceMemoryBandwidth : * podMemoryBandwidthUsage ,
510+ }, numaUsage , assignedNUMAs , rampUp , errors .NewAggregate (errList )
469511}
470512
471513func (p * nodeMetricsReporterPlugin ) getGroupUsage (pods []* v1.Pod , qosLevel string ) (* nodeapis.ResourceMetric , []nodeapis.NUMAMetricInfo , []* v1.Pod , error ) {
472514 var errList []error
473515
474516 cpu := resource .NewQuantity (0 , resource .DecimalSI )
475517 memory := resource .NewQuantity (0 , resource .BinarySI )
518+ memoryBandwidth := resource .NewQuantity (0 , resource .BinarySI )
476519
477520 numaUsages := make (map [int ]v1.ResourceList )
478521
@@ -494,14 +537,28 @@ func (p *nodeMetricsReporterPlugin) getGroupUsage(pods []*v1.Pod, qosLevel strin
494537 }
495538
496539 for numaID := range assignedNUMAs .ToSliceInt () {
497- podNUMAUsage [ numaID ] = map [v1. ResourceName ]resource. Quantity {
498- v1 . ResourceCPU : * resource . NewMilliQuantity ( req . Cpu (). MilliValue () / int64 ( assignedNUMAs . Size ()), resource . DecimalSI ),
499- v1 . ResourceMemory : * resource . NewQuantity ( req . Memory (). Value () / int64 ( assignedNUMAs . Size ()), resource . BinarySI ),
540+ usages , ok := podNUMAUsage [ numaID ]
541+ if ! ok {
542+ usages = make (v1. ResourceList )
500543 }
544+
545+ usages [v1 .ResourceCPU ] = * resource .NewMilliQuantity (
546+ req .Cpu ().MilliValue ()/ int64 (assignedNUMAs .Size ()),
547+ resource .DecimalSI ,
548+ )
549+ usages [v1 .ResourceMemory ] = * resource .NewQuantity (
550+ req .Memory ().Value ()/ int64 (assignedNUMAs .Size ()),
551+ resource .BinarySI ,
552+ )
553+
554+ podNUMAUsage [numaID ] = usages
501555 }
502556 }
503557 cpu .Add (* podUsage .Cpu ())
504558 memory .Add (* podUsage .Memory ())
559+ if mbw , ok := podUsage [apiconsts .ResourceMemoryBandwidth ]; ok {
560+ memoryBandwidth .Add (mbw )
561+ }
505562
506563 for numaID , podUsages := range podNUMAUsage {
507564 usages , ok := numaUsages [numaID ]
@@ -539,6 +596,13 @@ func (p *nodeMetricsReporterPlugin) getGroupUsage(pods []*v1.Pod, qosLevel strin
539596 resourceMetric .CPU = aggCPU
540597 }
541598
599+ aggMBW := p .getAggregatedMetric (memoryBandwidth , apiconsts .ResourceMemoryBandwidth , "getGroupUsage" , qosLevel , "memory_bandwidth" )
600+ if aggMBW == nil {
601+ errList = append (errList , fmt .Errorf ("failed to get enough samples for group memory bandwidth, qosLevel=%v" , qosLevel ))
602+ } else {
603+ resourceMetric .MemoryBandwidth = aggMBW
604+ }
605+
542606 for numaID := 0 ; numaID < p .metaServer .NumNUMANodes ; numaID ++ {
543607 resourceUsages , ok := numaUsages [numaID ]
544608 if ! ok {
@@ -565,6 +629,14 @@ func (p *nodeMetricsReporterPlugin) getGroupUsage(pods []*v1.Pod, qosLevel strin
565629 resourceNUMAMetric .Memory = aggNUMAMem
566630 }
567631
632+ mbwUsage := resourceUsages [apiconsts .ResourceMemoryBandwidth ]
633+ aggNUMAMBW := p .getAggregatedMetric (& mbwUsage , apiconsts .ResourceMemoryBandwidth , "getGroupNUMAUsage" , qosLevel , "memory_bandwidth" , strconv .Itoa (numaID ))
634+ if aggNUMAMBW == nil {
635+ errList = append (errList , fmt .Errorf ("failed to get enough samples for group numa memory bandwidth, qosLevel=%v, numa=%v" , qosLevel , numaID ))
636+ } else {
637+ resourceNUMAMetric .MemoryBandwidth = aggNUMAMBW
638+ }
639+
568640 resourceNUMAMetrics = append (resourceNUMAMetrics , nodeapis.NUMAMetricInfo {
569641 NUMAId : numaID ,
570642 Usage : & resourceNUMAMetric ,
@@ -660,3 +732,52 @@ func (p *nodeMetricsReporterPlugin) getAggregatedMetric(value *resource.Quantity
660732 }
661733 return aggregator .GetWindowedResources (* value )
662734}
735+
736+ func (p * nodeMetricsReporterPlugin ) getNodeNUMAMemoryBandwidthUsage (numaID int ) (* resource.Quantity , error ) {
737+ metricData , err := p .metaServer .GetNumaMetric (numaID , consts .MetricTotalPsMemBandwidthNuma )
738+ if err != nil {
739+ return nil , fmt .Errorf ("failed to get %s for numa=%d: %w" , consts .MetricTotalPsMemBandwidthNuma , numaID , err )
740+ }
741+
742+ return resource .NewQuantity (int64 (metricData .Value ), resource .BinarySI ), nil
743+ }
744+
745+ func (p * nodeMetricsReporterPlugin ) getNodeMemoryBandwidthUsage () (* resource.Quantity , error ) {
746+ total := resource .NewQuantity (0 , resource .BinarySI )
747+
748+ for numaID := 0 ; numaID < p .metaServer .NumNUMANodes ; numaID ++ {
749+ q , err := p .getNodeNUMAMemoryBandwidthUsage (numaID )
750+ if err != nil {
751+ return nil , err
752+ }
753+ total .Add (* q )
754+ }
755+ return total , nil
756+ }
757+
758+ func (p * nodeMetricsReporterPlugin ) getContainerNUMAMemoryBandwidthUsage (podUID , containerName string ) (map [int ]resource.Quantity , * resource.Quantity , error ) {
759+ key := fmt .Sprintf ("%s/%s/%s" , consts .MetricMbmTotalPsContainerL3 , podUID , containerName )
760+ raw := p .metaServer .MetricsFetcher .GetByStringIndex (key )
761+
762+ statsMap , ok := raw .(map [int ]malachitetypes.L3CacheBytesPS )
763+ if ! ok || len (statsMap ) == 0 {
764+ return map [int ]resource.Quantity {}, resource .NewQuantity (0 , resource .BinarySI ), nil
765+ }
766+
767+ total := resource .NewQuantity (0 , resource .BinarySI )
768+ numaUsage := make (map [int ]resource.Quantity )
769+
770+ for _ , l3Stat := range statsMap {
771+ q := * resource .NewQuantity (int64 (l3Stat .MbmTotalBytesPS ), resource .BinarySI )
772+ total .Add (q )
773+
774+ exist , ok := numaUsage [l3Stat .NumaID ]
775+ if ! ok {
776+ exist = * resource .NewQuantity (0 , resource .BinarySI )
777+ }
778+ exist .Add (q )
779+ numaUsage [l3Stat .NumaID ] = exist
780+ }
781+
782+ return numaUsage , total , nil
783+ }
0 commit comments