C語言中常用計時方法總結


轉自:http://blog.csdn.net/fz_ywj/article/details/8109368

 

C語言中常用計時方法總結

1. time()

頭文件:time.h

函數原型:time_t time(time_t * timer)

功能:返回以格林尼治時間(GMT)為標准,從1970年1月1日00:00:00到現在的此時此刻所經過的秒數。

用time()函數結合其他函數(如:localtime、gmtime、asctime、ctime)可以獲得當前系統時間或是標准時間。

用difftime函數可以計算兩個time_t類型的時間的差值,可以用於計時。用difftime(t2,t1)要比t2-t1更准確,因為C標准中並沒有規定time_t的單位一定是秒,而difftime會根據機器進行轉換,更可靠。

用法

 

[cpp]  view plain copy print ?
 
  1. time_t start,end;  
  2. start =time(NULL);//or time(&start);  
  3. //…calculating…  
  4. end =time(NULL);  
  5. printf("time=%d\n",difftime(end,start));  
總結:C標准庫中的函數,可移植性最好,性能也很穩定,但精度太低,只能精確到秒,對於一般的事件計時還算夠用,而對運算時間的計時就明顯不夠用了。

2. clock()

頭文件:time.h

函數原型:clock_t clock(void);

功能:該函數返回值是硬件滴答數,要換算成秒,需要除以CLK_TCK或者 CLK_TCKCLOCKS_PER_SEC。比如,在VC++6.0下,這兩個量的值都是1000。

用法

 

[cpp]  view plain copy print ?
 
  1. clock_t start,end;  
  2. start = clock();  
  3. //…calculating…  
  4. end = clock();  
  5. printf("time=%f\n",(double)end-start)/CLK_TCK);  
總結:可以精確到毫秒,適合一般場合的使用。

3. timeGetTime()

WIN32API

頭文件:Mmsystem.h  引用庫: Winmm.lib

函數原型:DWORD timeGetTime(VOID);

功能:返回系統時間,以毫秒為單位。系統時間是從系統啟動到調用函數時所經過的毫秒數。注意,這個值是32位的,會在0到2^32之間循環,約49.71天。

用法

 

[cpp]  view plain copy print ?
 
  1. DWORDstart,end;  
  2. start= timeGetTime();  
  3. //…calculating…  
  4. end= timeGetTime();  
  5. printf("time=%d\n",end-start);  
總結:該函數的時間精度是五毫秒或更大一些,這取決於機器的性能。可用timeBeginPeriod和timeEndPeriod函數提高timeGetTime函數的精度。如果使用了,連續調用timeGetTime函數,一系列返回值的差異由timeBeginPeriod和timeEndPeriod決定。

4. GetTickCount()

WIN32API

頭文件:windows.h

函數原型:DWORD WINAPI GetTickCount(void);

功能:返回自設備啟動后的毫秒數(不含系統暫停時間)。

用法

 

[cpp]  view plain copy print ?
 
  1. DWORDstart,end;  
  2. start= GetTickCount();  
  3. //…calculating…  
  4. end= GetTickCount();  
  5. printf("time=%d\n",end-start);  
總結:精確到毫秒。對於一般的實時控制,使用GetTickCount()函數就可以滿足精度要求。

5. QueryPerformanceCounter()、QueryPerformanceFrequency()

WIN32API

頭文件:windows.h

函數原型:BOOLQueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);

          BOOLQueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);

功能:前者獲得的是CPU從開機以來執行的時鍾周期數。后者用於獲得你的機器一秒鍾執行多少次,就是你的時鍾周期。

補充:LARGE_INTEGER既可以是一個8字節長的整型數,也可以是兩個4字節長的整型數的聯合結構, 其具體用法根據編譯器是否支持64位而定:

 

[cpp]  view plain copy print ?
 
  1. typedef union_LARGE_INTEGER  
  2. {  
  3.     struct  
  4.     {  
  5.         DWORD LowPart ;  
  6.         LONG HighPart;  
  7.     };  
  8.     LONGLONG QuadPart ;  
  9. }LARGE_INTEGER;  

 

用法

在進行定時之前,先調用QueryPerformanceFrequency()函數獲得機器內部定時器的時鍾頻率,然后在需要嚴格定時的事件發生之前和發生之后分別調用QueryPerformanceCounter()函數,利用兩次獲得的計數之差及時鍾頻率,計算出事件經歷的精確時間。

 

[cpp]  view plain copy print ?
 
  1. LARGE_INTEGER  num;  
  2. longlong start,end,freq;  
  3. QueryPerformanceFrequency(&num);  
  4. freq=num.QuadPart;  
  5. QueryPerformanceCounter(&num);   
  6. start= num.QuadPart;   
  7. //…calculating…  
  8. QueryPerformanceCounter(&num);   
  9. end= num.QuadPart;    
  10. printf("time=%d\n",(end-start)*1000/freq);  
