Files
logpile/internal/parser/vendors/nvidia/inventory_log.go
Michael Chus 77e25ddc02 Fix NVIDIA GPU serial number format extraction
Extract decimal serial numbers from devname parameters (e.g., "SXM5_SN_1653925027099")
instead of hex PCIe Device Serial Numbers. This provides the correct GPU serial
numbers as they appear in NVIDIA diagnostics tooling.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-10 22:57:50 +03:00

93 lines
2.6 KiB
Go

package nvidia
import (
"bufio"
"regexp"
"strings"
"git.mchus.pro/mchus/logpile/internal/models"
"git.mchus.pro/mchus/logpile/internal/parser"
)
var (
// Regex to extract devname mappings from fieldiag command line
// Example: "devname=0000:ba:00.0,SXM5_SN_1653925027099"
devnameRegex = regexp.MustCompile(`devname=([\da-fA-F:\.]+),(\w+)`)
)
// ParseInventoryLog parses inventory/output.log to extract GPU serial numbers
// from fieldiag devname parameters (e.g., "SXM5_SN_1653925027099")
func ParseInventoryLog(content []byte, result *models.AnalysisResult) error {
if result.Hardware == nil || len(result.Hardware.GPUs) == 0 {
// No GPUs to update
return nil
}
scanner := bufio.NewScanner(strings.NewReader(string(content)))
// First pass: build mapping of PCI BDF -> Slot name and serial number from fieldiag command line
pciToSlot := make(map[string]string)
pciToSerial := make(map[string]string)
for scanner.Scan() {
line := scanner.Text()
// Look for fieldiag command with devname parameters
if strings.Contains(line, "devname=") && strings.Contains(line, "fieldiag") {
matches := devnameRegex.FindAllStringSubmatch(line, -1)
for _, match := range matches {
if len(match) == 3 {
pciBDF := match[1]
slotName := match[2]
// Extract slot number and serial from name like "SXM5_SN_1653925027099"
if strings.HasPrefix(slotName, "SXM") {
parts := strings.Split(slotName, "_")
if len(parts) >= 1 {
// Convert "SXM5" to "GPUSXM5"
slot := "GPU" + parts[0]
pciToSlot[pciBDF] = slot
}
// Extract serial number from "SXM5_SN_1653925027099"
if len(parts) == 3 && parts[1] == "SN" {
serial := parts[2]
pciToSerial[pciBDF] = serial
}
}
}
}
}
}
// Second pass: assign serial numbers to GPUs based on slot mapping
for i := range result.Hardware.GPUs {
slot := result.Hardware.GPUs[i].Slot
// Find the PCI BDF for this slot
var foundSerial string
for pciBDF, mappedSlot := range pciToSlot {
if mappedSlot == slot {
// Found matching slot, get serial number
if serial, ok := pciToSerial[pciBDF]; ok {
foundSerial = serial
break
}
}
}
if foundSerial != "" {
result.Hardware.GPUs[i].SerialNumber = foundSerial
}
}
return scanner.Err()
}
// findInventoryOutputLog finds the inventory/output.log file
func findInventoryOutputLog(files []parser.ExtractedFile) *parser.ExtractedFile {
for _, f := range files {
// Look for inventory/output.log
path := strings.ToLower(f.Path)
if strings.Contains(path, "inventory/output.log") ||
strings.Contains(path, "inventory\\output.log") {
return &f
}
}
return nil
}