master
go 661 lines 31.9 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package dcgm
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 )
11
12 type metricEntity string
13
14 const (
15 entityGPU metricEntity = "gpu"
16 entityMIG metricEntity = "mig"
17 entityNVLink metricEntity = "nvlink"
18 entityNVSwitch metricEntity = "nvswitch"
19 entityCPU metricEntity = "cpu"
20 entityCPUCore metricEntity = "cpu_core"
21 entityExporter metricEntity = "exporter"
22 )
23
24 type sampleKind uint8
25
26 const (
27 sampleGauge sampleKind = iota
28 sampleCounter
29 sampleUnsupported
30 )
31
32 type contextSpec struct {
33 ID string
34 Title string
35 Units string
36 Family string
37 Type collectorapi.ChartType
38 Priority int
39 }
40
41 type metricSpec struct {
42 Context contextSpec
43 DimName string
44 Scale float64
45 }
46
47 type groupSpec struct {
48 Suffix string
49 Title string
50 Units string
51 Family string
52 Type collectorapi.ChartType
53 }
54
55 var groupCatalog = []groupSpec{
56 {Suffix: "compute.utilization", Title: "Compute Utilization", Units: "percentage", Family: "compute", Type: collectorapi.Line},
57 {Suffix: "compute.activity", Title: "Compute Pipeline Activity", Units: "percentage", Family: "compute", Type: collectorapi.Line},
58 {Suffix: "compute.tensor.activity", Title: "Tensor Core Activity by Precision", Units: "percentage", Family: "compute", Type: collectorapi.Line},
59 {Suffix: "compute.media.activity", Title: "Media Engine Activity", Units: "percentage", Family: "compute", Type: collectorapi.Line},
60 {Suffix: "compute.cache.activity", Title: "Memory Cache Hit/Miss", Units: "events/s", Family: "compute", Type: collectorapi.Line},
61 {Suffix: "memory.utilization", Title: "Memory Utilization", Units: "percentage", Family: "memory", Type: collectorapi.Line},
62 {Suffix: "memory.usage", Title: "Memory Usage", Units: "bytes", Family: "memory", Type: collectorapi.Stacked},
63 {Suffix: "memory.capacity", Title: "Memory Capacity", Units: "bytes", Family: "memory", Type: collectorapi.Line},
64 {Suffix: "memory.bar1_usage", Title: "BAR1 Memory Usage", Units: "bytes", Family: "memory", Type: collectorapi.Stacked},
65 {Suffix: "memory.bar1_capacity", Title: "BAR1 Memory Capacity", Units: "bytes", Family: "memory", Type: collectorapi.Line},
66 {Suffix: "memory.ecc_errors", Title: "ECC Errors", Units: "errors", Family: "memory", Type: collectorapi.Line},
67 {Suffix: "memory.ecc_error_rate", Title: "ECC Error Rate", Units: "errors/s", Family: "memory", Type: collectorapi.Line},
68 {Suffix: "memory.page_retirements", Title: "Retired Memory Pages", Units: "pages/s", Family: "memory", Type: collectorapi.Line},
69 {Suffix: "reliability.row_remap_status", Title: "Row Remap Status", Units: "state", Family: "reliability", Type: collectorapi.Line},
70 {Suffix: "reliability.row_remap_events", Title: "Row Remap Events", Units: "rows/s", Family: "reliability", Type: collectorapi.Line},
71 {Suffix: "reliability.memory_health", Title: "Memory Health", Units: "state", Family: "reliability", Type: collectorapi.Line},
72 {Suffix: "reliability.recovery_action", Title: "Recovery Action", Units: "state", Family: "reliability", Type: collectorapi.Line},
73 {Suffix: "clock.frequency", Title: "Clock Frequency", Units: "MHz", Family: "clock", Type: collectorapi.Line},
74 {Suffix: "throttle.reasons", Title: "Throttle Reasons", Units: "bitmask", Family: "throttle", Type: collectorapi.Line},
75 {Suffix: "thermal.temperature", Title: "Temperature", Units: "Celsius", Family: "thermal", Type: collectorapi.Line},
76 {Suffix: "thermal.fan_speed", Title: "Fan Speed", Units: "percentage", Family: "thermal", Type: collectorapi.Line},
77 {Suffix: "power.usage", Title: "Power Usage", Units: "Watts", Family: "power", Type: collectorapi.Line},
78 {Suffix: "power.energy", Title: "Energy Consumption Rate", Units: "mJ/s", Family: "power", Type: collectorapi.Line},
79 {Suffix: "power.profiles", Title: "Power Profiles", Units: "state", Family: "power", Type: collectorapi.Line},
80 {Suffix: "power.smoothing", Title: "Power Smoothing", Units: "value", Family: "power", Type: collectorapi.Line},
81 {Suffix: "throttle.violations", Title: "Throttle Violation Duration", Units: "milliseconds/s", Family: "throttle", Type: collectorapi.Line},
82 {Suffix: "interconnect.total.throughput", Title: "Interconnect Total Throughput", Units: "bytes/s", Family: "interconnect/overview", Type: collectorapi.Area},
83 {Suffix: "interconnect.pcie.throughput", Title: "PCIe Throughput", Units: "bytes/s", Family: "interconnect/pcie", Type: collectorapi.Area},
84 {Suffix: "interconnect.nvlink.throughput", Title: "NVLink Throughput", Units: "bytes/s", Family: "interconnect/nvlink", Type: collectorapi.Area},
85 {Suffix: "interconnect.throughput", Title: "Interconnect Throughput", Units: "bytes/s", Family: "interconnect/overview", Type: collectorapi.Area},
86 {Suffix: "interconnect.pcie.traffic", Title: "PCIe Traffic", Units: "events/s", Family: "interconnect/pcie", Type: collectorapi.Line},
87 {Suffix: "interconnect.nvlink.traffic", Title: "NVLink Traffic", Units: "events/s", Family: "interconnect/nvlink", Type: collectorapi.Line},
88 {Suffix: "interconnect.traffic", Title: "Interconnect Traffic", Units: "events/s", Family: "interconnect/overview", Type: collectorapi.Line},
89 {Suffix: "interconnect.pcie.ber", Title: "PCIe Bit Error Rate", Units: "ratio", Family: "interconnect/pcie", Type: collectorapi.Line},
90 {Suffix: "interconnect.nvlink.ber", Title: "NVLink Bit Error Rate", Units: "ratio", Family: "interconnect/nvlink", Type: collectorapi.Line},
91 {Suffix: "interconnect.ber", Title: "Interconnect Bit Error Rate", Units: "ratio", Family: "interconnect/overview", Type: collectorapi.Line},
92 {Suffix: "interconnect.pcie.link.generation", Title: "PCIe Link Generation", Units: "generation", Family: "interconnect/pcie", Type: collectorapi.Line},
93 {Suffix: "interconnect.pcie.link.width", Title: "PCIe Link Width", Units: "lanes", Family: "interconnect/pcie", Type: collectorapi.Line},
94 {Suffix: "interconnect.pcie.state", Title: "PCIe State", Units: "state", Family: "interconnect/pcie", Type: collectorapi.Line},
95 {Suffix: "interconnect.nvlink.state", Title: "NVLink State", Units: "state", Family: "interconnect/nvlink", Type: collectorapi.Line},
96 {Suffix: "interconnect.state", Title: "Interconnect State", Units: "state", Family: "interconnect/overview", Type: collectorapi.Line},
97 {Suffix: "interconnect.nvlink.congestion", Title: "NVLink Congestion", Units: "events/s", Family: "interconnect/nvlink", Type: collectorapi.Line},
98 {Suffix: "interconnect.congestion", Title: "Interconnect Congestion", Units: "events/s", Family: "interconnect/overview", Type: collectorapi.Line},
99 {Suffix: "interconnect.fabric", Title: "Fabric State", Units: "state", Family: "interconnect/overview", Type: collectorapi.Line},
100 {Suffix: "interconnect.pcie.errors", Title: "PCIe Errors", Units: "errors", Family: "interconnect/pcie", Type: collectorapi.Line},
101 {Suffix: "interconnect.pcie.error_rate", Title: "PCIe Error Rate", Units: "errors/s", Family: "interconnect/pcie", Type: collectorapi.Line},
102 {Suffix: "interconnect.nvlink.errors", Title: "NVLink Errors", Units: "errors", Family: "interconnect/nvlink", Type: collectorapi.Line},
103 {Suffix: "interconnect.nvlink.error_rate", Title: "NVLink Error Rate", Units: "errors/s", Family: "interconnect/nvlink", Type: collectorapi.Line},
104 {Suffix: "interconnect.errors", Title: "Interconnect Errors", Units: "errors", Family: "interconnect/overview", Type: collectorapi.Line},
105 {Suffix: "interconnect.error_rate", Title: "Interconnect Error Rate", Units: "errors/s", Family: "interconnect/overview", Type: collectorapi.Line},
106 {Suffix: "interconnect.connectx.status", Title: "ConnectX Status", Units: "state", Family: "interconnect/pcie", Type: collectorapi.Line},
107 {Suffix: "interconnect.connectx.link", Title: "ConnectX Link", Units: "value", Family: "interconnect/pcie", Type: collectorapi.Line},
108 {Suffix: "interconnect.connectx.temperature", Title: "ConnectX Temperature", Units: "Celsius", Family: "interconnect/pcie", Type: collectorapi.Line},
109 {Suffix: "interconnect.connectx.errors", Title: "ConnectX Errors", Units: "errors/s", Family: "interconnect/pcie", Type: collectorapi.Line},
110 {Suffix: "interconnect.nvswitch.status", Title: "NVSwitch Status", Units: "state", Family: "interconnect/nvlink", Type: collectorapi.Line},
111 {Suffix: "interconnect.nvswitch.topology", Title: "NVSwitch Topology", Units: "value", Family: "interconnect/nvlink", Type: collectorapi.Line},
112 {Suffix: "interconnect.nvswitch.throughput", Title: "NVSwitch Throughput", Units: "bytes/s", Family: "interconnect/nvlink", Type: collectorapi.Area},
113 {Suffix: "interconnect.nvswitch.latency", Title: "NVSwitch Link Latency", Units: "events/s", Family: "interconnect/nvlink", Type: collectorapi.Line},
114 {Suffix: "interconnect.nvswitch.errors", Title: "NVSwitch Errors", Units: "errors/s", Family: "interconnect/nvlink", Type: collectorapi.Line},
115 {Suffix: "interconnect.nvswitch.temperature", Title: "NVSwitch Temperature", Units: "Celsius", Family: "interconnect/nvlink", Type: collectorapi.Line},
116 {Suffix: "interconnect.nvswitch.power", Title: "NVSwitch Power", Units: "Watts", Family: "interconnect/nvlink", Type: collectorapi.Line},
117 {Suffix: "interconnect.nvswitch.current", Title: "NVSwitch Current", Units: "value", Family: "interconnect/nvlink", Type: collectorapi.Line},
118 {Suffix: "interconnect.nvswitch.voltage", Title: "NVSwitch Voltage", Units: "mV", Family: "interconnect/nvlink", Type: collectorapi.Line},
119 {Suffix: "interconnect.connectx.error_status", Title: "ConnectX Error Status", Units: "state", Family: "interconnect/pcie", Type: collectorapi.Line},
120 {Suffix: "reliability.xid", Title: "XID Errors", Units: "code", Family: "reliability", Type: collectorapi.Line},
121 {Suffix: "health.status", Title: "Health Status", Units: "state", Family: "health", Type: collectorapi.Line},
122 {Suffix: "state.performance", Title: "Performance State", Units: "state", Family: "state", Type: collectorapi.Line},
123 {Suffix: "state.virtualization", Title: "Virtualization State", Units: "state", Family: "state", Type: collectorapi.Line},
124 {Suffix: "state.configuration", Title: "Configuration State", Units: "state", Family: "state", Type: collectorapi.Line},
125 {Suffix: "virtualization.vgpu.license", Title: "vGPU License", Units: "state", Family: "virtualization", Type: collectorapi.Line},
126 {Suffix: "virtualization.vgpu.type", Title: "vGPU Type", Units: "value", Family: "virtualization", Type: collectorapi.Line},
127 {Suffix: "virtualization.vgpu.instance", Title: "vGPU Instance", Units: "value", Family: "virtualization", Type: collectorapi.Line},
128 {Suffix: "virtualization.vgpu.vm", Title: "vGPU VM", Units: "value", Family: "virtualization", Type: collectorapi.Line},
129 {Suffix: "virtualization.vgpu.memory", Title: "vGPU Memory", Units: "bytes", Family: "virtualization", Type: collectorapi.Line},
130 {Suffix: "virtualization.vgpu.frame_rate", Title: "vGPU Frame Rate", Units: "fps", Family: "virtualization", Type: collectorapi.Line},
131 {Suffix: "virtualization.vgpu.utilization", Title: "vGPU Utilization", Units: "percentage", Family: "virtualization", Type: collectorapi.Line},
132 {Suffix: "virtualization.vgpu.sessions", Title: "vGPU Sessions", Units: "value", Family: "virtualization", Type: collectorapi.Line},
133 {Suffix: "virtualization.vgpu.software", Title: "vGPU Software", Units: "value", Family: "virtualization", Type: collectorapi.Line},
134 {Suffix: "workload.sessions", Title: "Workload Sessions", Units: "value", Family: "workload", Type: collectorapi.Line},
135 {Suffix: "cpu.utilization", Title: "CPU Utilization", Units: "percentage", Family: "cpu", Type: collectorapi.Line},
136 {Suffix: "cpu.temperature", Title: "CPU Temperature", Units: "Celsius", Family: "cpu", Type: collectorapi.Line},
137 {Suffix: "cpu.power", Title: "CPU Power", Units: "Watts", Family: "cpu", Type: collectorapi.Line},
138 {Suffix: "cpu.info", Title: "CPU Information", Units: "value", Family: "cpu", Type: collectorapi.Line},
139 {Suffix: "diagnostics.status", Title: "Diagnostics Status", Units: "state", Family: "diagnostics", Type: collectorapi.Line},
140 {Suffix: "diagnostics.results", Title: "Diagnostics Results", Units: "state", Family: "diagnostics", Type: collectorapi.Line},
141 {Suffix: "inventory.identity", Title: "Inventory Identity", Units: "value", Family: "inventory", Type: collectorapi.Line},
142 {Suffix: "inventory.software", Title: "Software and Firmware", Units: "value", Family: "inventory", Type: collectorapi.Line},
143 {Suffix: "inventory.platform", Title: "Platform Inventory", Units: "value", Family: "inventory", Type: collectorapi.Line},
144 {Suffix: "topology.affinity", Title: "Topology and Affinity", Units: "value", Family: "topology", Type: collectorapi.Line},
145 {Suffix: "capability.support", Title: "Capability Support", Units: "state", Family: "capability", Type: collectorapi.Line},
146 {Suffix: "internal.boundary", Title: "Internal Boundary Fields", Units: "state", Family: "internal", Type: collectorapi.Line},
147 {Suffix: "state", Title: "Device State", Units: "state", Family: "state", Type: collectorapi.Line},
148 {Suffix: "other.gauge", Title: "Other Metrics", Units: "value", Family: "other", Type: collectorapi.Line},
149 {Suffix: "other.counter", Title: "Other Metric Rate", Units: "events/s", Family: "other", Type: collectorapi.Line},
150 }
151
152 var contextCatalog = buildContextCatalog()
153
154 func buildContextCatalog() map[string]contextSpec {
155 entities := []metricEntity{entityGPU, entityMIG, entityNVLink, entityNVSwitch, entityCPU, entityCPUCore, entityExporter}
156 catalog := make(map[string]contextSpec, len(entities)*len(groupCatalog))
157
158 prio := collectorapi.Priority
159 for _, entity := range entities {
160 for _, group := range groupCatalog {
161 ctx := fmt.Sprintf("dcgm.%s.%s", entity, group.Suffix)
162 catalog[ctx] = contextSpec{
163 ID: ctx,
164 Title: fmt.Sprintf("%s %s", entityDisplayName(entity), group.Title),
165 Units: group.Units,
166 Family: fmt.Sprintf("%s %s", entityFamilyPrefix(entity), group.Family),
167 Type: group.Type,
168 Priority: prio,
169 }
170 prio += 10
171 }
172 }
173
174 return catalog
175 }
176
177 func entityDisplayName(entity metricEntity) string {
178 switch entity {
179 case entityGPU:
180 return "GPU"
181 case entityMIG:
182 return "MIG"
183 case entityNVLink:
184 return "NVLink"
185 case entityNVSwitch:
186 return "NVSwitch"
187 case entityCPU:
188 return "CPU"
189 case entityCPUCore:
190 return "CPU Core"
191 default:
192 return "Exporter"
193 }
194 }
195
196 func entityFamilyPrefix(entity metricEntity) string {
197 switch entity {
198 case entityCPUCore:
199 return "cpu core"
200 default:
201 return string(entity)
202 }
203 }
204
205 func classifyMetric(entity metricEntity, metricName, help string, typ sampleKind) metricSpec {
206 group := classifyMetricGroup(entity, metricName, typ)
207 ctxID := fmt.Sprintf("dcgm.%s.%s", entity, group)
208 spec, ok := contextCatalog[ctxID]
209 if !ok {
210 fallback := "other.gauge"
211 if typ == sampleCounter {
212 fallback = "other.counter"
213 }
214 spec = contextCatalog[fmt.Sprintf("dcgm.%s.%s", entity, fallback)]
215 }
216
217 return metricSpec{
218 Context: spec,
219 DimName: metricDimensionName(metricName),
220 Scale: metricScale(metricName, help, spec),
221 }
222 }
223
224 func classifyMetricGroup(entity metricEntity, metricName string, typ sampleKind) string {
225 name := strings.ToUpper(metricName)
226
227 switch {
228 case strings.HasPrefix(name, "DCGM_FI_INTERNAL_FIELDS_"),
229 strings.Contains(name, "FIRST_"),
230 strings.Contains(name, "LAST_"):
231 return "internal.boundary"
232 case !strings.Contains(name, "VGPU_") && containsAny(name, "GPU_UTIL", "MEM_COPY_UTIL", "ENC_UTIL", "DEC_UTIL"):
233 return "compute.utilization"
234 case containsAny(name, "TENSOR_HMMA", "TENSOR_IMMA", "TENSOR_DFMA"):
235 return "compute.tensor.activity"
236 case containsAny(name, "NVDEC", "NVJPG", "NVOFA"):
237 return "compute.media.activity"
238 case containsAny(name, "HOSTMEM_CACHE", "PEERMEM_CACHE"):
239 return "compute.cache.activity"
240 case containsAny(name,
241 "SM_ACTIVE",
242 "SM_OCCUPANCY",
243 "GR_ENGINE_ACTIVE",
244 "PIPE_",
245 "DRAM_ACTIVE",
246 "TENSOR",
247 "FP16",
248 "FP32",
249 "FP64",
250 "INTEGER_ACTIVE",
251 ):
252 return "compute.activity"
253 case strings.Contains(name, "FB_USED_PERCENT"):
254 return "memory.utilization"
255 case strings.Contains(name, "BAR1_TOTAL"):
256 return "memory.bar1_capacity"
257 case strings.Contains(name, "BAR1"):
258 return "memory.bar1_usage"
259 case strings.Contains(name, "FB_TOTAL"):
260 return "memory.capacity"
261 case containsAny(name, "FB_FREE", "FB_USED", "FB_RESERVED", "FRAME_BUFFER"):
262 return "memory.usage"
263 case strings.Contains(name, "ECC_"):
264 if typ == sampleCounter {
265 return "memory.ecc_error_rate"
266 }
267 return "memory.ecc_errors"
268 case strings.Contains(name, "RETIRED_"):
269 return "memory.page_retirements"
270 case strings.Contains(name, "ROW_REMAP_FAILURE"):
271 return "reliability.row_remap_status"
272 case strings.Contains(name, "ROW_REMAP_PENDING"):
273 return "reliability.row_remap_status"
274 case strings.Contains(name, "REMAPPED_ROWS"):
275 return "reliability.row_remap_events"
276 case containsAny(name, "BANKS_REMAP", "MEMORY_UNREPAIRABLE_FLAG", "THRESHOLD_SRM"):
277 return "reliability.memory_health"
278 case strings.Contains(name, "GET_GPU_RECOVERY_ACTION"):
279 return "reliability.recovery_action"
280 case containsAny(name, "HEALTH_STATUS", "P2P_STATUS", "CLOCK_EVENTS_COUNT", "IMEX_DOMAIN_STATUS", "IMEX_DAEMON_STATUS", "BIND_UNBIND_EVENT"):
281 return "health.status"
282 case strings.Contains(name, "CLOCKS_EVENT_REASONS"):
283 return "throttle.reasons"
284 case strings.Contains(name, "CLOCKS_EVENT_REASON"):
285 return "throttle.violations"
286 case strings.Contains(name, "CLOCK_THROTTLE_REASONS"):
287 return "throttle.reasons"
288 case strings.Contains(name, "PSTATE"):
289 return "state.performance"
290 case containsAny(name, "VIRTUAL_MODE", "MIG_MODE"):
291 return "state.virtualization"
292 case containsAny(name, "COMPUTE_MODE", "PERSISTENCE_MODE", "AUTOBOOST", "SYNC_BOOST"):
293 return "state.configuration"
294 case containsAny(name, "GPU_TEMP", "MEMORY_TEMP", "SLOWDOWN_TEMP", "MAX_OP_TEMP", "SHUTDOWN_TEMP", "TEMPERATURE"):
295 return "thermal.temperature"
296 case strings.Contains(name, "FAN_SPEED"):
297 return "thermal.fan_speed"
298 case strings.Contains(name, "TOTAL_ENERGY"):
299 return "power.energy"
300 case containsAny(name, "POWER_PROFILE_MASK"):
301 return "power.profiles"
302 case containsAny(name, "PWR_SMOOTHING"):
303 return "power.smoothing"
304 case containsAny(name, "POWER_USAGE", "POWER_MGMT_LIMIT", "POWER_MANAGEMENT_LIMIT", "ENFORCED_POWER_LIMIT"):
305 return "power.usage"
306 case strings.Contains(name, "VIOLATION"):
307 return "throttle.violations"
308 case strings.Contains(name, "PCIE") && strings.Contains(name, "LINK_GEN"):
309 return "interconnect.pcie.link.generation"
310 case strings.Contains(name, "PCIE") && strings.Contains(name, "LINK_WIDTH"):
311 return "interconnect.pcie.link.width"
312 case strings.Contains(name, "NVSWITCH"):
313 return classifyNVSwitchGroup(name, typ)
314 case strings.Contains(name, "CONNECTX"):
315 return classifyConnectXGroup(name, typ)
316 case strings.Contains(name, "C2C_"):
317 return classifyC2CGroup(name, typ)
318 case strings.Contains(name, "PCIE") || strings.Contains(name, "NVLINK") || strings.Contains(name, "P2P_") || strings.Contains(name, "FABRIC_"):
319 return classifyInterconnectGroup(entity, name, typ)
320 case strings.Contains(name, "XID"):
321 return "reliability.xid"
322 case strings.Contains(name, "DIAG_"):
323 if strings.HasSuffix(name, "_STATUS") {
324 return "diagnostics.status"
325 }
326 return "diagnostics.results"
327 case strings.Contains(name, "CPU_UTIL"):
328 return "cpu.utilization"
329 case strings.Contains(name, "CPU_TEMP"):
330 return "cpu.temperature"
331 case containsAny(name, "CPU_POWER", "MODULE_POWER", "SYSIO_POWER"):
332 return "cpu.power"
333 case containsAny(name, "CPU_VENDOR", "CPU_MODEL"):
334 return "cpu.info"
335 case containsAny(name, "CPU_AFFINITY", "MEM_AFFINITY", "GPU_TOPOLOGY", "PCI_BUSID", "PCI_COMBINED_ID", "PCI_SUBSYS_ID"):
336 return "topology.affinity"
337 case strings.Contains(name, "VGPU_"):
338 return classifyVGPUGroup(name)
339 case containsAny(name, "ACCOUNTING_DATA", "FBC_", "ENC_STATS"):
340 return "workload.sessions"
341 case containsAny(name, "SUPPORTED_", "CREATABLE_", "CUDA_COMPUTE_CAPABILITY", "CC_MODE", "GPM_SUPPORT", "MIG_ATTRIBUTES", "MIG_GI_INFO", "MIG_CI_INFO", "MIG_MAX_SLICES"):
342 return "capability.support"
343 case containsAny(name, "DRIVER_VERSION", "NVML_VERSION", "VBIOS_VERSION", "INFOROM", "OEM_INFOROM", "PROCESS_NAME"):
344 return "inventory.software"
345 case containsAny(name, "PLATFORM_", "CHASSIS", "HOST_ID", "TRAY_INDEX", "MODULE_ID", "INFINIBAND_GUID"):
346 return "inventory.platform"
347 case containsAny(name, "DEV_NAME", "BRAND", "SERIAL", "UUID", "MINOR_NUMBER", "NVML_INDEX", "CUDA_VISIBLE_DEVICES_STR", "DEV_COUNT"):
348 return "inventory.identity"
349 case strings.Contains(name, "CLOCK"):
350 return "clock.frequency"
351 default:
352 if typ == sampleCounter {
353 return "other.counter"
354 }
355 return "other.gauge"
356 }
357 }
358
359 func classifyInterconnectGroup(entity metricEntity, name string, typ sampleKind) string {
360 switch {
361 case containsAny(name, "P2P_STATUS"):
362 return "health.status"
363 case containsAny(name, "FABRIC_"):
364 return "interconnect.fabric"
365 case strings.Contains(name, "PCIE") && containsAny(name, "BYTES", "THROUGHPUT", "BANDWIDTH"):
366 return "interconnect.pcie.throughput"
367 case strings.Contains(name, "NVLINK") && containsAny(name, "BYTES", "THROUGHPUT", "BANDWIDTH"):
368 if entity == entityNVLink {
369 return "interconnect.throughput"
370 }
371 return "interconnect.nvlink.throughput"
372 case containsAny(name, "XMIT_WAIT"):
373 if strings.Contains(name, "NVLINK") {
374 if entity == entityNVLink {
375 return "interconnect.congestion"
376 }
377 return "interconnect.nvlink.congestion"
378 }
379 return "interconnect.congestion"
380 case containsAny(name, "BER"):
381 if strings.Contains(name, "PCIE") {
382 return "interconnect.pcie.ber"
383 }
384 if strings.Contains(name, "NVLINK") {
385 if entity == entityNVLink {
386 return "interconnect.ber"
387 }
388 return "interconnect.nvlink.ber"
389 }
390 return "interconnect.ber"
391 case containsAny(name, "PACKETS", "CODES"):
392 if strings.Contains(name, "PCIE") {
393 return "interconnect.pcie.traffic"
394 }
395 if strings.Contains(name, "NVLINK") {
396 if entity == entityNVLink {
397 return "interconnect.traffic"
398 }
399 return "interconnect.nvlink.traffic"
400 }
401 return "interconnect.traffic"
402 case containsAny(name, "BYTES", "THROUGHPUT", "BANDWIDTH"):
403 return "interconnect.throughput"
404 case containsAny(name, "ERROR", "CRC", "REPLAY", "RECOVERY", "DISCARD", "FEC", "UNCORRECTABLE", "INTEGRITY"):
405 if strings.Contains(name, "PCIE") {
406 if typ == sampleCounter {
407 return "interconnect.pcie.error_rate"
408 }
409 return "interconnect.pcie.errors"
410 }
411 if strings.Contains(name, "NVLINK") {
412 if entity == entityNVLink {
413 if typ == sampleCounter {
414 return "interconnect.error_rate"
415 }
416 return "interconnect.errors"
417 }
418 if typ == sampleCounter {
419 return "interconnect.nvlink.error_rate"
420 }
421 return "interconnect.nvlink.errors"
422 }
423 if typ == sampleCounter {
424 return "interconnect.error_rate"
425 }
426 return "interconnect.errors"
427 case strings.Contains(name, "PCIE") && strings.Contains(name, "RESULT"):
428 return "interconnect.pcie.state"
429 case containsAny(name, "STATE", "STATUS", "POWER_STATE", "LINK_COUNT"):
430 if strings.Contains(name, "PCIE") {
431 return "interconnect.pcie.state"
432 }
433 if strings.Contains(name, "NVLINK") {
434 if entity == entityNVLink {
435 return "interconnect.state"
436 }
437 return "interconnect.nvlink.state"
438 }
439 return "interconnect.state"
440 default:
441 return "interconnect.state"
442 }
443 }
444
445 func classifyNVSwitchGroup(name string, typ sampleKind) string {
446 switch {
447 case containsAny(name, "LINK_LATENCY_"):
448 return "interconnect.nvswitch.latency"
449 case containsAny(name, "THROUGHPUT"):
450 return "interconnect.nvswitch.throughput"
451 case containsAny(name, "ERROR", "FATAL", "NON_FATAL", "CRC", "REPLAY", "RECOVERY", "FLIT"):
452 if typ == sampleCounter {
453 return "interconnect.nvswitch.errors"
454 }
455 return "interconnect.nvswitch.errors"
456 case containsAny(name, "TEMPERATURE"):
457 return "interconnect.nvswitch.temperature"
458 case containsAny(name, "POWER_"):
459 return "interconnect.nvswitch.power"
460 case containsAny(name, "CURRENT_"):
461 return "interconnect.nvswitch.current"
462 case containsAny(name, "VOLTAGE"):
463 return "interconnect.nvswitch.voltage"
464 case containsAny(name, "PCIE_", "PHYS_ID", "DEVICE_UUID", "LINK_ID", "LINK_SID", "DEVICE_LINK_ID", "REMOTE_PCIE_"):
465 return "interconnect.nvswitch.topology"
466 default:
467 return "interconnect.nvswitch.status"
468 }
469 }
470
471 func classifyConnectXGroup(name string, typ sampleKind) string {
472 switch {
473 case containsAny(name, "TEMPERATURE"):
474 return "interconnect.connectx.temperature"
475 case containsAny(name, "ERR", "ERROR"):
476 if typ == sampleCounter {
477 return "interconnect.connectx.errors"
478 }
479 return "interconnect.connectx.error_status"
480 case containsAny(name, "LINK_SPEED", "LINK_WIDTH", "PCIE"):
481 return "interconnect.connectx.link"
482 default:
483 return "interconnect.connectx.status"
484 }
485 }
486
487 func classifyC2CGroup(name string, typ sampleKind) string {
488 switch {
489 case containsAny(name, "RX_", "TX_", "BANDWIDTH"):
490 return "interconnect.throughput"
491 case containsAny(name, "ERROR", "REPLAY", "FEC", "BER", "INTR", "DISCARD", "RECOVERY"):
492 if typ == sampleCounter {
493 return "interconnect.error_rate"
494 }
495 return "interconnect.errors"
496 default:
497 return "interconnect.state"
498 }
499 }
500
501 func classifyVGPUGroup(name string) string {
502 switch {
503 case containsAny(name, "VGPU_LICENSE_STATUS", "TYPE_LICENSE", "INSTANCE_LICENSE_STATE"):
504 return "virtualization.vgpu.license"
505 case containsAny(name, "VGPU_TYPE", "TYPE_CLASS", "TYPE_INFO", "TYPE_NAME"):
506 return "virtualization.vgpu.type"
507 case containsAny(name, "VGPU_INSTANCE_IDS", "VGPU_UUID", "VGPU_PCI_ID"):
508 return "virtualization.vgpu.instance"
509 case containsAny(name, "VGPU_VM_"):
510 return "virtualization.vgpu.vm"
511 case containsAny(name, "VGPU_MEMORY_USAGE"):
512 return "virtualization.vgpu.memory"
513 case containsAny(name, "VGPU_FRAME_RATE_LIMIT"):
514 return "virtualization.vgpu.frame_rate"
515 case containsAny(name, "VGPU_UTILIZATIONS", "PER_PROCESS_UTILIZATION"):
516 return "virtualization.vgpu.utilization"
517 case containsAny(name, "VGPU_ENC_", "VGPU_FBC_"):
518 return "virtualization.vgpu.sessions"
519 case containsAny(name, "VGPU_DRIVER_VERSION"):
520 return "virtualization.vgpu.software"
521 default:
522 return "virtualization.vgpu.instance"
523 }
524 }
525
526 func metricScale(metricName, help string, spec contextSpec) float64 {
527 name := strings.ToUpper(metricName)
528 h := strings.ToLower(help)
529
530 if spec.ID == "" {
531 return 1
532 }
533
534 if strings.HasSuffix(spec.ID, ".compute.activity") ||
535 strings.HasSuffix(spec.ID, ".compute.tensor.activity") ||
536 strings.HasSuffix(spec.ID, ".compute.media.activity") {
537 return 100
538 }
539
540 if strings.HasSuffix(spec.ID, ".memory.utilization") {
541 return 100
542 }
543
544 if (strings.HasSuffix(spec.ID, ".memory.usage") ||
545 strings.HasSuffix(spec.ID, ".memory.capacity") ||
546 strings.HasSuffix(spec.ID, ".memory.bar1_usage") ||
547 strings.HasSuffix(spec.ID, ".memory.bar1_capacity")) &&
548 (containsAny(name, "FB_", "BAR1") || strings.Contains(h, "mib") || strings.Contains(h, " mb")) {
549 return 1024 * 1024
550 }
551
552 if strings.HasSuffix(spec.ID, ".virtualization.vgpu.memory") &&
553 (strings.Contains(h, "mib") || strings.Contains(h, " mb")) {
554 return 1024 * 1024
555 }
556
557 if strings.HasSuffix(spec.ID, ".virtualization.vgpu.utilization") && strings.Contains(h, "ratio") {
558 return 100
559 }
560
561 if strings.HasSuffix(spec.ID, ".throttle.violations") && strings.Contains(name, "VIOLATION") {
562 return 1.0 / 1e6 // ns => ms
563 }
564 if strings.HasSuffix(spec.ID, ".throttle.violations") && strings.Contains(name, "CLOCKS_EVENT_REASON") {
565 return 1.0 / 1e6 // ns => ms
566 }
567
568 return 1
569 }
570
571 func metricDimensionName(metricName string) string {
572 name := strings.ToUpper(metricName)
573 if v, ok := metricDimensionAliases[name]; ok {
574 return v
575 }
576
577 for _, pfx := range []string{
578 "DCGM_FI_DEV_",
579 "DCGM_FI_PROF_",
580 "DCGM_FI_",
581 "DCGM_EXP_",
582 "DCGM_",
583 } {
584 name = strings.TrimPrefix(name, pfx)
585 }
586
587 name = strings.TrimSuffix(name, "_TOTAL")
588 name = strings.TrimSuffix(name, "_COUNT")
589 name = strings.TrimSuffix(name, "_VALUE")
590 name = strings.ToLower(name)
591
592 return sanitizeID(name)
593 }
594
595 func containsAny(s string, values ...string) bool {
596 for _, v := range values {
597 if strings.Contains(s, v) {
598 return true
599 }
600 }
601 return false
602 }
603
604 var metricDimensionAliases = map[string]string{
605 "DCGM_FI_DEV_GPU_UTIL": "gpu",
606 "DCGM_FI_DEV_MEM_COPY_UTIL": "memory_copy",
607 "DCGM_FI_DEV_ENC_UTIL": "encoder",
608 "DCGM_FI_DEV_DEC_UTIL": "decoder",
609 "DCGM_FI_DEV_GPU_TEMP": "gpu",
610 "DCGM_FI_DEV_MEMORY_TEMP": "memory",
611 "DCGM_FI_DEV_SM_CLOCK": "sm",
612 "DCGM_FI_DEV_MEM_CLOCK": "memory",
613 "DCGM_FI_DEV_POWER_USAGE": "draw",
614 "DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION": "total",
615 "DCGM_FI_DEV_PCIE_REPLAY_COUNTER": "pcie_replay",
616 "DCGM_FI_DEV_XID_ERRORS": "xid",
617 "DCGM_FI_DEV_POWER_VIOLATION": "power_violation",
618 "DCGM_FI_DEV_THERMAL_VIOLATION": "thermal_violation",
619 "DCGM_FI_DEV_SYNC_BOOST_VIOLATION": "sync_boost_violation",
620 "DCGM_FI_DEV_BOARD_LIMIT_VIOLATION": "board_limit_violation",
621 "DCGM_FI_DEV_LOW_UTIL_VIOLATION": "low_utilization_violation",
622 "DCGM_FI_DEV_RELIABILITY_VIOLATION": "reliability_violation",
623 "DCGM_FI_DEV_FB_FREE": "free",
624 "DCGM_FI_DEV_FB_TOTAL": "total",
625 "DCGM_FI_DEV_FB_USED": "used",
626 "DCGM_FI_DEV_FB_RESERVED": "reserved",
627 "DCGM_FI_DEV_FB_USED_PERCENT": "used_percent",
628 "DCGM_FI_DEV_BAR1_TOTAL": "total",
629 "DCGM_FI_DEV_BAR1_USED": "used",
630 "DCGM_FI_DEV_BAR1_FREE": "free",
631 "DCGM_FI_DEV_FAN_SPEED": "fan_speed",
632 "DCGM_FI_DEV_ENFORCED_POWER_LIMIT": "enforced_limit",
633 "DCGM_FI_DEV_PCIE_LINK_GEN": "link_gen",
634 "DCGM_FI_DEV_PCIE_MAX_LINK_GEN": "max_link_gen",
635 "DCGM_FI_DEV_PCIE_LINK_WIDTH": "link_width",
636 "DCGM_FI_DEV_PCIE_MAX_LINK_WIDTH": "max_link_width",
637 "DCGM_FI_DEV_CLOCK_THROTTLE_REASONS": "reasons",
638 "DCGM_FI_DEV_CLOCKS_EVENT_REASON_SW_POWER_CAP_NS": "sw_power_cap",
639 "DCGM_FI_DEV_CLOCKS_EVENT_REASON_HW_THERM_SLOWDOWN_NS": "hw_therm_slowdown",
640 "DCGM_FI_DEV_CLOCKS_EVENT_REASON_SW_THERM_SLOWDOWN_NS": "sw_therm_slowdown",
641 "DCGM_FI_DEV_CLOCKS_EVENT_REASON_HW_POWER_BRAKE_SLOWDOWN_NS": "hw_power_brake_slowdown",
642 "DCGM_FI_DEV_CLOCKS_EVENT_REASON_SYNC_BOOST_NS": "sync_boost",
643 "DCGM_FI_DEV_UNCORRECTABLE_REMAPPED_ROWS": "uncorrectable_remapped_rows",
644 "DCGM_FI_DEV_CORRECTABLE_REMAPPED_ROWS": "correctable_remapped_rows",
645 "DCGM_FI_DEV_ROW_REMAP_FAILURE": "row_remap_failure",
646 "DCGM_FI_DEV_ROW_REMAP_PENDING": "row_remap_pending",
647 "DCGM_FI_PROF_SM_ACTIVE": "sm_active",
648 "DCGM_FI_PROF_SM_OCCUPANCY": "sm_occupancy",
649 "DCGM_FI_PROF_GR_ENGINE_ACTIVE": "graphics_engine_active",
650 "DCGM_FI_PROF_PIPE_TENSOR_ACTIVE": "tensor",
651 "DCGM_FI_PROF_DRAM_ACTIVE": "dram",
652 "DCGM_FI_PROF_PIPE_FP64_ACTIVE": "fp64",
653 "DCGM_FI_PROF_PIPE_FP32_ACTIVE": "fp32",
654 "DCGM_FI_PROF_PIPE_FP16_ACTIVE": "fp16",
655 "DCGM_FI_PROF_PCIE_TX_BYTES": "pcie_tx",
656 "DCGM_FI_PROF_PCIE_RX_BYTES": "pcie_rx",
657 "DCGM_FI_PROF_PIPE_INT_ACTIVE": "integer",
658 "DCGM_FI_PROF_PIPE_TENSOR_DFMA_ACTIVE": "tensor_dfma",
659 "DCGM_FI_PROF_PIPE_TENSOR_HMMA_ACTIVE": "tensor_hmma",
660 "DCGM_FI_PROF_PIPE_TENSOR_IMMA_ACTIVE": "tensor_imma",
661 }