5

我正在尝试使用 rusage 测量各种函数调用的资源使用时间(用户和系统)。我发现我得到的结果大约是 10 毫秒,例如 0 秒 70000us、10000us 等。如果有办法为 getrusage 设置精度/粒度,请告诉我。

我的程序很简单:

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

int main(){
  struct rusage usage;
  struct timeval start, end;
  int i, j, k = 0;

  getrusage(RUSAGE_SELF, &usage);
  start = usage.ru_utime;
  printf("buffer check\n");
  char *str = "---";
  int arr[100],ctr;

  for(ctr = 0;ctr<100;ctr++){

    arr[ctr] = ctr + 1000;

  }

  for (i = 0; i < 10000; i++) {
     for (j = 0; j < 10000; j++) {
      k += 20;
  }
 }

 getrusage(RUSAGE_SELF, &usage);
 end = usage.ru_utime;

 printf("Started at: %ld.%lds\n", start.tv_sec, start.tv_usec);
 printf("Ended at: %ld.%lds\n", end.tv_sec, end.tv_usec);

 return 1;
}

结果开始于:0.0s 结束于:0.2000000s

我添加了另一个 for 循环,得到的结果如下: Started at: 0.0s Ended at: 0.7000000s 我浏览了很多内容以找到一种可能的方法来获得准确的时间。在linux源等中遇到3个参数getrusage,但我不确定如何使用它,因为它需要任务指针作为第一个参数。链接之一表明它与 linux 版本有关。无论如何,如果有任何方法可以设置精度/粒度,请告诉我。如果没有,请告诉我是否有任何替代 getrusage 的方法。gettimeofDay 似乎没有提供资源使用详细信息,因此如果我无法设置精度,请寻找 getrusage 的实际实现。

4

3 回答 3

4

许多操作系统不会精确计算进程使用的时间。在许多情况下,在每次上下文切换和系统调用时读取时钟的成本太高,在其他情况下,硬件甚至可能没有时钟来让您以任何精度对事物进行计时。

一种非常常用的记账方法getrusage是使用 100Hz(通常是 100Hz,尽管 64Hz 和 1024Hz 也很常见)定时器中断来采样中断时系统上发生的事情。因此,内核每秒 100 次检查当前正在运行的内容和位置(ru_utime 的用户空间或 ru_stime 的内核空间)并增加一个计数器。然后将该计数器解释为您的程序运行了 10 毫秒。

您可以clock_gettime在您的系统上进行试验,看看它是否具有每个进程的计数器,有时这些计数器可能比getrusage计数器更精确。但是我不会抱有希望,如果 10 毫秒的分辨率是最好getrusage的,那么很可能clock_gettime不会有更好的分辨率或任何每个进程的时钟。

如果操作系统中的时钟对于您的测量来说不够好,您唯一的选择是重复您的测试运行几分钟,然后将您获得的任何结果除以运行次数。

更精确的事实gettimeofday并不意味着什么。gettimeofday可能相对昂贵。想想内核为了准确跟踪进程的用户和系统时间而必须做的工作。每次进行系统调用时,都必须使用两次时间戳(一次用于系统调用的开始,一次用于结束),以跟踪您使用了多少系统时间。为了跟踪用户时间,每次系统切换到另一个进程时,您都需要时间戳。许多系统确实跟踪第二个,但不是第一个,因为系统调用比进程上下文切换更常见(这就是我建议检查的原因,clock_gettime因为它可以有一个计时器来累积进程的总系统和用户时间)。

现代系统中的时钟非常烦人,因为即使获取时间戳是最常见的系统调用之一,我们仍然经常需要通过缓慢的总线并进行重度锁定来获取它们。已经使用了其他解决方案,例如 cpu 上的循环计数器,但这些解决方案非常不准确,因为它们可能在 CPU 之间不同步,可能具有可变频率,可以在操作系统控制之外停止等等,您需要知道您的 CPU 的确切型号,以便能够可靠地使用它们。操作系统有很多启发式方法来确定要使用哪些时钟,但这可能意味着两台几乎相同的机器之间存在巨大差异。

于 2013-09-27T08:28:16.727 回答
0
My new program:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
//int clock_gettime(clockid_t clk_id, struct timespect *tp);

#define BILLION  1000000000L;

