【C語言進階】使用gettimeofday為你的程序運行時間做統計
有時候在編程調試的時候,會遇到個別性能問題需要調試,這時候我們需要比較精確地統計每段代碼的耗時情況,這種情況下,你是怎么做的呢?本文介紹一種方法來實現此功能。
1 需求背景
在項目編程中,如果遇到調試代碼性能的時候,慢慢需要加時戳來觀察,找出那些耗時的操作。這種情況大部分需要人工干涉,如果我們需要程序自動幫忙完成耗時分析呢?我們可以怎么做呢?
本文就這個場景問題,提供一種解決方案,歡迎大家參考。
2 簡要分析
2.1 算法分析
根據我們的常識,我們知道,要想知道一個操作的耗時,一般的做法就是在操作前取一個時間,然后操作后取一個時間;最后兩個時間相減,得到的就是這段操作的耗時。
根據這里方法論,我們可以比較快地實現邏輯代碼,但是我們應該用哪個函數取當前時間點呢?
2.2 gettimeofday簡介
在Linux C語言編程中,我們很容易會想到gettimeofday這個函數,下面我們將簡單介紹一下這個函數。
參考Linux下的man說明,如下:
GETTIMEOFDAY(2) Linux Programmer's Manual GETTIMEOFDAY(2)
NAME
** gettimeofday, settimeofday - get / set time**
SYNOPSIS
** #include **
int gettimeofday(struct timeval *tv, struct timezone *tz); ? int settimeofday(const struct timeval *tv, const struct timezone *tz);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
settimeofday(): Since glibc 2.19: _DEFAULT_SOURCE Glibc 2.19 and earlier: _BSD_SOURCE
DESCRIPTION
** The functions gettimeofday() and settimeofday() can get and set the time as well as a timezone.**
The tv argument is a struct timeval (as specified in ): ? struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ }; ? and gives the number of seconds and microseconds since the Epoch (see time(2)). ? The tz argument is a struct timezone: ? struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ }; ? If either tv or tz is NULL, the corresponding structure is not set or returned. (However, compilation warnings will result if tv is NULL.) ? The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL. (See NOTES below.) ? Under Linux, there are some peculiar "warp clock" semantics associated with the settimeofday() system call if on the very first call (after booting) that has a non-NULL tz argument, the tv argument is NULL and the tz_minuteswest field is nonzero. (The tz_dsttime field should be zero for this case.) In such a case it is assumed that the CMOS clock is on local time, and that it has to be incremented by this amount to get UTC system time. No doubt it is a bad idea to use this feature.
RETURN VALUE
** gettimeofday() and settimeofday() return 0 for success, or -1 for failure (in which case errno is set appropriately).**
從這里我們可以知道,gettimeofday用于獲取當前的時間是非常容易的,它會將時間結果存儲在這個結構體中:
struct timeval {
** time_t tv_sec; /* seconds */
** suseconds_t tv_usec; /* microseconds / *
** };
struct timeval 結構體中有 tv_sec 秒參數 和 tv_usec 微妙參數,非常有利于我們做時間的加減計算。
下面我們就用這個函數來實現下本期的功能。
3 源碼實現
3.1 參考代碼
本例給出一個參考代碼如下:
#include
#include
#include
#include
?
static int get_cur_time_ms(void)
{
struct timeval tv;
?
gettimeofday(&tv, NULL); //使用gettimeofday獲取當前系統時間
?
return (tv.tv_sec * 1000 + tv.tv_usec / 1000); //利用struct timeval結構體將時間轉換為ms
}
?
3.2 代碼簡介
代碼的功能邏輯,正如上面 的函數描述所說,正是利用gettimeofday返回的struct timeval結構內的成員變量,通過秒、毫秒、微妙的數量轉換,將當前時間轉換成毫秒,然后以函數返回值的形式輸出。
值得注意的是,雖然gettimeofday在結構體定義上 【號稱】有微妙級的精度,但是實際大部分的平臺是沒法達到這樣的精度的,所以我們取其中,轉換成毫秒級的精度,這個已經滿足我們絕大多數應用場景了。
3.3 代碼測試
針對上面的功能代碼,寫了一段小代碼來測試下。
#include
#include
#include
#include
?
static int get_cur_time_ms(void)
{
struct timeval tv;
?
gettimeofday(&tv, NULL); //使用gettimeofday獲取當前系統時間
?
return (tv.tv_sec * 1000 + tv.tv_usec / 1000); //利用struct timeval結構體將時間轉換為ms
}
?
static void get_rand_bytes(unsigned char *data, int len)
{
int a;
int i;
?
srand((unsigned)time(NULL)); //種下隨機種子
for (i = 0; i < len; i++) {
data[i] = rand() % 255; //取隨機數,并保證數在0-255之間
//printf("%02X ", data[i]);
}
}
?
int main(int argc, const char **argv)
{
int t1;
int t2;
unsigned char data[1024000];
?
t1 = get_cur_time_ms();
get_rand_bytes(data, sizeof(data));
t2 = get_cur_time_ms();
printf("random %d bytes, waste time: %dms
", sizeof(data), t2 - t1); //打印耗時
?
return 0;
}
?
以下測試代碼的邏輯還是很簡單的,主要就是測試獲取 1024000個隨機數的耗時情況。
由于我本次測試使用的PC主機,其性能還是不錯,所以測試出來的數據,還是耗時比較小的;如果這段代碼放在嵌入式平臺去運行的話,一個可能data數組的內存會爆,第二個耗時可能會大大增加。
感興趣的朋友可以拿去一試。
注,本次測試的PC機情況如下:
4 小小總結
- 面對需求說明,盡快找到核心的功能要點,找到算法邏輯是關鍵;
- 明白要做什么,再去選擇合適的函數來滿足功能邏輯,這是比較好的思路;
- 考慮到gettimeofday的實際精度問題,犧牲部分不起眼的精度,依然可以滿足大部分的需求。
5 更多分享
[架構師李肯]
架構師李肯 ( 全網同名 ),一個專注于嵌入式IoT領域的架構師。有著近10年的嵌入式一線開發經驗,深耕IoT領域多年,熟知IoT領域的業務發展,深度掌握IoT領域的相關技術棧,包括但不限于主流RTOS內核的實現及其移植、硬件驅動移植開發、網絡通訊協議開發、編譯構建原理及其實現、底層匯編及編譯原理、編譯優化及代碼重構、主流IoT云平臺的對接、嵌入式IoT系統的架構設計等等。擁有多項IoT領域的發明專利,熱衷于技術分享,有多年撰寫技術博客的經驗積累,連續多月獲得RT-Thread官方技術社區原創技術博文優秀獎,榮獲[CSDN博客專家]、[CSDN物聯網領域優質創作者]、[2021年度CSDN&RT-Thread技術社區之星]、[2022年RT-Thread全球技術大會講師]、[RT-Thread官方嵌入式開源社區認證專家]、[RT-Thread 2021年度論壇之星TOP4]、[華為云云享專家(嵌入式物聯網架構設計師)]等榮譽。堅信【知識改變命運,技術改變世界】!
審核編輯:湯梓紅
-
RT-Thread
+關注
關注
31文章
1300瀏覽量
40264
發布評論請先 登錄
相關推薦
評論