詳解如何在C/C++中測(cè)量一個(gè)函數(shù)或功能的運(yùn)行時(shí)間
最常用的clock()
最常用的測(cè)量方法是使用clock()來記錄兩個(gè) CPU 時(shí)間點(diǎn)clock_t,然后做差。這個(gè)方法的好處在于非常簡(jiǎn)單易寫,如下(第一行是為說明需要導(dǎo)入哪個(gè)庫(kù)):
#include <time.h>
.....
clock_t begin = clock();
...需要被測(cè)量的代碼
clock_t end = clock();
int duration = (end - begin)/CLOCKS_PER_SEC;
需要注意 3 點(diǎn):
CLOCKS_PER_SEC在 macOS 上是 1000000,也就是說(end - begin)的單位是微秒,所以要除以CLOCKS_PER_SEC。- 不同平臺(tái)的
clock_t類型是不一樣的,有些平臺(tái)是整數(shù)型,有些是使用浮點(diǎn)型。如果是浮點(diǎn)型的話,CLOCKS_PER_SEC或許可以不用寫,還是要看time.h的相關(guān)內(nèi)容。 - 這個(gè)方法中的“clock”一詞表示的是時(shí)鐘頻率,而不是時(shí)間。早期的計(jì)算機(jī)是固定頻率的(現(xiàn)在的一些計(jì)算器或者單片機(jī)其實(shí)也是固定頻率的),這個(gè)方法就是誕生于那個(gè)時(shí)間的。
這種方法最大的弊端就是它測(cè)量是 CPU 運(yùn)行時(shí)間,準(zhǔn)確的說是該進(jìn)程使用 CPU 的時(shí)間。這就導(dǎo)致了對(duì)于非 CPU 密集型程序來說,這個(gè)結(jié)果可能不是那么精確。當(dāng)然導(dǎo)致的最大的問題是并行計(jì)算程序得到的時(shí)間完全不對(duì),而且不能簡(jiǎn)單地使用核心數(shù)計(jì)算得到正確的時(shí)間。
因?yàn)檫@個(gè)方法是將多個(gè) CPU 的運(yùn)行時(shí)間加在一起了,串行計(jì)算的程序完全沒有問題,但是并行計(jì)算的話,CPU 使用率一般不會(huì)達(dá)到或接近核心數(shù)*100%,因?yàn)橛?jì)算機(jī)上還有其他任務(wù)也需要 CPU。比如說如果串行計(jì)算的程序使用率一般在 99% 左右,獲取時(shí)間為 30 秒,但是對(duì)于 6 核的設(shè)備上運(yùn)行的并行計(jì)算程序的話,CPU 使用率達(dá)到 570% 就很不錯(cuò)了,獲取的時(shí)間可能為 27 秒,而實(shí)際上只用了 5 秒。
這是我在使用 ISPC 編寫并行計(jì)算程序的時(shí)候發(fā)現(xiàn)的,所以我想尋找到新的方案,于是我發(fā)現(xiàn)了下一個(gè)方法。
timespec
timespec是一個(gè)簡(jiǎn)單的日歷時(shí)間或者時(shí)間流逝。通過使用日歷時(shí)間可以解決上一節(jié)中無法測(cè)量并行程序的實(shí)際運(yùn)行時(shí)間的問題。但是“簡(jiǎn)單”這點(diǎn)的表現(xiàn)為整數(shù)時(shí)間,也就是說最小的時(shí)間精度是秒,而不是上一種方法中的微秒,不過這對(duì)于復(fù)雜函數(shù)或程序的測(cè)試來說沒啥問題,畢竟 30 分鐘和 31 分鐘的性能差距不過 3.22%。
方法如下(第一行是為說明需要導(dǎo)入哪個(gè)庫(kù)):
#include <time.h>
time_t begin = time(NULL);
...需要被測(cè)量的代碼
time_t end = time(NULL);
int duration = (end - begin);
可以看到比上一種還要簡(jiǎn)單。
但是對(duì)于一些小型的測(cè)試來說,這個(gè)方法又不太行,因?yàn)檎麛?shù)帶來的誤差太大了,比如說 0.6 秒是 1.8 秒性能的三倍,但是在整數(shù)上只為 2 倍甚至是 1 倍(為什么有這個(gè)“甚至”等會(huì)演示可以看到),所以還是需要一個(gè)更精確時(shí)間測(cè)量方法,這個(gè)方法不光要適應(yīng)并行計(jì)算,還要有一定的精度。
clock_gettime()
clock_gettime()可以完美的符合要求,但是使用上有點(diǎn)復(fù)雜。
clock_gettime()是我從文檔的下面發(fā)現(xiàn)的。一開始我找到的是gettimeofday(),然后我去看了一下 IEEE 標(biāo)準(zhǔn)的文檔gettimeofday (opengroup.org),發(fā)現(xiàn)在“FUTURE DIRECTIONS(未來方向)”這一欄表示gettimeofday()可能未來會(huì)被廢棄;在“APPLICATION USAGE(應(yīng)用使用)”這一欄表示應(yīng)用應(yīng)該使用clock_gettime()而不是gettimeofday。這必須得使用clock_gettime()了。

