@@ -33,11 +33,13 @@ import (
33
33
"google.golang.org/grpc/status"
34
34
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
35
"k8s.io/apimachinery/pkg/types"
36
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
36
37
internalapi "k8s.io/cri-api/pkg/apis"
37
38
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
38
39
"k8s.io/klog/v2"
39
40
statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
40
41
kubetypes "k8s.io/kubelet/pkg/types"
42
+ "k8s.io/kubernetes/pkg/features"
41
43
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
42
44
"k8s.io/kubernetes/pkg/kubelet/server/stats"
43
45
"k8s.io/utils/clock"
@@ -211,6 +213,7 @@ func (p *criStatsProvider) listPodStatsPartiallyFromCRI(ctx context.Context, upd
211
213
p .addPodNetworkStats (ps , podSandboxID , caInfos , cs , containerNetworkStats [podSandboxID ])
212
214
p .addPodCPUMemoryStats (ps , types .UID (podSandbox .Metadata .Uid ), allInfos , cs )
213
215
p .addSwapStats (ps , types .UID (podSandbox .Metadata .Uid ), allInfos , cs )
216
+ p .addIOStats (ps , types .UID (podSandbox .Metadata .Uid ), allInfos , cs )
214
217
215
218
// If cadvisor stats is available for the container, use it to populate
216
219
// container stats
@@ -260,6 +263,7 @@ func (p *criStatsProvider) listPodStatsStrictlyFromCRI(ctx context.Context, upda
260
263
addCRIPodCPUStats (ps , criSandboxStat )
261
264
addCRIPodMemoryStats (ps , criSandboxStat )
262
265
addCRIPodProcessStats (ps , criSandboxStat )
266
+ addCRIPodIOStats (ps , criSandboxStat )
263
267
makePodStorageStats (ps , rootFsInfo , p .resourceAnalyzer , p .hostStatsProvider , true )
264
268
summarySandboxStats = append (summarySandboxStats , * ps )
265
269
}
@@ -535,6 +539,7 @@ func (p *criStatsProvider) addPodCPUMemoryStats(
535
539
usageNanoCores := getUint64Value (cs .CPU .UsageNanoCores ) + getUint64Value (ps .CPU .UsageNanoCores )
536
540
ps .CPU .UsageCoreNanoSeconds = & usageCoreNanoSeconds
537
541
ps .CPU .UsageNanoCores = & usageNanoCores
542
+ // Pod level PSI stats cannot be calculated from container level
538
543
}
539
544
540
545
if cs .Memory != nil {
@@ -555,6 +560,7 @@ func (p *criStatsProvider) addPodCPUMemoryStats(
555
560
ps .Memory .RSSBytes = & rSSBytes
556
561
ps .Memory .PageFaults = & pageFaults
557
562
ps .Memory .MajorPageFaults = & majorPageFaults
563
+ // Pod level PSI stats cannot be calculated from container level
558
564
}
559
565
}
560
566
@@ -564,14 +570,14 @@ func (p *criStatsProvider) addSwapStats(
564
570
allInfos map [string ]cadvisorapiv2.ContainerInfo ,
565
571
cs * statsapi.ContainerStats ,
566
572
) {
567
- // try get cpu and memory stats from cadvisor first.
573
+ // try get swap stats from cadvisor first.
568
574
podCgroupInfo := getCadvisorPodInfoFromPodUID (podUID , allInfos )
569
575
if podCgroupInfo != nil {
570
576
ps .Swap = cadvisorInfoToSwapStats (podCgroupInfo )
571
577
return
572
578
}
573
579
574
- // Sum Pod cpu and memory stats from containers stats.
580
+ // Sum Pod swap stats from containers stats.
575
581
if cs .Swap != nil {
576
582
if ps .Swap == nil {
577
583
ps .Swap = & statsapi.SwapStats {Time : cs .Swap .Time }
@@ -583,6 +589,30 @@ func (p *criStatsProvider) addSwapStats(
583
589
}
584
590
}
585
591
592
+ func (p * criStatsProvider ) addIOStats (
593
+ ps * statsapi.PodStats ,
594
+ podUID types.UID ,
595
+ allInfos map [string ]cadvisorapiv2.ContainerInfo ,
596
+ cs * statsapi.ContainerStats ,
597
+ ) {
598
+ if ! utilfeature .DefaultFeatureGate .Enabled (features .KubeletPSI ) {
599
+ return
600
+ }
601
+ // try get IO stats from cadvisor first.
602
+ podCgroupInfo := getCadvisorPodInfoFromPodUID (podUID , allInfos )
603
+ if podCgroupInfo != nil {
604
+ ps .IO = cadvisorInfoToIOStats (podCgroupInfo )
605
+ return
606
+ }
607
+
608
+ if cs .IO != nil {
609
+ if ps .IO == nil {
610
+ ps .IO = & statsapi.IOStats {Time : cs .IO .Time }
611
+ }
612
+ // Pod level PSI stats cannot be calculated from container level
613
+ }
614
+ }
615
+
586
616
func (p * criStatsProvider ) addProcessStats (
587
617
ps * statsapi.PodStats ,
588
618
container * cadvisorapiv2.ContainerInfo ,
@@ -624,6 +654,7 @@ func (p *criStatsProvider) makeContainerStats(
624
654
if usageNanoCores != nil {
625
655
result .CPU .UsageNanoCores = usageNanoCores
626
656
}
657
+ result .CPU .PSI = makePSIStats (stats .Cpu .Psi )
627
658
} else {
628
659
result .CPU .Time = metav1 .NewTime (time .Unix (0 , time .Now ().UnixNano ()))
629
660
result .CPU .UsageCoreNanoSeconds = uint64Ptr (0 )
@@ -634,6 +665,7 @@ func (p *criStatsProvider) makeContainerStats(
634
665
if stats .Memory .WorkingSetBytes != nil {
635
666
result .Memory .WorkingSetBytes = & stats .Memory .WorkingSetBytes .Value
636
667
}
668
+ result .Memory .PSI = makePSIStats (stats .Memory .Psi )
637
669
} else {
638
670
result .Memory .Time = metav1 .NewTime (time .Unix (0 , time .Now ().UnixNano ()))
639
671
result .Memory .WorkingSetBytes = uint64Ptr (0 )
@@ -651,6 +683,15 @@ func (p *criStatsProvider) makeContainerStats(
651
683
result .Swap .SwapUsageBytes = uint64Ptr (0 )
652
684
result .Swap .SwapAvailableBytes = uint64Ptr (0 )
653
685
}
686
+ if utilfeature .DefaultFeatureGate .Enabled (features .KubeletPSI ) {
687
+ result .IO = & statsapi.IOStats {}
688
+ if stats .Io != nil {
689
+ result .IO .Time = metav1 .NewTime (time .Unix (0 , stats .Io .Timestamp ))
690
+ result .IO .PSI = makePSIStats (stats .Io .Psi )
691
+ } else {
692
+ result .IO .Time = metav1 .NewTime (time .Unix (0 , time .Now ().UnixNano ()))
693
+ }
694
+ }
654
695
if stats .WritableLayer != nil {
655
696
result .Rootfs .Time = metav1 .NewTime (time .Unix (0 , stats .WritableLayer .Timestamp ))
656
697
if stats .WritableLayer .UsedBytes != nil {
@@ -714,6 +755,7 @@ func (p *criStatsProvider) makeContainerCPUAndMemoryStats(
714
755
if usageNanoCores != nil {
715
756
result .CPU .UsageNanoCores = usageNanoCores
716
757
}
758
+ result .CPU .PSI = makePSIStats (stats .Cpu .Psi )
717
759
} else {
718
760
result .CPU .Time = metav1 .NewTime (time .Unix (0 , time .Now ().UnixNano ()))
719
761
result .CPU .UsageCoreNanoSeconds = uint64Ptr (0 )
@@ -724,6 +766,7 @@ func (p *criStatsProvider) makeContainerCPUAndMemoryStats(
724
766
if stats .Memory .WorkingSetBytes != nil {
725
767
result .Memory .WorkingSetBytes = & stats .Memory .WorkingSetBytes .Value
726
768
}
769
+ result .Memory .PSI = makePSIStats (stats .Memory .Psi )
727
770
} else {
728
771
result .Memory .Time = metav1 .NewTime (time .Unix (0 , time .Now ().UnixNano ()))
729
772
result .Memory .WorkingSetBytes = uint64Ptr (0 )
@@ -732,6 +775,33 @@ func (p *criStatsProvider) makeContainerCPUAndMemoryStats(
732
775
return result
733
776
}
734
777
778
+ func makePSIStats (stats * runtimeapi.PsiStats ) * statsapi.PSIStats {
779
+ if ! utilfeature .DefaultFeatureGate .Enabled (features .KubeletPSI ) {
780
+ return nil
781
+ }
782
+ if stats == nil {
783
+ return nil
784
+ }
785
+ result := & statsapi.PSIStats {}
786
+ if stats .Full != nil {
787
+ result .Full = statsapi.PSIData {
788
+ Total : stats .Full .Total ,
789
+ Avg10 : stats .Full .Avg10 ,
790
+ Avg60 : stats .Full .Avg60 ,
791
+ Avg300 : stats .Full .Avg300 ,
792
+ }
793
+ }
794
+ if stats .Some != nil {
795
+ result .Some = statsapi.PSIData {
796
+ Total : stats .Some .Total ,
797
+ Avg10 : stats .Some .Avg10 ,
798
+ Avg60 : stats .Some .Avg60 ,
799
+ Avg300 : stats .Some .Avg300 ,
800
+ }
801
+ }
802
+ return result
803
+ }
804
+
735
805
// getContainerUsageNanoCores first attempts to get the usage nano cores from the stats reported
736
806
// by the CRI. If it is unable to, it gets the information from the cache instead.
737
807
func (p * criStatsProvider ) getContainerUsageNanoCores (stats * runtimeapi.ContainerStats ) * uint64 {
@@ -910,6 +980,13 @@ func (p *criStatsProvider) addCadvisorContainerStats(
910
980
if swap != nil {
911
981
cs .Swap = swap
912
982
}
983
+
984
+ if utilfeature .DefaultFeatureGate .Enabled (features .KubeletPSI ) {
985
+ io := cadvisorInfoToIOStats (caPodStats )
986
+ if io != nil {
987
+ cs .IO = io
988
+ }
989
+ }
913
990
}
914
991
915
992
func (p * criStatsProvider ) addCadvisorContainerCPUAndMemoryStats (
0 commit comments