I want to start a process and measure the cpu time (user+sys) it needs until it terminates.
I know I can use the
wait4 system call, which returns a struct with user and system time (I use the sum of both times).
I can also use the
cpuacct cgroup subsystem, put the process into a new cgroup, and read the
cpuacct.usage file (which contains the combined user and system time).
I know the former has problems when the process spawns subprocesses (sometimes their time does not get counted). However, I thought that for a single-process case the two measurements should be almost equal. I expected the cpuacct value to be a little bit smaller, because I can only put the process into the cgroup after it has been created (but I do this immediately after fork, so the difference should be minimal).
Now for processes that take a few seconds, I see the expected results.
wait4: 8.292518s cpuacct: 8.299105444s wait4: 13.788861s cpuacct: 13.796484557s wait4: 24.229514s cpuacct: 24.234132965s wait4: 84.101255s cpuacct: 84.104336222s
However, for processes that take longer, I get a different result:
wait4: 155.309706s cpuacct: 155.306291274s wait4: 505.547594s cpuacct: 505.526723631s wait4: 897.180069s cpuacct: 897.131232685s
Now the cpuacct value is a little bit lower, which I would never expect to happen. Does somebody have an idea why this happens?
I do not care about 0.1s accuracy, and I have never experienced a higher difference. Can I be confident, that the difference will always be that small? Or are there possible scenarios where the difference will be larger?
cpuacct documentation states that the value may be imprecise in 2 cases. However, both cases do not apply here, as I am on a 64bit machine, and I can wait an arbitrary amount of time after the process finishes, the reading of
cpuacct.usage will stay constant (so I strongly believe it is not an outdated value).
My starting process is a Python process. I use
subprocess.Popen() to spawn the task and
os.wait4() to get the time. For using the cgroups I pass a function to the
preexec_fn parameter of
Popen that adds the new process to the cgroup (so this is done between the
exec system calls). The started process is a Java VM.
I don't think this is relevant, but I wanted to provide this information just in case.