我想启动一个进程并测量它终止之前所需的CPU时间(用户+系统)。
我知道我可以使用wait4
系统调用,它返回一个包含用户和系统时间的结构(我使用两个时间的总和)。
我也可以使用cpuacct
cgroup 子系统,将进程放入一个新的cgroup中,并读取cpuacct.usage
文件(其中包含用户和系统时间的组合)。
我知道前者在进程产生子进程时会出现问题(有时它们的时间不被计算在内)。然而,我认为对于单进程情况,两个测量值应该几乎相等。我预计 cpuacct 值会小一点,因为我只能在创建进程后将其放入 cgroup(但我在 fork 后立即执行此操作,因此差异应该很小)。
现在,对于需要几秒钟的过程,我看到了预期的结果。
例子:
wait4: 8.292518s
cpuacct: 8.299105444s
wait4: 13.788861s
cpuacct: 13.796484557s
wait4: 24.229514s
cpuacct: 24.234132965s
wait4: 84.101255s
cpuacct: 84.104336222s
然而,对于需要更长时间的过程,我得到不同的结果:
wait4: 155.309706s
cpuacct: 155.306291274s
wait4: 505.547594s
cpuacct: 505.526723631s
wait4: 897.180069s
cpuacct: 897.131232685s
现在 cpuacct 值有点低,这是我从未预料到的。有人知道为什么会发生这种情况吗?
我不在乎0.1s的精度,而且我从未经历过更高的差异。我可以确信差异总是那么小吗?或者是否有可能出现差异更大的情况?
文档cpuacct
指出该值在两种情况下可能不精确。但是,这两种情况都不适用,因为我在 64 位机器上,并且我可以在进程完成后等待任意时间,读取的cpuacct.usage
值将保持不变(所以我坚信它不是一个过时的值)。
精确设置:
我的启动进程是一个Python进程。我习惯于subprocess.Popen()
产生任务并os.wait4()
获得时间。为了使用 cgroup,我将一个函数传递给将新进程添加到 cgrouppreexec_fn
的参数(因此这是在和系统调用之间完成的)。启动的进程是一个Java VM。我认为这不相关,但我想提供此信息以防万一。Popen
fork
exec