詳解如何在C/C++中測量一個函數(shù)或功能的運(yùn)行時間
最常用的clock()
最常用的測量方法是使用clock()
來記錄兩個 CPU 時間點clock_t
,然后做差。這個方法的好處在于非常簡單易寫,如下(第一行是為說明需要導(dǎo)入哪個庫):
#include <time.h> ..... clock_t begin = clock(); ...需要被測量的代碼 clock_t end = clock(); int duration = (end - begin)/CLOCKS_PER_SEC;
需要注意 3 點:
CLOCKS_PER_SEC
在 macOS 上是 1000000,也就是說(end - begin)
的單位是微秒,所以要除以CLOCKS_PER_SEC
。- 不同平臺的
clock_t
類型是不一樣的,有些平臺是整數(shù)型,有些是使用浮點型。如果是浮點型的話,CLOCKS_PER_SEC
或許可以不用寫,還是要看time.h
的相關(guān)內(nèi)容。 - 這個方法中的“clock”一詞表示的是時鐘頻率,而不是時間。早期的計算機(jī)是固定頻率的(現(xiàn)在的一些計算器或者單片機(jī)其實也是固定頻率的),這個方法就是誕生于那個時間的。
這種方法最大的弊端就是它測量是 CPU 運(yùn)行時間,準(zhǔn)確的說是該進(jìn)程使用 CPU 的時間。這就導(dǎo)致了對于非 CPU 密集型程序來說,這個結(jié)果可能不是那么精確。當(dāng)然導(dǎo)致的最大的問題是并行計算程序得到的時間完全不對,而且不能簡單地使用核心數(shù)計算得到正確的時間。
因為這個方法是將多個 CPU 的運(yùn)行時間加在一起了,串行計算的程序完全沒有問題,但是并行計算的話,CPU 使用率一般不會達(dá)到或接近核心數(shù)*100%
,因為計算機(jī)上還有其他任務(wù)也需要 CPU。比如說如果串行計算的程序使用率一般在 99% 左右,獲取時間為 30 秒,但是對于 6 核的設(shè)備上運(yùn)行的并行計算程序的話,CPU 使用率達(dá)到 570% 就很不錯了,獲取的時間可能為 27 秒,而實際上只用了 5 秒。
這是我在使用 ISPC 編寫并行計算程序的時候發(fā)現(xiàn)的,所以我想尋找到新的方案,于是我發(fā)現(xiàn)了下一個方法。
timespec
timespec
是一個簡單的日歷時間或者時間流逝。通過使用日歷時間可以解決上一節(jié)中無法測量并行程序的實際運(yùn)行時間的問題。但是“簡單”這點的表現(xiàn)為整數(shù)時間,也就是說最小的時間精度是秒,而不是上一種方法中的微秒,不過這對于復(fù)雜函數(shù)或程序的測試來說沒啥問題,畢竟 30 分鐘和 31 分鐘的性能差距不過 3.22%。
方法如下(第一行是為說明需要導(dǎo)入哪個庫):
#include <time.h> time_t begin = time(NULL); ...需要被測量的代碼 time_t end = time(NULL); int duration = (end - begin);
可以看到比上一種還要簡單。
但是對于一些小型的測試來說,這個方法又不太行,因為整數(shù)帶來的誤差太大了,比如說 0.6 秒是 1.8 秒性能的三倍,但是在整數(shù)上只為 2 倍甚至是 1 倍(為什么有這個“甚至”等會演示可以看到),所以還是需要一個更精確時間測量方法,這個方法不光要適應(yīng)并行計算,還要有一定的精度。
clock_gettime()
clock_gettime()可以完美的符合要求,但是使用上有點復(fù)雜。
clock_gettime()是我從文檔的下面發(fā)現(xiàn)的。一開始我找到的是gettimeofday(),然后我去看了一下 IEEE 標(biāo)準(zhǔn)的文檔gettimeofday (opengroup.org),發(fā)現(xiàn)在“FUTURE DIRECTIONS(未來方向)”這一欄表示gettimeofday()可能未來會被廢棄;在“APPLICATION USAGE(應(yīng)用使用)”這一欄表示應(yīng)用應(yīng)該使用clock_gettime()而不是gettimeofday。這必須得使用clock_gettime()了。
clock_gettime()
的復(fù)雜之處在于太精確了。先來看看使用方法(第一行是為說明需要導(dǎo)入哪個庫):
#include <time.h> struct timespec start; clock_gettime(CLOCK_REALTIME, &start); ...需要被測量的代碼 struct timespec end; clock_gettime(CLOCK_REALTIME, &end); double duration = (double)(end.tv_nsec-start.tv_nsec)/((double) 1e9) + (double)(end.tv_sec-start.tv_sec);
clock_gettime()的參數(shù)CLOCK_REALTIME表示系統(tǒng)層面的實時時間;這個地方還可以用CLOCK_MONOTONIC,這個值是從系統(tǒng)啟動開始一直運(yùn)行的,一直連續(xù)的不跳躍的(除非手動改了),這個要比CLOCK_REALTIME精度小一些,所以更快一些。
可以看到計算運(yùn)行時間的代碼,也就是時間差的表達(dá)式長了很多,是因為clock_gettime()獲取的時間分為兩部分:秒和納秒(在某論壇上有人指出在曾經(jīng)的 Mac OS X 上這里是微秒,不確定,不過現(xiàn)在也是納秒了)。秒是int很簡單的,但是納秒用的是long int,這就涉及到轉(zhuǎn)換的問題了。所以就需要分別計算兩個部分,轉(zhuǎn)換合成。
實際演示(三種方法的對比)
這里展示一段并行計算程序在三種測量時間方法下的對比,各位可以看看差別(可以推測出測試設(shè)備是 6C6T 的 CPU 哦):
可以看到有時差別還是挺大的。
以上就是詳解如何在C/C++中測量一個函數(shù)或者功能的運(yùn)行時間的詳細(xì)內(nèi)容,更多關(guān)于在C/C++中測量函數(shù)運(yùn)行時間的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實現(xiàn)查詢自動售貨機(jī)中的商品價格【實例分享】
本文主要介紹了C語言實現(xiàn)查詢自動售貨機(jī)中的商品價格的相關(guān)資料。具有很好的參考價值。下面跟著小編一起來看下吧2017-04-04DHCP:解析開發(fā)板上動態(tài)獲取ip的2種實現(xiàn)方法詳解
本篇文章是對開發(fā)板上動態(tài)獲取ip的2種實現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C語言實現(xiàn)簡易通訊錄(靜態(tài)版本)的代碼分享
這篇文章主要為大家詳細(xì)介紹了如何錄音C語言實現(xiàn)一個簡易的通訊錄(靜態(tài)版本),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-10-10C++結(jié)構(gòu)體數(shù)組實現(xiàn)貪吃蛇
這篇文章主要為大家詳細(xì)介紹了C++結(jié)構(gòu)體數(shù)組實現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-03-03通過C++獲取CPU占用率的代碼示例(windows、linux、macOS)
本文介紹了在Windows、Linux和macOS平臺下使用C++獲取CPU占用率的多種方法,包括系統(tǒng)整體CPU占用率和特定進(jìn)程CPU占用率的計算公式和實現(xiàn)代碼示例,需要的朋友可以參考下2025-03-03