c/c++測試函數的運行時間(八種方法)


目前,存在着各種計時函數,一般的處理都是先調用計時函數,記下當前時間tstart,然后處理一段程序,再調用計時函數,記下處理后的時間tend,再tend和tstart做差,就可以得到程序的執行時間,但是各種計時函數的精度不一樣.下面對各種計時函數,做些簡單記錄.

void foo() { long i; for (i=0;i<100000000;i++) { long a= 0; a = a+1; } }

 

 

方法1,time()獲取當前的系統時間,返回的結果是一個time_t類型,其實就是一個大整數,其值表示從CUT(Coordinated Universal Time)時間1970年1月1日00:00:00(稱為UNIX系統的Epoch時間)到當前時刻的秒數.

void test1()
{
    time_t start,stop; start = time(NULL); foo();//dosomething stop = time(NULL); printf("Use Time:%ld\n",(stop-start)); }

 

 

方法2,clock()函數返回從“開啟這個程序進程”到“程序中調用clock()函數”時之間的CPU時鍾計時單元(clock tick)數,在MSDN中稱之為掛鍾時間(wal-clock)常量CLOCKS_PER_SEC,它用來表示一秒鍾會有多少個時鍾計時單元。

void test2()
{
    double dur;
    clock_t start,end; start = clock(); foo();//dosomething end = clock(); dur = (double)(end - start); printf("Use Time:%f\n",(dur/CLOCKS_PER_SEC)); }

 

如果你想學習C/C++可以來這個群,首先是三三零,中間是八五九,最后是七六六,里面有大量的學習資料可以下載。

方法3,timeGetTime()函數以毫秒計的系統時間。該時間為從系統開啟算起所經過的時間,是windows api

void test3()
{
    DWORD t1,t2;
    t1 = timeGetTime();
    foo();//dosomething t2 = timeGetTime(); printf("Use Time:%f\n",(t2-t1)*1.0/1000); }

 

 

方法4,QueryPerformanceCounter()這個函數返回高精確度性能計數器的值,它可以以微妙為單位計時.但是QueryPerformanceCounter()確切的精確計時的最小單位是與系統有關的,所以,必須要查詢系統以得到QueryPerformanceCounter()返回的嘀噠聲的頻率.QueryPerformanceFrequency()提供了這個頻率值,返回每秒嘀噠聲的個數.

void test4()
{
    LARGE_INTEGER t1,t2,tc;
    QueryPerformanceFrequency(&tc);
    QueryPerformanceCounter(&t1);
    foo();//dosomething QueryPerformanceCounter(&t2); printf("Use Time:%f\n",(t2.QuadPart - t1.QuadPart)*1.0/tc.QuadPart); }

 

 

 

方法5,GetTickCount返回(retrieve)從操作系統啟動到現在所經過(elapsed)的毫秒數,它的返回值是DWORD

void test5()
{
    DWORD t1,t2;
    t1 = GetTickCount();
    foo();//dosomething t2 = GetTickCount(); printf("Use Time:%f\n",(t2-t1)*1.0/1000); }

 

方法6,RDTSC指令,在Intel Pentium以上級別的CPU中,有一個稱為“時間戳(Time Stamp)”的部件,它以64位無符號整型數的格式,記錄了自CPU上電以來所經過的時鍾周期數。由於目前的CPU主頻都非常高,因此這個部件可以達到納秒級的計時精度。這個精確性是上述幾種方法所無法比擬的.在Pentium以上的CPU中,提供了一條機器指令RDTSC(Read Time Stamp Counter)來讀取這個時間戳的數字,並將其保存在EDX:EAX寄存器對中。由於EDX:EAX寄存器對恰好是Win32平台下C++語言保存函數返回值的寄存器,所以我們可以把這條指令看成是一個普通的函數調用,因為RDTSC不被C++的內嵌匯編器直接支持,所以我們要用_emit偽指令直接嵌入該指令的機器碼形式0X0F、0X31

inline unsigned __int64 GetCycleCount() { __asm { _emit 0x0F; _emit 0x31; } } void test6() { unsigned long t1,t2; t1 = (unsigned long)GetCycleCount(); foo();//dosomething t2 = (unsigned long)GetCycleCount(); printf("Use Time:%f\n",(t2 - t1)*1.0/FREQUENCY); //FREQUENCY指CPU的頻率 }

 

 

方法7,gettimeofday() linux環境下的計時函數,int gettimeofday ( struct timeval * tv , struct timezone * tz ),gettimeofday()會把目前的時間有tv所指的結構返回,當地時區的信息則放到tz所指的結構中.

//timeval結構定義為: struct timeval{ long tv_sec; /*秒*/ long tv_usec; /*微秒*/ }; //timezone 結構定義為: struct timezone{ int tz_minuteswest; /*和Greenwich 時間差了多少分鍾*/ int tz_dsttime; /*日光節約時間的狀態*/ }; void test7() { struct timeval t1,t2; double timeuse; gettimeofday(&t1,NULL); foo(); gettimeofday(&t2,NULL); timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec)/1000000.0; printf("Use Time:%f\n",timeuse); }

 

 

方法8,linux環境下,用RDTSC指令計時.與方法6是一樣的.只不過在linux實現方式有點差異.

#if defined (__i386__) static __inline__ unsigned long long GetCycleCount(void) { unsigned long long int x; __asm__ volatile("rdtsc":"=A"(x)); return x; } #elif defined (__x86_64__) static __inline__ unsigned long long GetCycleCount(void) { unsigned hi,lo; __asm__ volatile("rdtsc":"=a"(lo),"=d"(hi)); return ((unsigned long long)lo)|(((unsigned long long)hi)<<32); } #endif void test8() { unsigned long t1,t2; t1 = (unsigned long)GetCycleCount(); foo();//dosomething t2 = (unsigned long)GetCycleCount(); printf("Use Time:%f\n",(t2 - t1)*1.0/FREQUENCY); //FREQUENCY CPU的頻率 } 

 

 總結,方法1,2,7,8可以在linux環境下執行,方法1,2,3,4,5,6可以在windows環境下執行.其中,timeGetTime()和GetTickCount()的返回值類型為DWORD,當統計的毫妙數過大時,將會使結果歸0,影響統計結果. 
測試結果,windows環境下,主頻為1.6GHz,單位為秒.

1 Use Time:0 
2 Use Time:0.390000 
3 Use Time:0.388000 
4 Use Time:0.394704 
5 Use Time:0.407000 
6 Use Time:0.398684


免責聲明!

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



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