2016-02-09 61 views
3

我有一個腳本,使用bash內建命令time來測量程序的執行時間。bash內建時間命令的精度是多少?

我想了解這個命令的精確度:據我所知,它返回精度以毫秒爲單位,但它使用getrusage()函數,它返回一個以微秒爲單位的值。但是讀取this paper時,實際精度僅爲10ms,因爲getrusage會依靠刻度(= 100Hz)對時間進行採樣。這篇文章真的很老了(它提到運行在Pentium 166Mhz和96Mb RAM上的Linux 2.2.14)。

time仍然使用getrusage()和100赫茲刻度或更精確的現代系統?

測試機器運行的是Linux 2.6.32。

EDIT:這是一個稍作修改的版本(其也應彙編關於舊版本的GCC)的穆魯的代碼:爲了當場修改變量和「v」也變化的措施之間的延遲的值最小粒度。約50萬的值應該觸發一個相對較新的CPU

#include <sys/time.h> 
#include <sys/resource.h> 
#include <stdio.h> 

void dosomething(){ 
    long v = 1000000; 
     while (v > 0) 
      v--; 
} 

int main() 
{ 
    struct rusage r1, r2; 
    long t1, t2, min, max; 
    int i; 

    printf("t1\tt2\tdiff\n"); 

    for (i = 0; i<5; i++){ 
     getrusage(RUSAGE_SELF, &r1); 
     dosomething(); 
     getrusage(RUSAGE_SELF, &r2); 

     t1 = r1.ru_stime.tv_usec + r1.ru_stime.tv_sec*1000000 + r1.ru_utime.tv_usec + r1.ru_utime.tv_sec*1000000; 
     t2 = r2.ru_stime.tv_usec + r2.ru_stime.tv_sec*1000000 + r2.ru_utime.tv_usec + r2.ru_utime.tv_sec*1000000; 

     printf("%ld\t%ld\t%ld\n",t1,t2,t2-t1); 

     if ((t2-t1 < min) | (i == 0)) 
      min = t2-t1; 

     if ((t2-t1 > max) | (i == 0)) 
      max = t2-t1; 
     dosomething(); 

    } 

    printf("Min = %ldus Max = %ldus\n",min,max); 

    return 0; 
} 

然而精度被綁定到Linux版本(的i5/i7的@〜2.5Ghz的第一版本)爲1ms的變化:使用Linux 3及以上的精度是按照我們的順序,而在Linux 2.6.32上可能會在1ms左右,可能還取決於具體的發行版。我想這種差異與在最近的linux版本中使用HRT而不是Tick相關。

在任何情況下,在所有最近和未近期的機器上,最大時間精度爲1ms。

回答

5

bash內建time仍然使用getrusage(2)。在Ubuntu 14.04系統:

$ bash --version 
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) 
Copyright (C) 2013 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 

This is free software; you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. 
$ strace -o log bash -c 'time sleep 1' 

real 0m1.018s 
user 0m0.000s 
sys 0m0.001s 
$ tail log 
getrusage(RUSAGE_SELF, {ru_utime={0, 0}, ru_stime={0, 3242}, ...}) = 0 
getrusage(RUSAGE_CHILDREN, {ru_utime={0, 0}, ru_stime={0, 530}, ...}) = 0 
write(2, "\n", 1)      = 1 
write(2, "real\t0m1.018s\n", 14)  = 14 
write(2, "user\t0m0.000s\n", 14)  = 14 
write(2, "sys\t0m0.001s\n", 13)   = 13 
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 
exit_group(0)       = ? 
+++ exited with 0 +++ 

由於strace輸出所示,它調用getrusage

至於精度,getrusage使用的rusage結構包括timeval對象,並且timeval具有微秒精度。從manpage of getrusage

ru_utime 
     This is the total amount of time spent executing in user mode, 
     expressed in a timeval structure (seconds plus microseconds). 

ru_stime 
     This is the total amount of time spent executing in kernel 
     mode, expressed in a timeval structure (seconds plus 
     microseconds). 

我認爲它比10毫秒更好。採取以下示例文件:

#include <sys/time.h> 
#include <sys/resource.h> 
#include <stdio.h> 

int main() 
{ 
    struct rusage now, then; 
    getrusage(RUSAGE_SELF, &then); 
    getrusage(RUSAGE_SELF, &now); 
    printf("%ld %ld\n", 
     then.ru_stime.tv_usec + then.ru_stime.tv_sec*1000000 + then.ru_utime.tv_usec + then.ru_utime.tv_sec*1000000 
     now.ru_stime.tv_usec + now.ru_stime.tv_sec*1000000 + now.ru_utime.tv_usec + now.ru_utime.tv_sec*1000000); 
} 

目前:

$ make test 
cc  test.c -o test 
$ for ((i=0; i < 5; i++)); do ./test; done 
447 448 
356 356 
348 348 
347 347 
349 350 

報告連續調用之間的差異,以getrusage是1微秒和0(最小值)。由於它確實顯示1微秒的間隔,所以刻度必須至多爲1微秒。

如果它有一個10毫秒的勾號,差異將爲零,或至少10000.

+1

謝謝,似乎是合理的。看看我關於RTOS的舊筆記,似乎Linux tick可以配置爲100,250和1000Hz,還有高精度定時器,它比1ms更精確。 也許我想念一些東西,但我認爲你應該乘以1,000,000,因爲1s = 10^-6s 但是對於我的目的,我可以假設時間(1ms)報告的最大精度 –

+0

@AlessandroValentini糟糕。這是重複使用測試代碼的結果。 :D – muru

+0

無論如何它不影響測試,直到你運行短程序;) –