Files
logpile/internal/parser/vendors/nvidia_bug_report/cpu.go
Mikhail Chusavitin 70cd541d9e v1.3.0: Add multiple vendor parsers and enhanced hardware detection
New parsers:
- NVIDIA Field Diagnostics parser with dmidecode output support
- NVIDIA Bug Report parser with comprehensive hardware extraction
- Supermicro crashdump (CDump.txt) parser
- Generic fallback parser for unrecognized text files

Enhanced GPU parsing (nvidia-bug-report):
- Model and manufacturer detection (NVIDIA H100 80GB HBM3)
- UUID, Video BIOS version, IRQ information
- Bus location (BDF), DMA size/mask, device minor
- PCIe bus type details

New hardware detection (nvidia-bug-report):
- System Information: server S/N, UUID, manufacturer, product name
- CPU: model, S/N, cores, threads, frequencies from dmidecode
- Memory: P/N, S/N, manufacturer, speed for all DIMMs
- Power Supplies: manufacturer, model, S/N, wattage, status
- Network Adapters: Ethernet/InfiniBand controllers with VPD data
  - Model, P/N, S/N from lspci Vital Product Data
  - Port count/type detection (QSFP56, OSFP, etc.)
  - Support for ConnectX-6/7 adapters

Archive handling improvements:
- Plain .gz file support (not just tar.gz)
- Increased size limit for plain gzip files (50MB)
- Better error handling for mixed archive formats

Web interface enhancements:
- Display parser name and filename badges
- Improved file info section with visual indicators

Co-Authored-By: Claude (qwen3-coder:480b) <noreply@anthropic.com>
2026-01-30 17:19:47 +03:00

141 lines
3.4 KiB
Go

package nvidia_bug_report
import (
"bufio"
"strconv"
"strings"
"git.mchus.pro/mchus/logpile/internal/models"
)
// parseCPUInfo extracts CPU information from dmidecode output
func parseCPUInfo(content string, result *models.AnalysisResult) {
scanner := bufio.NewScanner(strings.NewReader(content))
var currentCPU *models.CPU
inProcessorInfo := false
cpuSocket := 0
for scanner.Scan() {
line := scanner.Text()
trimmed := strings.TrimSpace(line)
// Start of Processor Information section
if strings.Contains(trimmed, "Processor Information") {
inProcessorInfo = true
currentCPU = &models.CPU{
Socket: cpuSocket,
}
cpuSocket++
continue
}
// End of current section (empty line or new section with Handle)
if inProcessorInfo && (trimmed == "" || strings.HasPrefix(trimmed, "Handle ")) {
// Save CPU if it has valid data
if currentCPU != nil && currentCPU.Model != "" {
result.Hardware.CPUs = append(result.Hardware.CPUs, *currentCPU)
}
inProcessorInfo = false
currentCPU = nil
continue
}
// Parse fields within Processor Information section
if inProcessorInfo && currentCPU != nil && strings.Contains(line, ":") {
parts := strings.SplitN(trimmed, ":", 2)
if len(parts) != 2 {
continue
}
field := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
if value == "" || value == "Not Specified" || value == "Unknown" || value == "UNKNOWN" || value == "<OUT OF SPEC>" {
continue
}
switch field {
case "Version":
// CPU model name
currentCPU.Model = value
case "Serial Number":
currentCPU.SerialNumber = value
case "Part Number":
// Store part number if available
// Could be stored in a custom field if needed
case "Core Count":
if cores, err := strconv.Atoi(value); err == nil {
currentCPU.Cores = cores
}
case "Core Enabled":
// Could store this if needed
case "Thread Count":
if threads, err := strconv.Atoi(value); err == nil {
currentCPU.Threads = threads
}
case "Max Speed":
// Parse speed like "3800 MHz"
if speed := parseCPUSpeed(value); speed > 0 {
currentCPU.MaxFreqMHz = speed
}
case "Current Speed":
// Parse current speed like "2000 MHz"
if speed := parseCPUSpeed(value); speed > 0 {
currentCPU.FrequencyMHz = speed
}
case "Voltage":
// Could parse voltage if needed (e.g., "1.6 V")
case "Status":
// Status like "Populated, Enabled"
// Check if CPU is enabled
if !strings.Contains(value, "Populated") {
// Skip unpopulated CPUs
currentCPU = nil
inProcessorInfo = false
}
}
}
}
// Save last CPU if exists
if currentCPU != nil && currentCPU.Model != "" {
result.Hardware.CPUs = append(result.Hardware.CPUs, *currentCPU)
}
}
// parseCPUSpeed parses CPU speed strings like "3800 MHz" or "2.0 GHz"
func parseCPUSpeed(speedStr string) int {
parts := strings.Fields(speedStr)
if len(parts) < 2 {
return 0
}
// Try to parse the number (may be int or float)
speedStr = parts[0]
var speed float64
var err error
if strings.Contains(speedStr, ".") {
speed, err = strconv.ParseFloat(speedStr, 64)
} else {
var speedInt int
speedInt, err = strconv.Atoi(speedStr)
speed = float64(speedInt)
}
if err != nil {
return 0
}
unit := strings.ToUpper(parts[1])
switch unit {
case "MHZ":
return int(speed)
case "GHZ":
return int(speed * 1000)
default:
return 0
}
}