如何调整 CPU 使用率粒度?

如何调整 CPU 使用率粒度?

这是关于格特鲁萨吉。效果不错,但是精度/粒度不够精确。

它不依赖于 CPU 及其性能。仅取决于内核。对于实际内核 4+精度为3800μs(微秒)。对于内核 3.x,该时间为 10,000 μs

但是 macos 提供了更精确的 CPU 使用率。它大约是 14 μs(比 Linux 精确 270 倍)其次,在 FreeBSD 及其 Linux 兼容层上,getrusage 每次调用都会返回更新的 CPU 使用率值(例如精度为 1.9 微秒)

我可以使用 sysctl 或重新编译内核来调整精度吗?

[更新] 详细百分位数和直方图

278 increments a second, e.g. 3,597.1 microseconds in average
 1%: 3.000           5%: 19.000         10%: 493.000        20%: 3,500.000      30%: 3,511.000
40%: 3,967.000      50%: 4,002.000      60%: 4,012.000      70%: 4,017.000      80%: 4,447.000
90%: 4,503.000      95%: 4,508.000      99%: 4,567.000

Histogram 'CPU Usage increments (microseconds)'
2.000     ... 399.417      9.7% | @@@@@@@@@@
399.417   ... 796.833      1.1% | @
796.833   ... 1,194.250    0.4% |
1,194.250 ... 1,591.667         |
1,591.667 ... 1,989.083    0.7% |
1,989.083 ... 2,386.500    0.4% |
2,386.500 ... 2,783.917    0.4% |
2,783.917 ... 3,181.333    0.7% |
3,181.333 ... 3,578.750   21.2% | @@@@@@@@@@@@@@@@@@@@@@@
3,578.750 ... 3,976.167    5.8% | @@@@@@
3,976.167 ... 4,373.583   38.5% | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
4,373.583 ... 4,771.000   21.2% | @@@@@@@@@@@@@@@@@@@@@@@

答案1

您能否提供参考文献和/或测试方法,以得出您在问题中发布的数字?

我可以观察到精确到微秒的粒度,但怀疑它是否真的精确到微秒。

我编写了一个简单的程序,列出用户和系统时间几次,然后仅当两者都改变​​几次时才列出:

/*****************************************************************************
*
* testrusage.c 2023.09.21 Smythies
*       Attempt to observe rusage time granularity.
*       see also: https://askubuntu.com/questions/1486310/how-to-tune-cpu-usage-granularity
*
*****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <sys/times.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <time.h>

unsigned long long stamp(void){
   struct timespec tv;

   clock_gettime(CLOCK_MONOTONIC_RAW,&tv);

   return (unsigned long long)tv.tv_sec * 1000000000 + tv.tv_nsec;
} /* endprocedure */

int main(){
   unsigned long long start, now, last;
   long tps;
   long sys_call_counter = 0;
   int i, j;
   long old_sys, old_user, new_sys, new_user;

   struct rusage usage;

   start = stamp();
   last = start;

   for(i = 0; i < 5; i++){
      getrusage(RUSAGE_SELF, &usage);
      sys_call_counter++;
      now = stamp();

      printf("loops: %ld : ", sys_call_counter);
      printf("Elapsed:%llu nS. ", now-start);
      printf("Delta:%llu nS.  : ru :  ", now-last);

      printf("user cpu: %ld uSec. ", usage.ru_utime.tv_usec);
      printf("sys cpu: %ld uSec.\n", usage.ru_stime.tv_usec);

      last = now;
   } /* endfor */
   printf("\n");

   old_sys = usage.ru_stime.tv_usec;
   old_user = usage.ru_utime.tv_usec;

   i = 0;
   while(i < 20){
      getrusage(RUSAGE_SELF, &usage);
      sys_call_counter++;
      new_sys = usage.ru_stime.tv_usec;
      new_user = usage.ru_utime.tv_usec;
      if((old_sys !=  new_sys) && (old_user != new_user)){
         for(j = 0; j < 1; j++){
            now = stamp();

            printf("loops: %ld : ", sys_call_counter);
            printf("Elapsed:%llu nS. ", now-start);
            printf("Delta:%llu nS.  : ru :  ", now-last);

            printf("user old: %ld uSec. ", old_user);
            printf("sys old: %ld uSec. ", old_sys);

            printf("user cpu: %ld uSec. ", new_user);
            printf("sys cpu: %ld uSec.\n", new_sys);

            last = now;

            getrusage(RUSAGE_SELF, &usage);
            sys_call_counter++;
            new_sys = (long) usage.ru_stime.tv_usec;
            new_user = (long) usage.ru_utime.tv_usec;
         } /* endfor */
         old_sys = new_sys;
         old_user = new_user;
         i++;
      } /* endif */
   } /* endwhile */
} /* endprogram */

并得到这个:

doug@s19:~/c$ ./testrusage
loops: 1 : Elapsed:2569 nS. Delta:2569 nS.  : ru :  user cpu: 292 uSec. sys cpu: 0 uSec.
loops: 2 : Elapsed:37342 nS. Delta:34773 nS.  : ru :  user cpu: 327 uSec. sys cpu: 0 uSec.
loops: 3 : Elapsed:38697 nS. Delta:1355 nS.  : ru :  user cpu: 329 uSec. sys cpu: 0 uSec.
loops: 4 : Elapsed:39827 nS. Delta:1130 nS.  : ru :  user cpu: 330 uSec. sys cpu: 0 uSec.
loops: 5 : Elapsed:40824 nS. Delta:997 nS.  : ru :  user cpu: 331 uSec. sys cpu: 0 uSec.