void testClockGetTime(clockid_t clk_id , struct timespec *start , struct timespec  *stop){

   long temp = 0,i;
   unsigned long accumsec,accumns;
   if( clock_gettime( clk_id, start) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
   }
   for ( i = 0; i< 24222000; i++)
       temp+=temp;

   if( clock_gettime( clk_id, stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }
    accumsec = stop->tv_sec - start->tv_sec;
    accumns =  stop->tv_nsec - start->tv_nsec;
    if(stop->tv_nsec<start->tv_nsec){
       accumsec = accumsec - 1;
       accumns = start->tv_nsec - stop->tv_nsec;
    }

    printf( " sec %ld\n", accumsec );
    printf(" ns %ld\n", accumns );

  }

int main( int argc, char **argv )
 {
   struct timespec start, stop;
   struct timeval tds,tdse;
   memset(&tds,0,sizeof(struct timeval));
   memset(&tdse,0,sizeof(struct timeval));
   unsigned long accumsec,accumns;
   long timesec, timeusec;
   printf("checking on various timers gives by clockGetTime \n");
   printf("cpu time\n");
   memset(&stop,0,sizeof(struct timespec));
   memset(&start,0,sizeof(struct timespec));
   testClockGetTime(CLOCK_PROCESS_CPUTIME_ID , &start,&stop);
   memset(&start,0,sizeof(struct timespec));
   memset(&stop,0,sizeof(struct timespec));
   printf("real time\n");    
   testClockGetTime(CLOCK_REALTIME,&start,&stop);
   memset(&start,0,sizeof(struct timespec));
   memset(&stop,0,sizeof(struct timespec));
   printf("monotonic\n");    
   testClockGetTime(CLOCK_MONOTONIC,&start,&stop);
   memset(&start,0,sizeof(struct timespec));
   memset(&stop,0,sizeof(struct timespec));
   printf("thread\n");
   testClockGetTime(CLOCK_THREAD_CPUTIME_ID,&start,&stop);
   memset(&start,0,sizeof(struct timespec));
   memset(&stop,0,sizeof(struct timespec));
   gettimeofday(&tds, NULL);
   long temp,i;
   for ( i = 0; i< 24222000; i++)
      temp+=temp;
   gettimeofday(&tdse, NULL);
   if( clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    //   accumsec = stop.tv_sec - start.tv_sec; 
    //   accumns =  stop.tv_nsec - start.tv_nsec; 
    //   if(stop.tv_nsec<start.tv_nsec){
    //     accumsec = accumsec - 1;
    //     accumns = start.tv_nsec - stop.tv_nsec;
    //   }

    //   printf( "proc sec %ld\n", accumsec );
    //   printf( "proc ns %ld\n", accumns );
    //    printf("before day =%ld,%ld\n",tds.tv_sec,tds.tv_usec);
    //    printf("after day=%ld,%ld\n",tdse.tv_sec, tdse.tv_usec);
    timesec =  tdse.tv_sec - tds.tv_sec;
    timeusec=  tdse.tv_usec- tds.tv_usec;
  if(tdse.tv_usec < tds.tv_usec){
    timesec = timesec - 1;
    timeusec= tds.tv_usec - tdse.tv_usec;
   }
   printf("daytime sec =%ld\n",timesec);
   printf("daytime usec=%ld\n",timeusec);
   return( EXIT_SUCCESS );
 }

结果:

第一次运行 > gcc getclk.c -o dfkj -lrt

getclk.c:在函数'main'中:

getclk.c:40:警告:内置函数“memset”的隐式声明不兼容

./dfkj

检查由clockGetTime提供的各种计时器

处理器时间

秒 0

ns 54502537

即时的

秒 0

ns 53748970

单调的

秒 0

ns 55456758

线

秒 0

ns 58649229

白天秒 =0

白天 usec=56991

第二次运行>./dfkj

检查由clockGetTime提供的各种计时器

处理器时间

秒 0

ns 54220021

即时的

秒 0

ns 52774966

单调的

秒 0

ns 53636163

线

秒 0

ns 53357492

白天秒 =0

白天使用 = 56176

于 2013-10-01T04:13:03.947 回答
0

在 2013-10-01 下午 4:48,Saurabh 写道:

嗨,道格拉斯,我是 Saurabh。我在堆栈溢出时看到了您的回复。不知何故,当我运行 getrusage 时,它​​不会在微秒内给出结果。但以毫秒为单位。如果您对此有解决办法,请告诉我。否则请建议我使用 API 替换 getrusage。

是的,getrusage 在我的 Linux 系统上也有毫秒精度。它仅在我的 OS X 工作站上以 µs 精度返回。 如果你仔细看的话,你在我的帖子中提到了这一点: “我的系统上的精度是 1 µs,但我也在 Linux 系统(带有 GCC 4.1.2 的 Red Hat 4.1.2-48)上对其进行了测试,并且在那里精度仅为 1 毫秒。”

关于您对替代功能的要求,我同意 Art。据我所知,clock_getTime它提供了迄今为止最好的 Linux 时钟。唯一的问题是它相对较新,所以它不是很便携(例如,OS X 没有它)。不过,如果您想要精确的计时并且您使用的是 Linux,我建议您使用clock_gettime.

于 2013-10-01T21:36:23.397 回答