javaoshi

Difference between Window Task CPU Utilization and Oshi CPU usage


I using Oshi API (https://github.com/oshi/oshi) to get the CPU usage. However, why the value is different from Task Manager CPU Utilization? What is my mistake?

My Program - Average 11.13%

enter image description here

Task Manager - Average around 29%

enter image description here

Edited Code

private SystemInfo systemInformation = new SystemInfo();
private CentralProcessor proc = systemInformation.getHardware().getProcessor();

private static float[] floatArrayPercent(double d) {
  float[] f = new float[1];
  f[0] = (float) (100d * d);
  return f;
}

private double cpuData(CentralProcessor proc) {
  double d = proc.getSystemCpuLoadBetweenTicks(oldTicks);
  oldTicks = proc.getSystemCpuLoadTicks();
  return d;
}


@Scheduled(fixedRate = 10)
public void processProcessorInformation() {
  System.out.println("The percentage of the floating value  cpu: " + floatArrayPercent(cpuData(proc))[0]);
}

Solution

  • The problem is that while you intended to do a "recent" usage calculation, you have a stray line of code resetting it to a cumulative (since startup) usage calculation.

    The getSystemCpuLoadBetweenTicks(oldTicks) calculation measures the elapsed user, system, idle, etc. ticks from the current counters to the previous ones you passed to it and will give you usage between those timeslices. In your cpuData() method you correctly save the old ticks and probably intend to use them again. That part's correct.

    However, in your processProcessorInformation() you zero out the oldTicks array each time: oldTicks = new long[TickType.values().length];. And thus the value being returned is the cumulative average CPU usage since you started, rather than the last 10 seconds. Deleting that line (or moving it outside the scheduled method) should give you the results you expect.

    You also don't need a fresh copy of the cpu object each time. You can move that initialization out of the scheduled method while you're moving the oldTicks initialization.

    On a related note, @Elliot-Frisch mentioned in the comments about calculations involving multiple processors. This is a useful warning when comparing processor ticks vs. time (e.g., if you're measuring ticks between elapsed time periods). Ticks accumulate on every logical processor, so you would need to make sure you scale the "elapsed time" to include every logical processor as well. This applies when dealing with per-Process CPU calculations, as you only have process up time available as a denominator, and in this case Windows Task Manager is scaled to ensure no process exceeds 100%, while *nix results (on top) are not scaled and it's possible to exceed 100%.

    However, for System CPU usage, we have an "idle" tick counter available, which does accumulate ticks on all the processors and is a better choice for calculating percent usage -- and is what's used in the getSystemCpuLoadBetweenTicks() method, so this correction is not required.