clock_gettime()的復(fù)雜之處在于太精確了。先來看看使用方法(第一行是為說明需要導(dǎo)入哪個(gè)庫(kù)):
#include <time.h>
struct timespec start;
clock_gettime(CLOCK_REALTIME, &start);
...需要被測(cè)量的代碼
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)層面的實(shí)時(shí)時(shí)間;這個(gè)地方還可以用CLOCK_MONOTONIC,這個(gè)值是從系統(tǒng)啟動(dòng)開始一直運(yùn)行的,一直連續(xù)的不跳躍的(除非手動(dòng)改了),這個(gè)要比CLOCK_REALTIME精度小一些,所以更快一些。
可以看到計(jì)算運(yùn)行時(shí)間的代碼,也就是時(shí)間差的表達(dá)式長(zhǎng)了很多,是因?yàn)閏lock_gettime()獲取的時(shí)間分為兩部分:秒和納秒(在某論壇上有人指出在曾經(jīng)的 Mac OS X 上這里是微秒,不確定,不過現(xiàn)在也是納秒了)。秒是int很簡(jiǎn)單的,但是納秒用的是long int,這就涉及到轉(zhuǎn)換的問題了。所以就需要分別計(jì)算兩個(gè)部分,轉(zhuǎn)換合成。
實(shí)際演示(三種方法的對(duì)比)
這里展示一段并行計(jì)算程序在三種測(cè)量時(shí)間方法下的對(duì)比,各位可以看看差別(可以推測(cè)出測(cè)試設(shè)備是 6C6T 的 CPU 哦):

可以看到有時(shí)差別還是挺大的。
以上就是詳解如何在C/C++中測(cè)量一個(gè)函數(shù)或者功能的運(yùn)行時(shí)間的詳細(xì)內(nèi)容,更多關(guān)于在C/C++中測(cè)量函數(shù)運(yùn)行時(shí)間的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++?OpenCV實(shí)現(xiàn)物體尺寸測(cè)量示例詳解
本文主要介紹了利用OpenCV對(duì)物體的尺寸進(jìn)行測(cè)量,即先定位到待測(cè)物體的位置,然后測(cè)量物體的寬高。感興趣的同學(xué)可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2022-01-01
VSCode 使用 Code Runner 插件無法編譯運(yùn)行文件名帶空格的文件問題
這篇文章主要介紹了VSCode 使用 Code Runner 插件無法編譯運(yùn)行文件名帶空格的文件問題,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-07-07
Visual?Studio配置靜態(tài)庫(kù)詳細(xì)步驟和關(guān)鍵配置項(xiàng)
這篇文章主要介紹了Visual?Studio配置靜態(tài)庫(kù)的詳細(xì)步驟和關(guān)鍵配置項(xiàng)的相關(guān)資料,靜態(tài)庫(kù)是一系列預(yù)先編譯好的目標(biāo)文件(.o文件或.obj文件)的集合,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-12-12
C語(yǔ)言實(shí)現(xiàn)掃雷算法簡(jiǎn)易版
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷算法簡(jiǎn)易版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
Qt Widgets庫(kù)的實(shí)現(xiàn)實(shí)例
QtWidgets 提供了豐富的控件和工具,適合開發(fā)傳統(tǒng)桌面應(yīng)用程序本文主要介紹了Qt Widgets庫(kù)的實(shí)現(xiàn)實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-09-09
用C語(yǔ)言來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的虛擬機(jī)
這篇文章主要介紹了用C語(yǔ)言來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的虛擬機(jī),其中棧數(shù)組的部分非常值得學(xué)習(xí),需要的朋友可以參考下2015-07-07
C語(yǔ)言實(shí)現(xiàn)掃雷項(xiàng)目
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
淺談C++ 中的常見的動(dòng)態(tài)內(nèi)存問題
C++動(dòng)態(tài)內(nèi)存管理容易引發(fā)多種嚴(yán)重問題,包括內(nèi)存泄漏、重復(fù)釋放、釋放后使用、new/delete不匹配、未初始化內(nèi)存、越界訪問和異常安全問題,下面就來介紹一下常見的問題,感興趣的可以了解一下2026-01-01
C語(yǔ)言實(shí)現(xiàn)學(xué)籍管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)學(xué)籍管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07

