git.sophuwu.com > amdgpu-qstat   
              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
}