git.sophuwu.com > amdgpu-qstat
made the quickstat amdgpu program quickly in one session
sophuwu sophie@sophuwu.com
Tue, 25 Nov 2025 16:36:07 +0100
commit

4a4fe9d78a4cff84d41e2dbf71d438aa945d4941

4 files changed, 312 insertions(+), 0 deletions(-)

jump to
A .gitignore

@@ -0,0 +1,2 @@

+.idea +build/
A config/config.go

@@ -0,0 +1,99 @@

+package config + +import ( + "fmt" + "os" + "strings" +) + +var ShowErr = false +var Use = false +var Temp = false +var Mem = false +var MemPerc = false +var Power = false +var Freq = false +var MemFreq = false +var Fan = false + +func init() { + help := false + all := func() { + Use = true + Temp = true + Mem = true + MemPerc = true + Power = true + Freq = true + MemFreq = true + Fan = true + } + for _, arg := range os.Args[1:] { + if strings.HasPrefix(arg, "--") { + switch arg { + case "--show-err": + ShowErr = true + case "--help": + help = true + case "--all": + all() + } + } else if strings.HasPrefix(arg, "-") { + for _, c := range arg[1:] { + switch c { + case '?', 'h': + help = true + case 'e': + ShowErr = true + case 'a': + all() + case 'u': + Use = true + case 't': + Temp = true + case 'm': + Mem = true + case 'p': + Power = true + case 'f': + Freq = true + case 'M': + MemFreq = true + case 'F': + Fan = true + case '%': + MemPerc = true + } + } + continue + } + } + if help { + fmt.Printf(helpMenu, os.Args[0]) + os.Exit(0) + } + if !(Use || Temp || Mem || MemPerc || Power || Freq || MemFreq || Fan) { + Use = true + Temp = true + MemPerc = true + } +} + +var helpMenu = `Usage: %s [options] +A utility to query AMD GPU statistics. + +Options: + -h, --help Show this help message and exit + -e, --err Show error messages + -a, --all Show all statistics + -u Show GPU utilization + -f Show GPU core frequency + -t Show GPU temperature + -m Show GPU memory usage + -% Show GPU memory usage percentage + -M Show GPU memory frequency + -p Show GPU power consumption + -F Show GPU fan speed + +If no options are given, -ut% are assumed. +`
A go.mod

@@ -0,0 +1,3 @@

+module git.sophuwu.com/amdgpu-qstat + +go 1.25.1
A main.go

@@ -0,0 +1,208 @@

+package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "git.sophuwu.com/amdgpu-qstat/config" +) + +func fatal(msg string) { + if config.ShowErr { + fmt.Fprintf(os.Stderr, "fatal error: %s\n", msg) + } + os.Exit(1) +} + +var HwmonPath string + +func getHwmonPath() { + if HwmonPath != "" { + return + } + hwmonPath := "/sys/class/hwmon" + dr, err := os.ReadDir(hwmonPath) + if err != nil || len(dr) == 0 { + fatal("unable to read hwmon") + } + var b []byte + for _, entry := range dr { + b, err = os.ReadFile(filepath.Join(hwmonPath, entry.Name(), "name")) + if err != nil { + continue + } + if strings.TrimSpace(string(b)) == "amdgpu" { + HwmonPath = filepath.Join(hwmonPath, entry.Name()) + return + } + } + fatal("amdgpu hwmon not found") +} + +func ERR(msg string) { + if config.ShowErr { + fmt.Fprintf(os.Stderr, "error: %s\n", msg) + } +} + +func main() { + getHwmonPath() + + var f Freq + if config.Freq || config.MemFreq { + err := f.Get() + if err != nil { + ERR("unable to read frequency") + config.Freq = false + config.MemFreq = false + } + } + + var m Mem + if config.Mem || config.MemPerc { + err := m.Get() + if err != nil { + ERR("unable to read memory usage") + config.Mem = false + config.MemPerc = false + } + } + + var val int + var err error + var s string + + if config.Use || config.Temp || config.Freq || config.Power { + s += "GPU: " + if config.Use { + val, err = readNum("device/gpu_busy_percent") + if err != nil { + ERR("unable to read GPU usage") + } else { + s += fmt.Sprintf("%3d%% ", val) + } + } + if config.Freq { + if f.Core != "" { + s += fmt.Sprintf("%s ", f.Core) + } + } + if config.Power { + val, err = readNum("power1_input") + if err != nil { + ERR("unable to read power consumption") + } else { + s += fmt.Sprintf("%3.0f W ", float64(val)/1000000.0) + } + } + if config.Temp { + val, err = readNum("temp1_input") + if err != nil { + ERR("unable to read temperature") + } else { + s += fmt.Sprintf("%3d C", val/1000) + } + } + if config.Fan || config.MemFreq || config.Mem || config.MemPerc { + s += " | " + } + } + if config.Mem || config.MemPerc || config.MemFreq { + s += "MEM: " + if config.Mem && config.MemPerc { + s += fmt.Sprintf("%s (%s) ", m.Gb, m.Perc) + } else if config.Mem { + s += fmt.Sprintf("%s ", m.Gb) + } else if config.MemPerc { + s += fmt.Sprintf("%s ", m.Perc) + } + if config.MemFreq { + s += fmt.Sprintf("%s", f.Mem) + } + if config.Fan { + s += " | " + } + } + if config.Fan { + val, err = readNum("fan1_input") + if err != nil { + ERR("unable to read fan speed") + } else { + s += fmt.Sprintf("FAN: %4d RPM", val) + } + } + + fmt.Println(s) + +} + +type Mem struct { + Perc string + Gb string +} + +func (m *Mem) Get() error { + used, err := readNum("device/mem_info_vram_used") + if err != nil { + return fmt.Errorf("unable to get memory usage") + } + total, err := readNum("device/mem_info_vram_total") + if err != nil { + return fmt.Errorf("unable to get memory usage") + } + Perc := float64(used) / float64(total) * 100 + m.Perc = fmt.Sprintf("%3.0f%%", Perc) + m.Gb = fmt.Sprintf("%4.2f GB / %4.2f GB", float64(used)/1073741824.0, float64(total)/1073741824.0) + return nil +} + +func readNum(path string) (int, error) { + b, err := os.ReadFile(filepath.Join(HwmonPath, path)) + if err != nil { + return 0, err + } + var val int + for _, c := range b { + if c < '0' || c > '9' { + break + } + val = val*10 + int(c-'0') + } + return int(val), nil +} + +type Freq struct { + Core string + Mem string +} + +func (f *Freq) Get() error { + dr, err := os.ReadDir(filepath.Join(HwmonPath)) + if err != nil { + return fmt.Errorf("unable to get frequency") + } + var b []byte + var val int + var s string + for _, entry := range dr { + if strings.HasPrefix(entry.Name(), "freq") && strings.HasSuffix(entry.Name(), "_label") { + b, err = os.ReadFile(filepath.Join(HwmonPath, entry.Name())) + if err != nil { + return fmt.Errorf("unable to get frequency") + } + val, err = readNum(strings.Replace(entry.Name(), "_label", "_input", 1)) + if err != nil { + return fmt.Errorf("unable to get frequency") + } + s = fmt.Sprintf("%4.0f MHz", float64(val)/1000000.0) + if strings.TrimSpace(string(b)) == "mclk" { + f.Mem = s + } else if strings.TrimSpace(string(b)) == "sclk" { + f.Core = s + } + } + } + return nil +}