我正在尝试使用rusage测量各种函数调用的资源使用时间(用户和系统)。我发现我得到的结果是10毫秒的顺序,比如0s 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循环,结果如下:开始于: 0.0s,结束于: 0.7000000s我浏览了很多次,以找到一种可能的方法来获得准确的时间。在linux源代码中遇到了3个参数getrusage,但我不确定如何使用它,因为它需要任务指针作为第一个参数。其中一个链接暗示它与linux版本有关。无论如何,如果有什么方法可以设置精度/粒度,请告诉我。如果没有,请让我知道是否有任何替代getrusage。gettimeofDay似乎没有给出资源使用的细节,所以如果我不能设置精度,那么寻找getrusage的实际实现。
发布于 2013-09-27 16:28:17
许多操作系统不会对进程使用的时间进行精确计算。在许多情况下,在每次上下文切换和系统调用时读取时钟的成本太高,而在其他情况下,硬件甚至可能没有时钟来让您精确地对事物进行计时。
从getrusage获得的一种非常常用的记账方法是使用100 at (最常见的是100 at,尽管64 at和1024 at也很常见)计时器中断,它对中断发生时系统上发生的事情进行采样。因此,内核每秒100次检查当前正在运行的内容以及运行位置( ru_utime的用户空间或ru_stime的内核空间),并递增一个计数器。然后,该计数器被解释为您的程序运行10ms。
您可以在您的系统上试验clock_gettime,看看它是否有每个进程的计数器,有时这些计数器可能比getrusage计数器更精确。但我不会抱太大希望,如果10ms的分辨率是getrusage所能做的最好的,那么很可能clock_gettime也不会有更好的分辨率,也不会有更好的每进程时钟。
如果操作系统中的时钟不足以进行测量,那么您唯一的选择就是重复测试运行几分钟,然后将得到的结果除以运行次数。
gettimeofday更精确这一事实并没有多大意义。gettimeofday可能相对较贵。想一想内核为了准确跟踪进程的用户和系统时间而必须做的工作。每次进行系统调用时,它都必须获取两次时间戳(一次用于系统调用的开始,一次用于系统调用的结束),以便跟踪您使用了多少系统时间。为了跟踪用户时间,您需要在每次系统切换到另一个进程时打开时间戳。许多系统确实跟踪第二个,但不是第一个,因为系统调用比进程上下文切换更常见(这就是为什么我建议检查clock_gettime,因为它可以有一个计时器,用于累计进程的总系统和用户时间)。
现代系统中的时钟是相当烦人的,因为即使获取时间戳是最常见的系统调用之一,我们仍然经常需要在缓慢的总线中搜索并进行大量锁定才能获得它们。其他解决方案,如cpu上的周期计数器,已被使用,但这些解决方案是出了名的不准确,因为它们可能在CPU之间不同步,可能具有可变频率,可能在操作系统控制之外停止,等等,并且您需要知道CPU的确切型号才能可靠地使用它们。操作系统有很多启发式方法来确定使用哪个时钟,但这可能意味着两台几乎相同的机器之间存在巨大的差异。一个可能得到一个亚纳秒精度的周期计数器,它需要花费一条指令来读取,而另一个需要通过ISA总线到一个30年前的微秒精度的芯片设计,甚至更糟,这需要数千个周期来读取。
发布于 2013-10-01 12:13:04
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 );
}结果:
first run > gcc getclk.c -o dfkj -lrt
getclk.c:在函数‘main’中:
getclk.c:40:警告:内置函数“memset”的隐式声明不兼容
。/dfkj.
对clockGetTime提供的各种定时器的检查
cpu时间
第0秒
ns 54502537
实时
第0秒
ns 53748970
单调
第0秒
ns 55456758
线程
第0秒
ns 58649229
日间秒=0
日间usec=56991
第二次运行>./dfkj
对clockGetTime提供的各种定时器的检查
cpu时间
第0秒
ns 54220021
实时
第0秒
ns 52774966
单调
第0秒
ns 53636163
线程
第0秒
ns 53357492
日间秒=0
日间usec=56176
发布于 2013-10-02 05:36:23
在2013-10-01 4:48 PM,Saurabh写道:
你好,道格拉斯,我是
。我在堆栈溢出时看到了你的响应。不知何故,当我运行getrusage时,它不能以微秒为单位给出结果。但以毫秒为单位。如果你有解决这个问题的办法,请告诉我。否则,请建议我使用API来替代getrusage。
是的,getrusage在我的Linux系统上也有ms精度。它只在我的OS X工作站上以µs精度返回。It says this in my post that you reference, if you look carefully:“我的系统上的精度是1µs,但我也在Linux系统上进行了测试(Red Hat4.1.2-48和GCC 4.1.2),那里的精度只有1ms。”
关于你对替代功能的要求,我同意Art的观点。据我所知,clock_getTime为Linux提供了最好的时钟。唯一的问题是,它相对较新,所以不是很便携(例如,OS X没有)。然而,如果你想要精确的计时,并且你使用的是Linux,我推荐clock_gettime。
https://stackoverflow.com/questions/19043873
复制相似问题