linux cpu 时间,【Linux】CPU时间与处理器耗时
文章結(jié)構(gòu):
CPU時間(CPU TIME)是指當應(yīng)用進程啟動后,占用CPU進行計算所進行的時間絕對值,或叫時間點。如果進程進入中斷、掛起、休眠等行為時,是不占用CPU的,所以CPU時間并不會跟著增加,且進程恢復(fù)運行后所獲得的CPU時間值與運行中斷之前的時間值是連續(xù)的,并不會因為運行的暫停而導(dǎo)致CPU時間的跳躍。這是和普通的日常時間值不一樣的點。另一個不同的點是CPU時間并不是以秒為單位的,而是處理器的時鐘周期為單位。
獲取CPU時間的函數(shù)#include
clock_t clock(void)
該函數(shù)返回CPU時間,CPU時間并不一定會從0開始,所以要計算進程的一段代碼所消耗的CPU時間記錄需要在代碼前后獲取各自的起始和終止CPU時間,兩者之差即為所消耗的CPU時間,即為處理器耗時(Processor Time)。要將clock_t轉(zhuǎn)換為秒數(shù),需要除以宏CLOCKS_PER_SEC生成的值,即為秒數(shù)。但要注意的是由于在不同的系統(tǒng)中clock_t或CLOCKS_PER_SEC可能為int也可能為浮點型數(shù)值,所以在計算時需要在計算過程中并其強制轉(zhuǎn)換為double以保證計算結(jié)果。另外需要注意的是clock()函數(shù)所返回的值在32位系統(tǒng)上每72分鐘就會恢復(fù)原始值一次。clock()如果執(zhí)行錯誤,則會返回-1。
獲取CPU時間與更詳細的進程時間還有另外一個函數(shù):#include
clock_t times(struct tms *buf);
struct tms {
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
};
函數(shù)times()會將進程的處理器時間分類。在參數(shù)tms中各字段含義為:tms_utime:用戶層處理器耗時。即執(zhí)行該進程的實現(xiàn)代碼所消耗的CPU時間和。tms_stime:系統(tǒng)層處理器耗時。即該進程實現(xiàn)的代碼調(diào)用了系統(tǒng)內(nèi)核代碼,由這部分內(nèi)核代碼執(zhí)行所消耗的CPU時間和。tms_cutime:子進程用戶層處理器耗時。即如果當前進程通過調(diào)用system()或fork()函數(shù)導(dǎo)致產(chǎn)生新的子進程(數(shù)量前后可能為多個),則記錄所有子進程的實現(xiàn)代碼所消耗的CPU時間和。tms_cstime:子進程用戶層處理器耗時。即如果當前進程通過調(diào)用system()或fork()函數(shù)導(dǎo)致產(chǎn)生新的子進程(數(shù)量前后可能為多個),則記錄所有子進程實現(xiàn)的代碼調(diào)用了系統(tǒng)內(nèi)核代碼,由這部分內(nèi)核代碼執(zhí)行所消耗的CPU時間和。
函數(shù)times()所返回的值單位都是時鐘滴噠(clock tick)數(shù)。要獲取每秒鐘的時鐘滴噠可以調(diào)用函數(shù)sysconf(_SC_CLK_TCK);來獲取。為了保證精度,在計算耗時時,也要在計算過程中將參與的計算值轉(zhuǎn)換為double以保證計算結(jié)果。函數(shù)times()所返回的值表示過去某個時間點到函數(shù)調(diào)用此刻的時間消耗長度。所以進程的中斷、掛起、休眠等行為仍會導(dǎo)致返回值的持續(xù)增加。這一點是與clock()的不同所在。通常也利用這個特點來計算進程的前后自然時間耗時時長。在計算時長方面,times()通過精確到秒以下(可能是毫秒,因為是double類型的計算),但缺點是參數(shù)buf必須不為空;difftime()由于其參數(shù)設(shè)定的原因只能精確到秒,能力是最弱的;gettimeofday()所獲取的timeval則可精確到微秒,只是計算時間差值時麻煩一點。
除了在代碼中調(diào)用函數(shù)來計算各種耗時以外,還可能通過命令time來顯示耗時統(tǒng)計。Time命令原型如下:
time [options] command [arguments...]
options:time命令的可選參數(shù),只接受-p,表示為按標準格式輸出。如下:
real: 命令`date`的全部運行時間時長。
user: 命令`date`(包括其子進程,如果有的話)的用戶層處理器耗時。
sys : 命令`date`(包括其子進程,如果有的話)的系統(tǒng)層處理器耗時。
command:time要統(tǒng)計的命令。[arguments]:command命令所接受的參數(shù)。
命令Time的輸出是可以自定義的,通過設(shè)置環(huán)境變量TIMEFORMAT指定輸出所要的格式化結(jié)果。另從man手冊中查看Time還具有查看CPU占用率、I/O數(shù)據(jù)量等功能(可是按文檔在Mac上來操作沒有成功呀…)
接下來的代碼將演示:
#include #include #include
pid_t getpid(void); // 獲取進程id
pid_t getppid(void); // 獲取父進程id
pid_t gettid(void){ // 獲取線程id
return syscall(SYS_gettid);
}
這里值得提一下的是getttid()是系統(tǒng)內(nèi)核非對外公開的函數(shù)。所以這里根據(jù)其源碼實現(xiàn)利用syscall()方法來獲取線程id。
#include
unsigned int sleep(unsigned int seconds);
參數(shù)seconds表示線程的休眠時間,單位為秒。在指定的休眠時間內(nèi),線程會暫停工作直至時間到期或被中斷。
為了測試times()中的tms_cutime和tms_cstime,需要創(chuàng)建一個子進程,這里用到system()函數(shù)。#include
int system(const char *command);
參數(shù)command為命令,可以是可執(zhí)行程序路徑也可以是系統(tǒng)支持的命令。system()函數(shù)會調(diào)用fork()去創(chuàng)建一個子進程并執(zhí)行參數(shù)command。在子進程執(zhí)行期間,父進程所調(diào)用的線程是被中斷的,不會再進行任何操作直至等到子進程全部執(zhí)行完畢。子進程所產(chǎn)生的日志輸出也將在結(jié)束之后才會被打印出來。
示例代碼中,通過在程序的開頭、進行中、結(jié)束各個階段執(zhí)行clock()來獲取進程當前的CPU時間點,通過減法操作最終得到每個階段的處理器耗時。
執(zhí)行完sleep()的前后CPU時間對比可以驗證CPU時間是進程所消耗處理器而產(chǎn)生的連續(xù)的時間集合。CPU用了多少就是多少,而與正常的時間流逝無關(guān)。執(zhí)行完system()的前后CPU時間對比可以驗證子進程的CPU時間并不會被計算在父進程中,可以通過times()區(qū)分。
clock_t c_start = clock();
sleep(2); // 進程進入休眠
clock_t c_mid01 = clock();
doCopyFile(); // 進程進入繁忙的工作狀態(tài)
clock_t c_mid02 = clock();
system(“”); // 生成子進程
clock_t c_end = clock();
doCopyFile()函數(shù)是復(fù)制文件的代碼實現(xiàn),本示例中所復(fù)制的文件大小為35M,耗時大概3.5s左右。具體復(fù)制代碼實現(xiàn)可以查看之前的文章:【C/C++】文件創(chuàng)建、打開、讀、寫、復(fù)制、關(guān)閉、刪除等操作匯總
獲取耗時詳情的前提是要獲取每秒時鐘滴噠數(shù);而詳情則是通過struct tms的前后對比得出的時間差:
// process_start與后面的process_end用于計算整個進程的耗時
clock_t process_start = times(&sys_t_start);
// 獲取每秒的時鐘滴噠數(shù)
long tck = sysconf(_SC_CLK_TCK);
... ... ...
struct tms sys_t_end;
clock_t process_end = times(&sys_t_end);
printf("4. sys time: user time=%f, stime=%f, cutime=%f, cstime=%f \n",
(sys_t_end.tms_utime - sys_t_start.tms_utime)/(double)tck,
(sys_t_end.tms_stime - sys_t_start.tms_stime)/(double)tck,
(sys_t_end.tms_cutime - sys_t_start.tms_cutime)/(double)tck,
(sys_t_end.tms_cstime - sys_t_start.tms_cstime)/(double)tck);
printf("5. real elapsed time=%f \n", ((process_end - process_start)/(double)tck));
最后看代碼的運行結(jié)果吧,如下圖:
圖中,real elapsed time=9.250000與time命令所打印出來的real 0m9.249s相符;user time=3.360000 , cutime=3.380000兩者之和與user 0m6.757s相符;stime=0.120000 cstime=0.120000兩者之和與sys 0m255s相符。數(shù)值上不是絕對相等,代碼內(nèi)的自我計算總是會少于time的值,因為代碼內(nèi)是計算完了之后要打印的,這部分打印及退出的時間是代碼的盲區(qū),而time命令能統(tǒng)計到。
以下為實現(xiàn)代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include
#include
#include
#include
#include
#include
#include
#include
#include
pid_t gettid(
void){
return syscall(SYS_gettid);
}
int main(
int argc,
char **argv) {
// author : sodino@qq.com
struct tms sys_t_start;
clock_t process_start = times(&sys_t_start);
clock_t c_start = clock();
times(&sys_t_start);
printf(
" pid=%d ppid=%d tid=%d \n", getpid(), getppid(), gettid());
long tck = sysconf(_SC_CLK_TCK);
sleep(
2);
clock_t c_mid01 = clock();
double diff = (c_mid01 - c_start)/(
double)CLOCKS_PER_SEC;
printf(
"1. after sleep(2) consume clock time=%f \n", diff);
doCopyFile();
clock_t c_mid02 = clock();
diff = (
double)(c_mid02 - c_start)/CLOCKS_PER_SEC;
printf(
"2. after doCopyFile() consume clock time=%f \n", diff);
// 這里會產(chǎn)生新的進程
system(
"/Users/sodino/workspace/xcode/Define/Define/t_copy.out");
clock_t c_end = clock();
diff = (
double)(c_end - c_start)/CLOCKS_PER_SEC;
printf(
"3. after system() consume clock time=%f \n", diff);
struct tms sys_t_end;
clock_t process_end = times(&sys_t_end);
printf(
"4. sys time: user time=%f, stime=%f, cutime=%f, cstime=%f \n",
(sys_t_end.tms_utime - sys_t_start.tms_utime)/(
double)tck,
(sys_t_end.tms_stime - sys_t_start.tms_stime)/(
double)tck,
(sys_t_end.tms_cutime - sys_t_start.tms_cutime)/(
double)tck,
(sys_t_end.tms_cstime - sys_t_start.tms_cstime)/(
double)tck);
printf(
"5. real elapsed time=%f \n", ((process_end - process_start)/(
double)tck));
return EXIT_SUCCESS;
}
總結(jié)
以上是生活随笔為你收集整理的linux cpu 时间,【Linux】CPU时间与处理器耗时的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聚类分析案例
- 下一篇: linux运维基础[系统磁盘管理]———