總結:這種方法的定時誤差不超過1微秒,精度與CPU等機器配置有關,一般認為精度為透微秒級。在Windows平台下進行高精度計時的時候可以考慮這種方法。

6. gettimeofday()

Linux C函數。

頭文件:sys/time.h

函數原型:int gettimeofday(struct timeval *tv,struct timezone *tz);

說明:其參數tv是保存獲取時間結果的結構體,參數tz用於保存時區結果(若不使用則傳入NULL即可)。

timeval的定義為:

 

[cpp]  view plain copy print ?
 
  1. struct timeval {  
  2.   long tv_sec; // 秒數  
  3.   long tv_usec; //微秒數  
  4. }  
可見該函數可用於在linux中獲得微秒精度的時間。

用法

 

[cpp]  view plain copy print ?
 
  1. struct timeval start,end;  
  2. gettimeofday(&start, NULL );  
  3. //…calculating…  
  4. gettimeofday(&end, NULL );  
  5. long timeuse =1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;  
  6. printf("time=%f\n",timeuse /1000000.0);  
總結:使用這種方式計時,精度可達微秒。經驗證,在arm+linux的環境下此函數仍可使用。推薦。

7. RDTSC - 讀取時間標簽計數器

X86架構CPU匯編指令。

操作碼:0F 31 指令:RDTSC

功能:將時間標簽計數器讀入 EDX:EAX寄存器中。

說明:在Pentium以上的CPU中,提供了一條機器指令RDTSC來讀取這個時間戳的數字,並將其保存在EDX:EAX寄存器對中。由於EDX:EAX寄存器對恰好是Win32平台下C++語言保存函數返回值的寄存器,所以我們可以把這條指令看成是一個普通的函數調用:

 

[cpp]  view plain copy print ?
 
  1. inline unsigned long longGetCycleCount()   
  2. {   
  3.     __asm RDTSC   
  4. }  
如果編譯器不允許直接用RDTSC的話,可以用_emit偽指令直接嵌入該指令的機器碼形式0X0F、0X31:

 

[cpp]  view plain copy print ?
 
  1. inline unsigned long long GetCycleCount()   
  2. {  
  3.     __asm _emit 0x0F   
  4.     __asm _emit 0x31  
  5. }   
計算時還需要將得到的數字除以CPU的主頻(單位GHZ),就能得到納秒級的時間了。暫時我還沒找到好的獲得機器主頻的方法,Windows平台下可以考慮用QueryPerformanceFrequency()函數,但這樣一來就沒辦法在Linux下使用此方法。后來我考慮配合sleep函數,獲取1秒中的機器周期數的方法來得到CPU主頻。如果哪位有更好的方法,還請多多請教。

 

[cpp]  view plain copy print ?
 
  1. #ifdef WIN32  
  2. #include <windows.h>  
  3. #else  
  4. #include <sys/unistd.h>  
  5. #endif  
  6. inline unsigned long long GetNTime()  
  7. {  
  8.     __asm("RDTSC");  
  9. }  
  10.   
  11. static double hz=0.0;  
  12.   
  13. void init_timer()  
  14. {  
  15.     longlong t1=GetNTime();  
  16. #ifdef WIN32  
  17.     Sleep(1000);  
  18. #else  
  19.     sleep(1);  
  20. #endif  
  21.     longlong t=GetNTime()-t1;  
  22.     hz=(double)t/1000000000;  
  23.     printf("hz=%fGhz\n",hz);  
  24. }  
  25.   
  26. long long u_timer(long long *t,int mode)  
  27. {  
  28.     if(hz<0.001)  
  29.         init_timer();  
  30.     if(!mode)  
  31.     {  
  32.         *t=GetNTime();  
  33.         return0;  
  34.     }  
  35.   
  36.     longlong t1=GetNTime()-*t;  
  37.     t1/=hz;  
  38.     longlong ns=t1%1000;  
  39.     longlong us=(t1/1000)%1000;  
  40.     longlong ms=(t1/1000000)%1000;  
  41.     longlong s=t1/1000000000;  
  42.   
  43.     printf("time=");  
  44.     if(s!=0)  
  45.         printf("%llds",s);  
  46.     if(ms!=0)  
  47.         printf("%lldms",ms);  
  48.     if(us!=0)  
  49.         printf("%lldus",us);  
  50.     if(ns!=0)  
  51.         printf("%lldns",ns);  
  52.     printf("\n");  
  53.   
  54.     *t=GetNTime();  
  55.     returnt1;  
  56. }  
總結:這種方法精確到納秒,但缺點是非常短時間的計時會不穩定。最近因為項目需要,我也找了一下ARM+Linux平台上可以用的計時方法,后來選擇了gettimeofday()。不知道ARM+Linux平台上有沒有類似RDTSC的這種指令。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM