From ecfffa882a159bb2a12954eed0f68eb4ec1a6120 Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Tue, 16 Sep 2025 14:15:18 +0200 Subject: CPU History, CPU Utilization --- util/sys/sys_linux.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'util/sys/sys_linux.go') diff --git a/util/sys/sys_linux.go b/util/sys/sys_linux.go index d4e6e8ae..8a494d62 100644 --- a/util/sys/sys_linux.go +++ b/util/sys/sys_linux.go @@ -4,10 +4,14 @@ package sys import ( + "bufio" "bytes" "fmt" "io" "os" + "strconv" + "strings" + "sync" ) func getLinesNum(filename string) (int, error) { @@ -79,3 +83,99 @@ func safeGetLinesNum(path string) (int, error) { } return getLinesNum(path) } + +// --- CPU Utilization (Linux native) --- + +var ( + cpuMu sync.Mutex + lastTotal uint64 + lastIdleAll uint64 + hasLast bool +) + +// CPUPercentRaw returns instantaneous total CPU utilization by reading /proc/stat. +// First call initializes and returns 0; subsequent calls return busy/total * 100. +func CPUPercentRaw() (float64, error) { + f, err := os.Open("/proc/stat") + if err != nil { + return 0, err + } + defer f.Close() + + rd := bufio.NewReader(f) + line, err := rd.ReadString('\n') + if err != nil && err != io.EOF { + return 0, err + } + // Expect line like: cpu user nice system idle iowait irq softirq steal guest guest_nice + fields := strings.Fields(line) + if len(fields) < 5 || fields[0] != "cpu" { + return 0, fmt.Errorf("unexpected /proc/stat format") + } + + var nums []uint64 + for i := 1; i < len(fields); i++ { + v, err := strconv.ParseUint(fields[i], 10, 64) + if err != nil { + break + } + nums = append(nums, v) + } + if len(nums) < 4 { // need at least user,nice,system,idle + return 0, fmt.Errorf("insufficient cpu fields") + } + + // Conform with standard Linux CPU accounting + var user, nice, system, idle, iowait, irq, softirq, steal uint64 + user = nums[0] + if len(nums) > 1 { + nice = nums[1] + } + if len(nums) > 2 { + system = nums[2] + } + if len(nums) > 3 { + idle = nums[3] + } + if len(nums) > 4 { + iowait = nums[4] + } + if len(nums) > 5 { + irq = nums[5] + } + if len(nums) > 6 { + softirq = nums[6] + } + if len(nums) > 7 { + steal = nums[7] + } + + idleAll := idle + iowait + nonIdle := user + nice + system + irq + softirq + steal + total := idleAll + nonIdle + + cpuMu.Lock() + defer cpuMu.Unlock() + + if !hasLast { + lastTotal = total + lastIdleAll = idleAll + hasLast = true + return 0, nil + } + + totald := total - lastTotal + idled := idleAll - lastIdleAll + lastTotal = total + lastIdleAll = idleAll + + if totald == 0 { + return 0, nil + } + busy := totald - idled + pct := float64(busy) / float64(totald) * 100.0 + if pct > 100 { + pct = 100 + } + return pct, nil +} -- cgit v1.2.3