@@ -727,6 +727,134 @@ func TestPCIELinkBytesPerSecond(t *testing.T) {
727727 }
728728}
729729
730+ func TestPCIELinkMetrics (t * testing.T ) {
731+ tests := map [string ]struct {
732+ currentWidth int
733+ maxWidth int
734+ currentGeneration int
735+ maxGeneration int
736+ expectedMetricVals map [string ]float64
737+ expectedErr string
738+ }{
739+ "matching link" : {
740+ currentWidth : 16 ,
741+ maxWidth : 16 ,
742+ currentGeneration : 4 ,
743+ maxGeneration : 4 ,
744+ expectedMetricVals : map [string ]float64 {
745+ "pci.link.width.current" : 16 ,
746+ "pci.link.width.max" : 16 ,
747+ "pci.link.width.degraded" : 0 ,
748+ "pci.link.speed.current" : 31.50769230769231e9 ,
749+ "pci.link.speed.max" : 31.50769230769231e9 ,
750+ "pci.link.speed.degraded" : 0 ,
751+ },
752+ },
753+ "degraded link" : {
754+ currentWidth : 8 ,
755+ maxWidth : 16 ,
756+ currentGeneration : 4 ,
757+ maxGeneration : 4 ,
758+ expectedMetricVals : map [string ]float64 {
759+ "pci.link.width.current" : 8 ,
760+ "pci.link.width.max" : 16 ,
761+ "pci.link.width.degraded" : 1 ,
762+ "pci.link.speed.current" : 15.753846153846155e9 ,
763+ "pci.link.speed.max" : 31.50769230769231e9 ,
764+ "pci.link.speed.degraded" : 1 ,
765+ },
766+ },
767+ "current width error" : {
768+ currentWidth : - 1 ,
769+ maxWidth : 16 ,
770+ currentGeneration : 4 ,
771+ maxGeneration : 4 ,
772+ expectedErr : "get current PCIe link width" ,
773+ },
774+ "max width error emits current width" : {
775+ currentWidth : 16 ,
776+ maxWidth : - 1 ,
777+ currentGeneration : 4 ,
778+ maxGeneration : 4 ,
779+ expectedMetricVals : map [string ]float64 {
780+ "pci.link.width.current" : 16 ,
781+ },
782+ expectedErr : "get max PCIe link width" ,
783+ },
784+ "current generation error emits width metrics" : {
785+ currentWidth : 8 ,
786+ maxWidth : 16 ,
787+ currentGeneration : - 1 ,
788+ maxGeneration : 4 ,
789+ expectedMetricVals : map [string ]float64 {
790+ "pci.link.width.current" : 8 ,
791+ "pci.link.width.max" : 16 ,
792+ "pci.link.width.degraded" : 1 ,
793+ },
794+ expectedErr : "get current PCIe link generation" ,
795+ },
796+ "max generation error emits current speed" : {
797+ currentWidth : 8 ,
798+ maxWidth : 16 ,
799+ currentGeneration : 4 ,
800+ maxGeneration : - 1 ,
801+ expectedMetricVals : map [string ]float64 {
802+ "pci.link.width.current" : 8 ,
803+ "pci.link.width.max" : 16 ,
804+ "pci.link.width.degraded" : 1 ,
805+ "pci.link.speed.current" : 15.753846153846155e9 ,
806+ },
807+ expectedErr : "get max PCIe link generation" ,
808+ },
809+ }
810+
811+ for name , test := range tests {
812+ t .Run (name , func (t * testing.T ) {
813+ device := setupMockDevice (t , testutil .WithCustomHook (func (device * mock.Device ) {
814+ device .GetCurrPcieLinkWidthFunc = func () (int , nvml.Return ) {
815+ if test .currentWidth == - 1 {
816+ return 0 , nvml .ERROR_UNKNOWN
817+ }
818+ return test .currentWidth , nvml .SUCCESS
819+ }
820+ device .GetMaxPcieLinkWidthFunc = func () (int , nvml.Return ) {
821+ if test .maxWidth == - 1 {
822+ return 0 , nvml .ERROR_UNKNOWN
823+ }
824+ return test .maxWidth , nvml .SUCCESS
825+ }
826+ device .GetCurrPcieLinkGenerationFunc = func () (int , nvml.Return ) {
827+ if test .currentGeneration == - 1 {
828+ return 0 , nvml .ERROR_UNKNOWN
829+ }
830+ return test .currentGeneration , nvml .SUCCESS
831+ }
832+ device .GetMaxPcieLinkGenerationFunc = func () (int , nvml.Return ) {
833+ if test .maxGeneration == - 1 {
834+ return 0 , nvml .ERROR_UNKNOWN
835+ }
836+ return test .maxGeneration , nvml .SUCCESS
837+ }
838+ }))
839+
840+ metricsOut , _ , err := pcieLinkMetrics (device )
841+ if test .expectedErr == "" {
842+ require .NoError (t , err )
843+ } else {
844+ require .ErrorContains (t , err , test .expectedErr )
845+ }
846+ require .Len (t , metricsOut , len (test .expectedMetricVals ))
847+ metricsByName := metricValuesToPointers (metricsOut )
848+ for metricName , expectedValue := range test .expectedMetricVals {
849+ metric := findMetric (metricsByName , metricName )
850+ require .NotNil (t , metric , "expected metric %s" , metricName )
851+ require .InDelta (t , expectedValue , metric .Value , 1e6 )
852+ require .Equal (t , metrics .GaugeType , metric .Type )
853+ }
854+ })
855+ }
856+ }
857+
730858func findAPICallByName (t * testing.T , apis []apiCallInfo , name string ) apiCallInfo {
731859 t .Helper ()
732860 for _ , api := range apis {
0 commit comments