mirror of
https://github.com/fankes/komari-agent.git
synced 2026-02-04 12:17:30 +08:00
251 lines
6.1 KiB
Go
251 lines
6.1 KiB
Go
//go:build linux
|
|
// +build linux
|
|
|
|
package monitoring
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func GpuName() string {
|
|
if name := getFromLspci(); name != "None" {
|
|
return name
|
|
}
|
|
|
|
if name := getFromSysfsDRM(); name != "None" {
|
|
return name
|
|
}
|
|
return "None"
|
|
}
|
|
|
|
func getFromLspci() string {
|
|
out, err := exec.Command("lspci").Output()
|
|
if err != nil {
|
|
return "None"
|
|
}
|
|
excludePatterns := []string{
|
|
"^1111", // 1111 (rev 02)
|
|
`(?i)^cirrus logic (cl[-\s]?)?gd 5`, // CL-GD 系列 1990 年代中期的产物, 现常用于虚拟机
|
|
"(?i)virtio",
|
|
"(?i)vmware",
|
|
`(?i)qxl`, // SPICE 虚拟显卡
|
|
`(?i)hyper-v`,
|
|
}
|
|
|
|
lines := strings.Split(string(out), "\n")
|
|
|
|
priorityVendors := []string{"nvidia", "amd", "radeon", "intel", "arc", "snap", "qualcomm", "snapdragon"}
|
|
|
|
isExcluded := func(name string) bool {
|
|
for _, pattern := range excludePatterns {
|
|
if matched, _ := regexp.MatchString(pattern, name); matched {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
extractName := func(line string) string {
|
|
// 取最后一个冒号之后的内容
|
|
idx := strings.LastIndex(line, ":")
|
|
if idx == -1 || idx == len(line)-1 {
|
|
return ""
|
|
}
|
|
name := strings.TrimSpace(line[idx+1:])
|
|
|
|
// 去除末尾的 (rev xx)
|
|
if parenIdx := strings.LastIndex(name, "("); parenIdx != -1 {
|
|
name = strings.TrimSpace(name[:parenIdx])
|
|
}
|
|
return name
|
|
}
|
|
|
|
// 寻找 priorityVendors
|
|
for _, line := range lines {
|
|
lower := strings.ToLower(line)
|
|
|
|
// 必须确认是显示设备,防止匹配到 Intel 网卡或 Qualcomm 蓝牙
|
|
if !strings.Contains(lower, "vga") && !strings.Contains(lower, "3d") && !strings.Contains(lower, "display") {
|
|
continue
|
|
}
|
|
|
|
for _, vendor := range priorityVendors {
|
|
if strings.Contains(lower, vendor) {
|
|
name := extractName(line)
|
|
if name != "" && !isExcluded(name) {
|
|
// 找到独显立刻返回
|
|
return name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 任意非黑名单的 VGA 设备
|
|
for _, line := range lines {
|
|
lower := strings.ToLower(line)
|
|
if strings.Contains(lower, "vga") || strings.Contains(lower, "3d") || strings.Contains(lower, "display") {
|
|
name := extractName(line)
|
|
if name != "" && !isExcluded(name) {
|
|
return name
|
|
}
|
|
}
|
|
}
|
|
|
|
return "None"
|
|
|
|
}
|
|
|
|
func getFromSysfsDRM() string {
|
|
matches, _ := filepath.Glob("/sys/class/drm/card*")
|
|
|
|
excludedDrivers := map[string]bool{
|
|
"virtio-pci": true,
|
|
"virtio_gpu": true,
|
|
"bochs-drm": true,
|
|
"qxl": true,
|
|
"vmwgfx": true,
|
|
"cirrus": true,
|
|
"vboxvideo": true,
|
|
"hyperv_fb": true,
|
|
"simpledrm": true,
|
|
"simplefb": true,
|
|
"cirrus-qemu": true,
|
|
}
|
|
|
|
for _, path := range matches {
|
|
// 驱动名称
|
|
driverLink, err := os.Readlink(filepath.Join(path, "device", "driver"))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
driverName := filepath.Base(driverLink)
|
|
|
|
if excludedDrivers[driverName] {
|
|
continue
|
|
}
|
|
|
|
// 设备树 compatible 提取具体型号
|
|
// /sys/class/drm/card0/device/of_node/compatible
|
|
// "qcom,adreno-750.1\0qcom,adreno"
|
|
exactModel := ""
|
|
compatibleBytes, err := os.ReadFile(filepath.Join(path, "device", "of_node", "compatible"))
|
|
if err == nil {
|
|
exactModel = parseSocModel(driverName, compatibleBytes)
|
|
}
|
|
|
|
// 有具体型号则直接返回
|
|
if exactModel != "" {
|
|
return exactModel
|
|
}
|
|
|
|
// 通用的驱动名称映射
|
|
switch driverName {
|
|
case "vc4":
|
|
return "Broadcom VideoCore IV/VI (Raspberry Pi)"
|
|
case "v3d":
|
|
return "Broadcom V3D (Raspberry Pi 4/5)"
|
|
case "msm", "msm_drm":
|
|
return "Qualcomm Adreno (Unknown Model)"
|
|
case "panfrost":
|
|
return "ARM Mali (Panfrost)"
|
|
case "lima":
|
|
return "ARM Mali (Lima)"
|
|
case "sun4i-drm", "sunxi-drm":
|
|
return "Allwinner Display Engine"
|
|
case "tegra":
|
|
return "NVIDIA Tegra"
|
|
case "ast": // LXC 容器映射物理显卡
|
|
return "ASPEED Technology, Inc. ASPEED Graphics Family"
|
|
}
|
|
|
|
if driverName != "" {
|
|
return "Direct Render Manager " + driverName
|
|
}
|
|
}
|
|
|
|
// 开发板 Model
|
|
modelData, err := os.ReadFile("/sys/firmware/devicetree/base/model")
|
|
if err == nil {
|
|
model := string(modelData)
|
|
if strings.Contains(model, "Raspberry Pi") {
|
|
return "Broadcom VideoCore (Integrated)"
|
|
}
|
|
}
|
|
|
|
return "None"
|
|
}
|
|
|
|
// parseSocModel 解析设备树 compatible 字符串,提取人性化名称
|
|
func parseSocModel(driver string, rawBytes []byte) string {
|
|
// compatible 文件包含多个以 \0 分隔的字符串
|
|
content := string(bytes.ReplaceAll(rawBytes, []byte{0}, []byte(" ")))
|
|
lower := strings.ToLower(content)
|
|
|
|
// 高通 Adreno (Qualcomm)
|
|
if driver == "msm" || strings.Contains(lower, "adreno") {
|
|
// "adreno-750", "adreno-660"
|
|
re := regexp.MustCompile(`adreno[-_](\d+)`)
|
|
matches := re.FindStringSubmatch(lower)
|
|
if len(matches) > 1 {
|
|
return "Qualcomm Adreno " + matches[1]
|
|
}
|
|
return "Qualcomm Adreno"
|
|
}
|
|
|
|
// ARM Mali (Rockchip/MediaTek/AmLogic)
|
|
if driver == "panfrost" || driver == "lima" || strings.Contains(lower, "mali") {
|
|
// "mali-g610", "mali-t860"
|
|
re := regexp.MustCompile(`mali[-_]([a-z]\d+)`)
|
|
matches := re.FindStringSubmatch(lower)
|
|
if len(matches) > 1 {
|
|
return "ARM Mali " + strings.ToUpper(matches[1]) // Mali G610
|
|
}
|
|
return "ARM Mali" // 泛指
|
|
}
|
|
|
|
// 树莓派 VideoCore
|
|
if driver == "vc4" || driver == "v3d" {
|
|
if strings.Contains(lower, "bcm2712") {
|
|
return "Broadcom VideoCore VII (Pi 5)"
|
|
}
|
|
if strings.Contains(lower, "bcm2711") {
|
|
return "Broadcom VideoCore VI (Pi 4)"
|
|
}
|
|
if strings.Contains(lower, "bcm2837") || strings.Contains(lower, "bcm2835") {
|
|
return "Broadcom VideoCore IV"
|
|
}
|
|
}
|
|
|
|
// Allwinner (全志)
|
|
// "allwinner,sun50i-h6-display-engine"
|
|
if strings.Contains(lower, "allwinner") || strings.Contains(lower, "sun50i") || strings.Contains(lower, "sun8i") {
|
|
re := regexp.MustCompile(`sun\d+i-([a-z0-9]+)`)
|
|
matches := re.FindStringSubmatch(lower)
|
|
if len(matches) > 1 {
|
|
model := strings.ToUpper(matches[1])
|
|
return "Allwinner " + model
|
|
}
|
|
return "Allwinner Display Engine"
|
|
}
|
|
|
|
// NVIDIA Tegra
|
|
if driver == "tegra" {
|
|
if strings.Contains(lower, "tegra194") {
|
|
return "NVIDIA Tegra Xavier"
|
|
}
|
|
if strings.Contains(lower, "tegra234") {
|
|
return "NVIDIA Orin"
|
|
}
|
|
if strings.Contains(lower, "tegra210") {
|
|
return "NVIDIA Tegra X1"
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|