Skip to content

[cpu][openbsd]: cpu-total is the per-CPU average, so TestTimes fails on hosts with 4+ CPUs #2131

Description

@neilpang

Describe the bug

cpu.TestTimes fails on OpenBSD on any host with 4 or more online CPUs:

--- FAIL: TestTimes (0.00s)
    cpu_test.go:51: {"cpu":"cpu-total","user":22.4,"system":17.2,"idle":10.7,...}
    cpu_test.go:57: Relative error is too high: 2 (expected) < 3.001336302895323 (actual)
    cpu_test.go:60: Relative error is too high: 2 (expected) < 3 (actual)
    cpu_test.go:63: Relative error is too high: 2 (expected) < 3.000000000000001 (actual)

The relative error is exactly ncpu - 1. hw.ncpu was 4 on that host, and all
three fields came out at 3.0.

To Reproduce

// on OpenBSD, on a host with 4 or more online CPUs
total, _ := cpu.Times(false)  // KERN_CPTIME
per, _ := cpu.Times(true)     // KERN_CPUSTATS, one per CPU
// sum(per) == ncpu * total[0]

Expected behavior

The test asserts that the per-CPU times sum to roughly cpu-total, with
margin = 2.0. On OpenBSD they do not, because the two paths are not on the
same scale: KERN_CPTIME is averaged over the online CPUs. From
sys/kern/kern_sysctl.c (lines 653-675):

case KERN_CPTIME:
	CPU_INFO_FOREACH(cii, ci) {
		if (!cpu_is_online(ci))
			continue;
		n++;
		sysctl_ci_cp_time(ci, ci_cp_time);
		for (i = 0; i < CPUSTATES; i++)
			cp_time[i] += ci_cp_time[i];
	}

	for (i = 0; i < CPUSTATES; i++)
		cp_time[i] /= n;

https://github.com/openbsd/src/blob/master/sys/kern/kern_sysctl.c

So sum(perCPU) == ncpu * cpuTotal, and margin = 2.0 only holds while
ncpu <= 3.

This may be more than a test tolerance. On Linux, cpu-total comes from
the cpu line of /proc/stat, which is the sum across CPUs. If OpenBSD
returns the average, cpu.Times(false) means something different there. It
cancels out in a percentage computed over two samples, so it may not matter in
practice -- your call.

If you do want a sum, KERN_CPTIME2 returns un-averaged per-CPU times, and
cpu_openbsd.go already reads hw.ncpuonline elsewhere, which is the same
divisor the kernel uses.

Environment (please complete the following information):

  • OpenBSD: OpenBSD 7.9 amd64, go1.26.2, gopsutil master, hw.ncpu=4

Additional context

Found while running the suite on OpenBSD for the first time:
https://github.com/neilpang/gopsutil/actions/runs/30751019667/job/91504958976

Filed separately from the Process.Times() panic, since they are unrelated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions