diff --git a/load/load_aix_cgo.go b/load/load_aix_cgo.go index e325432ed0..72d158bc62 100644 --- a/load/load_aix_cgo.go +++ b/load/load_aix_cgo.go @@ -8,6 +8,7 @@ package load #include #include +#include */ import "C" @@ -33,28 +34,50 @@ func AvgWithContext(ctx context.Context) (*AvgStat, error) { } func MiscWithContext(ctx context.Context) (*MiscStat, error) { - info := C.struct_procentry64{} + // Count total processes and collect PIDs for thread-state enumeration. + pinfo := C.struct_procentry64{} cpid := C.pid_t(0) ret := MiscStat{} + var pids []C.pid_t for { - // getprocs first argument is a void* - num, err := C.getprocs64(unsafe.Pointer(&info), C.sizeof_struct_procentry64, nil, 0, &cpid, 1) + num, err := C.getprocs64(unsafe.Pointer(&pinfo), C.sizeof_struct_procentry64, nil, 0, &cpid, 1) if err != nil { return nil, err } - - ret.ProcsTotal++ - switch info.pi_state { - case C.SACTIVE: - ret.ProcsRunning++ - case C.SSTOP: - ret.ProcsBlocked++ - } - if num == 0 { break } + ret.ProcsTotal++ + pids = append(pids, pinfo.pi_pid) } + + // Count threads in TSRUN state (runnable/running) across all processes. + // SACTIVE at the process level means "active in memory" which includes + // sleeping processes and is not a useful proxy for ProcsRunning. + tinfo := C.struct_thrdentry64{} + for _, pid := range pids { + ctid := C.tid64_t(0) + for { + n, err := C.getthrds64(pid, unsafe.Pointer(&tinfo), C.sizeof_struct_thrdentry64, &ctid, 1) + if err != nil { + break // process may have exited + } + if n == 0 { + break + } + if tinfo.ti_state == C.TSRUN { + ret.ProcsRunning++ + } + } + } + + // ProcsBlocked: processes sleeping waiting for I/O, equivalent to Linux D state. + // perfstat IOWait and PhysIO are instantaneous counts, matching vmstat's b column. + var cpuStat C.perfstat_cpu_total_t + if rc := C.perfstat_cpu_total(nil, &cpuStat, C.sizeof_perfstat_cpu_total_t, 1); rc == 1 { + ret.ProcsBlocked = int(cpuStat.iowait) + int(cpuStat.physio) + } + return &ret, nil }