【C/C++】計時函式比較
目前,存在著各種計時函式,一般的處理都是先呼叫計時函式,記下當前時間tstart,然後處理一段程式,再呼叫計時函式,記下處理後的時間tend,再tend和tstart做差,就可以得到程式的執行時間,但是各種計時函式的精度不一樣.下面對各種計時函式,做些簡單記錄.
方法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)); }
方法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 | time | C系統呼叫 | 低 | <1s |
2 | clcok | C系統呼叫 | 低 | <10ms |
3 | timeGetTime | Windows API | 中 | <1ms |
4 | QueryPerformanceCounter | Windows API | 高 | <0.1ms |
5 | GetTickCount | Windows API | 中 | <1ms |
6 | RDTSC | 指令 | 高 | <0.1ms |
7 | gettimeofday | linux環境下C系統呼叫 | 高 | <0.1ms |
總結,方法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
linux環境下,主頻為2.67GHz,單位為秒
1 Use Time:1 2 Use Time:0.290000 7 Use Time:0.288476 8 Use Time:0.297843
由於time()計時函式的精度比較低,多次執行程式時,將會得到不同的結果,時而為0,時而為1
foo()函式如下:
void foo() { long i; for (i=0;i<100000000;i++) { long a= 0; a = a+1; } }
相關推薦
【C/C++】計時函式比較
目前,存在著各種計時函式,一般的處理都是先呼叫計時函式,記下當前時間tstart,然後處理一段程式,再呼叫計時函式,記下處理後的時間tend,再tend和tstart做差,就可以得到程式的執行時間,但是各種計時函式的精度不一樣.下面對各種計時函式,做些簡單記錄. 方法1,time()獲取當前的系統時
【C語言】字串函式strtok 按照指定字串分割
C語言字串函式 strtok() 函式原型 char *strtok(char *str,const char *delimiters); 引數 str,待分割的字串 delimiters,分隔符字串 該函式用來將字串str分割成一個個片段。 引數str指
5、【C++ STL】仿函式(函式物件)
仿函式(函式物件) 仿函式又稱函式物件,函式物件首先是一個物件,即某個類的例項。其次,函式物件的行為和函式一致,即是說可以像呼叫函式一樣來使用函式物件,如引數傳遞、返回值等。這種行為是通過過載類的()操作符來實現的。 【示例】 class Print {
【C語言】字串函式的實現
求字串的長度 strlen 長度不受限制的字串函式 strcpy strcat strcmp 長度受限制的字串函式 strncpy strncat strncmp 字串查詢 strc
【C語言】字串函式探幽
目錄 1、strcpy() a)如果src長度大於dest會發生什麼? i.執行到strcpy函式之前,檢視a和b的值和記憶體: ii、執行strcpy,觀察記憶體 iii、得出結論 b)如果src長度小於dset呢? c)手寫strcpy d)總結 2、strl
【C語言】main函式的引數解析
main函式 每個C程式都必須有一個main函式,main函式又稱為主函式,是執行程式的起點,它被稱之為函式,是否會像平時使用函式時需要自己的引數呢? 答案是肯定的,那麼他都有那些引數呢? main函式的在vs2017環境下除錯,可以看到main函式裡的三個引數
【C語言】編寫函式實現庫函式atoi,把字串轉換成整形
//編寫函式實現庫函式atoi,把字串轉換成整形 #include <stdio.h> #include <string.h> int my_atoi(const char *
【C語言】printf函式和scanf函式典型例子
<span style="font-size:18px;">#include <stdio.h> void main() { int i; char c; for(i=
【C語言】編寫函式實現:100-200素數的輸出
這裡面,先要理解素數如何求得,可用自己除以2到自己的前一位,根據餘數情況判斷是素數還是合數。優化:(1)從101開始,每次自加2,這樣提高效率一倍。(2)一直除以自己的平方根也可。#include<stdio.h> #include<math.h&g
【C深入】認清函式的真面目
函式的由來與好處——以下摘自陳正衝《C語言深度剖析》其實在組合語言階段,函式這個概念還是比較模糊的。組合語言的程式碼往往就是從入口開始一條一條執行,直到遇到跳轉指令(比如ARM 指令B 、BL 、BX 、BLX 之類)然後才跳轉到目的指令處執行。這個時候所有的程式碼僅僅是按其
【C語言】getchar函式的控制檯輸入原理,回車符的處理
getchar函式的功能是從輸入流讀取一個字元,這是我們要明確的就是: 我們在控制檯需要輸入至少兩個字元才能保證這個函式的執行: 例如: 源程式: char ch; ch = getchar(); 我們需要在標準輸入流裡面輸入 ”w 回車“,就是需要至少輸入兩個字元,一
c語言clock()計時函式(結果很精準)
#include<stdio.h> #include<time.h> clock_t start, stop; //clock_t為clock()函式返回的變數型別 double duration; int main() { start=clock();
【python基礎】sort函式
1. 基本用法 1)僅對於list型別的資料 a.sort() 按升序 a.sort(reverse = True) 按降序 2)對於所有可排序型別的資料 sorted(a, reverse = True) 2. 自定義排序函式 a = ((1,2), (3,1), (2
【深度學習】Tensorflow函式詳解
目錄 tf.truncated_normal tf.random_normal tf.nn.conv2d tf.nn.max_pool tf.reshape tf.nn.softmax tf.reduce_sum tf.reduce_max,tf.r
【gp資料庫】查詢函式中引用資料表資訊
函式指令碼寫得多了,再想統計整理用到的表資訊十分麻煩。甚至存在歷史資料表不再使用的情況,所以需要根據條件對函式引用表資訊進行統計。本篇介紹我常用的指令碼。 1. 查詢某資料表在哪些函式中引用過 select proname from pg_proc w
【STM32F103RCT學習】庫函式雙通道ADC實現
一、連續掃描、連續轉換模式下對規則組的理解 規則組最多包含16個轉換通道,也就是說ADC_NbrOfChannel可以設定上限為16 在每個組的每個通道上執行單次轉換。在每個轉換結束時,同一組的下一個通道被自動轉換。如果設定了ADC_CR2暫存器CONT位為1(從實踐結果
【函式式】純函式與替代模型
純函式 一個函式在程式執行的過程中除了根據輸入引數給出運算結果之外沒有其他的副作用影響,我們可以把這類函式稱為“純函式”。純函式由於不依賴外部變數,使得給定函式輸入其返回結果永遠不變,比如整數的加法函式,它接收兩個整數值並返回一個整數值,對於給定的兩個整數值,
【施工ing】生成函式與多項式——學習筆記
生成函式大概是一個無窮冪級數形式的函式,我們只關心它的形式,而不會去帶入 x 求值。可以看做是多項式,只是帶入沒有意義。它的一些運算可以對應組合意義,所以能通過它解決一些組合問題。 一般生成函式(OGF): f(x)=a0+a1x1+a2x2+a3x3+a4
【重溫基礎】4.函式
本文是 重溫基礎 系列文章的第四篇。 今日感受:常懷感恩之心,對人對己。 系列目錄: 【複習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1.語法和資料型別 【重溫基礎】2.流程控制和錯誤處理 【重溫基礎】3.迴圈和迭代 本
【程式設計筆記】虛擬函式表
如果一個C++類中包含有虛擬函式,C++編譯器在進行編譯時,會通過動態聯編機制,為這個類生成一個“虛擬函式表”。 我們通常把所有的方法都是純虛擬函式的類,叫做:介面類。 class BasicTable { public: virtual voi