loops: 904 : Elapsed:205213 nS. Delta:164389 nS.  : ru :  user old: 331 uSec. sys old: 0 uSec. user cpu: 491 uSec. sys cpu: 3 uSec.
loops: 6486 : Elapsed:1203157 nS. Delta:997944 nS.  : ru :  user old: 491 uSec. sys old: 6 uSec. user cpu: 493 uSec. sys cpu: 1000 uSec.
loops: 9316 : Elapsed:1711772 nS. Delta:508615 nS.  : ru :  user old: 495 uSec. sys old: 1000 uSec. user cpu: 1001 uSec. sys cpu: 1001 uSec.
loops: 9319 : Elapsed:1713784 nS. Delta:2012 nS.  : ru :  user old: 1001 uSec. sys old: 1001 uSec. user cpu: 1002 uSec. sys cpu: 1002 uSec.
loops: 9322 : Elapsed:1715740 nS. Delta:1956 nS.  : ru :  user old: 1002 uSec. sys old: 1002 uSec. user cpu: 1003 uSec. sys cpu: 1003 uSec.
loops: 9325 : Elapsed:1717655 nS. Delta:1915 nS.  : ru :  user old: 1003 uSec. sys old: 1003 uSec. user cpu: 1004 uSec. sys cpu: 1004 uSec.
loops: 9328 : Elapsed:1719611 nS. Delta:1956 nS.  : ru :  user old: 1004 uSec. sys old: 1004 uSec. user cpu: 1005 uSec. sys cpu: 1005 uSec.
loops: 9332 : Elapsed:1721729 nS. Delta:2118 nS.  : ru :  user old: 1005 uSec. sys old: 1005 uSec. user cpu: 1006 uSec. sys cpu: 1006 uSec.
loops: 9335 : Elapsed:1723650 nS. Delta:1921 nS.  : ru :  user old: 1006 uSec. sys old: 1006 uSec. user cpu: 1007 uSec. sys cpu: 1007 uSec.
loops: 9339 : Elapsed:1725728 nS. Delta:2078 nS.  : ru :  user old: 1007 uSec. sys old: 1007 uSec. user cpu: 1008 uSec. sys cpu: 1008 uSec.
loops: 9342 : Elapsed:1727697 nS. Delta:1969 nS.  : ru :  user old: 1008 uSec. sys old: 1008 uSec. user cpu: 1009 uSec. sys cpu: 1009 uSec.
loops: 9346 : Elapsed:1729758 nS. Delta:2061 nS.  : ru :  user old: 1009 uSec. sys old: 1009 uSec. user cpu: 1010 uSec. sys cpu: 1010 uSec.
loops: 9349 : Elapsed:1731665 nS. Delta:1907 nS.  : ru :  user old: 1010 uSec. sys old: 1010 uSec. user cpu: 1011 uSec. sys cpu: 1011 uSec.
loops: 9352 : Elapsed:1733646 nS. Delta:1981 nS.  : ru :  user old: 1011 uSec. sys old: 1011 uSec. user cpu: 1012 uSec. sys cpu: 1012 uSec.
loops: 9356 : Elapsed:1735733 nS. Delta:2087 nS.  : ru :  user old: 1012 uSec. sys old: 1012 uSec. user cpu: 1013 uSec. sys cpu: 1013 uSec.
loops: 9359 : Elapsed:1737668 nS. Delta:1935 nS.  : ru :  user old: 1013 uSec. sys old: 1013 uSec. user cpu: 1014 uSec. sys cpu: 1014 uSec.
loops: 9362 : Elapsed:1739614 nS. Delta:1946 nS.  : ru :  user old: 1014 uSec. sys old: 1014 uSec. user cpu: 1015 uSec. sys cpu: 1015 uSec.
loops: 9366 : Elapsed:1741727 nS. Delta:2113 nS.  : ru :  user old: 1015 uSec. sys old: 1015 uSec. user cpu: 1016 uSec. sys cpu: 1016 uSec.
loops: 9369 : Elapsed:1743624 nS. Delta:1897 nS.  : ru :  user old: 1016 uSec. sys old: 1016 uSec. user cpu: 1017 uSec. sys cpu: 1017 uSec.
loops: 9372 : Elapsed:1745647 nS. Delta:2023 nS.  : ru :  user old: 1017 uSec. sys old: 1017 uSec. user cpu: 1018 uSec. sys cpu: 1018 uSec.

注 1:我没有旧版 4 系列或 3 系列内核。我是在 6.X 系列内核上执行此操作的。(我可以在 5.15 系列内核上执行此操作,但我没有这样做。)

注 2:我正在使用支持高分辨率计时器的硬件和内核:

doug@s19:~/c$ grep CONFIG_HIGH_RES_TIMERS /boot/con*
...
/boot/config-5.15.0-79-generic:CONFIG_HIGH_RES_TIMERS=y
/boot/config-5.15.0-83-generic:CONFIG_HIGH_RES_TIMERS=y
...
/boot/config-5.4.0-162-generic:CONFIG_HIGH_RES_TIMERS=y
...
/boot/config-6.6.0-rc2-stock:CONFIG_HIGH_RES_TIMERS=y

这些计时器可以测量到 uSec:

doug@s19:~/tmp$ sudo cat /proc/timer_list | grep min_delta_ns
 min_delta_ns:   8001
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000
 min_delta_ns:   1000

编辑:我修改了我的程序,以便只打印一些总数,并运行 getrusage 报告的 1 亿次用户或系统时间更改。
耗时为 100.004 秒,即每次更改平均耗时 1 微秒。
对 getrusage 的调用次数为 5.299 亿次。
总用户时间和系统时间为 14320833 微秒和 85683415 微秒,与top执行期间报告的结果非常吻合。

相关内容