日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

计算程序运行时间(time_t, clock_t)

發布時間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 计算程序运行时间(time_t, clock_t) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自:http://blog.chinaunix.net/uid-23208702-id-75182.html
計算程序運行時間(time_t, clock_t)-whyliyi-ChinaUnix博客
我們有時需要得到程序的運行時間,但我們也要知道,根本不可能精確測量某一個程序運行的確切時間 -[3] ,文獻 [4] 中說的很明白,現摘錄如 下。

   我們平時常用的測量運行時間的方法并不是那么精確的,換句話說,想精確獲取程序運行時間并不是那么 容易的。也許你會想,程序不就是一條條指令么,每一條指令序列都有固定執行時間,為什么不好算?真實情況下,我們的計算機并不是只運行一個程序的,進程的 切換,各種中斷,共享的多用戶,網絡流量,高速緩存的訪問,轉移預測等,都會對計時產生影響。文獻 [4] 中還提到:對于進程調度來 講,花費的時間分為兩部分,第一是計時器中斷處理的時間,也就是當且僅當這個時間間隔的時候,操作系統會選擇,是繼續當前進程的執行還是切換到另外一個進 程中去。第二是進程切換時間,當系統要從進程 A 切換到進程 B 時,它必須先進入內核模式將進程 A 的狀態 保存,然后恢復進程 B 的狀態。因此,這個切換過程是有內核活動來消耗時間的。具體到進程的執行時間,這個時間也包括內核 模式和用戶模式兩部分,模式之間的切換也是需要消耗時間,不過都算在進程執行時間中了。那么有哪些方法能統計程序的運行時間呢?通過查找一些資料并結合自己的實踐體會,摘錄和總結了下面 幾種方法。

一、 Linux 的 time 命令

   Linux 系統下統計程序運行實踐最簡單直接的方法就是使用 time 命令,文獻 [1, 2] 中詳細介紹了 time 命令的用法。此命令的用途在于測量特定指令執行時所需消耗的時間及系統資源等資訊,在統計的時間結 果中包含以下數據:***(1) 實際時間( real time ):從命令行執行到運行終止的消逝時間;(2) 用戶 CPU 時間( user CPU time ):命 令執行完成花費的系統 CPU 時間,即命令在用戶態中執行時間的總和;(3) 系統 CPU 時間( system CPU time ): 命令執行完成花費的系統 CPU 時間,即命令在核心態中執行時間的總和。其中,用戶 CPU 時 間和系統 CPU 時間之和為 CPU 時 間,即命令占用 CPU 執行的時間總和。實際時間要大于 CPU 時 間,因為 Linux 是多任務操作系統,往往在執行一條命令時,系統還要處理其他任務。另一個需要注意的問題是即使每次 執行相同的命令,所花費的時間也不一定相同,因為其花費的時間與系統運行相關。***

二、間隔計數 [4]

   上面介紹的 time 命 令能測量特定進程執行時所消耗的時間,它是怎么做到的呢?操作系統用計時器來記錄每個進程使用的累計時間,原理很簡單,計時器中斷發生時,操作系統會在當前 進程列表中尋找哪個進程是活動的,一旦發現進程 A 正在運行立馬就給進程 A 的計數值增加計時器的時間間隔(這也是引起較大誤差的原因)。當然不是統一增加的,還要確定這個進程 是在用戶空間活動還是在內核空間活動,如果是用戶模式,就增加用戶時間,如果是內核模式,就增加系統時間。這種方法的原理雖然簡單但不精確。如果一個進程 的運行時間很短,短到和系統的計時器間隔一個數量級,用這種方法測出來的結果必然是不夠精確的,頭尾都有誤差。不過,如果程序的時間足夠長,這種誤差有時 能夠相互彌補,一些被高估一些被低估,平均下來剛好。從理論上很難分析這個誤差的值,所以一般只有程序達到秒的數量級時用這種方法測試程序時間才有意義。這種方法最大的優點是它的準確性不是非常依賴于系統負載。實現方法之一就是上面介紹的 time 命 令,之二是使用 tms 結構體和 times 函 數。在 Linux 中,提供了一個 times 函數,原型是clock_t times( struct tms * buf );

這個 tms 的結構體為

struct tms

{

   clock_t tms_utime;             //user timeclock_t tms_stime;             //system timeclock_t tms_cutime;    //user time of reaped childrenclock_t tms_cstime;     //system time of reaped children

}

這里的 cutime 和 cstime ,都是對已經終止并回收的時間的累計,也就是說, times 不能監視任何正在進行中的子進程所使用的時間。使用 times 函數需要包含頭文件 sys/times.h 。

三、周期計數 [4]

   為了給計時測量提供更高的準確度,很多處理器還包含一個運行在始終周期級別的計時器,它是一個特殊 的寄存器,每個時鐘周期它都會自動加 1 。這個周期計數器呢,是一個 64 位無 符號數,直觀理解,就是如果你的處理器是 1GHz 的,那么需要 570 年,它才會從 2 的 64 次方繞回到 0 ,所以 你大可不必考慮溢出的問題。但是這種方法是依賴于硬件的。首先,并不是每種處理器都有這樣的寄存器的;其次,即使大多數都有,實現機制也不一樣,因此,我 們無法用統一的,與平臺無關的接口來使用它們。這下,就要使用匯編了。當然,在這里實際用的是 C 語言 的嵌入匯編:
void counter( unsigned *hi, unsigned *lo ){asm(”rdtsc; movl %%edx,%0; movl %%eax, %1″
“=r” (*hi), “=r” (*lo)
:
“%edx”, “%eax”);
}

第一行的指令負責讀取周期計數器,后面的指令表示將其轉移到指定地點或寄存器。這樣,我們將這段代碼封裝到函數中,就可以在需要測量 的代碼前后均加上這個函數即可。最后得到的 hi 和 lo 值都是兩個,除了相減得到間隔值外,還要進行一些處理,在此 不表。

   不得不提出的是,周期計數方式還有一個問題,就是我們得到了 兩次調用 counter 之間總的周期數,但我們不知道是哪個進程使用了這些周期,或者說處理器是在內核還是在用戶模式 中。間隔計數的好處就是它是操作系統控制給進程計時的,我們可以知道具體哪個進程呢個模式;但是周期計數只測量經過的時間,他不管是哪個進程使用的。所 以,用周期計數的話必須很小心。舉個例子:double time(){start_counter();p();get_counter();

}

這樣一段程序,如果機器的負載很重,會導致 p 運行 時間很長,而其實 p 函數本身是不需要運行這么長時間的,而是上下文切換等過程將它的時間拖長了。

   而且,轉移預測和高速緩存的命中率,對這個計數值也會有影響。通常情況下,為了減少高速緩存不命中 給我們程序執行時間帶來的影響,可以執行這樣的代碼:double time_warm(void){p();start_counter();p();get_counter();

}

它讓指令高速緩存和數據高速緩存都得到了 warm-up 。

   接下來又有問題。如果我們的應用是屬于那種每次執行都希望訪問新的數據的那種呢?在這種情況下,我 們希望讓指令高速緩存 warm-up ,而數據高速緩存不能 warm-up ,很明顯, time-warm 函數低估我們的運行時間了。進一步修改:double time_cold( void ){p();clear_cache();start_counter();p();get_counter();

}

注意,程序中加入了一個清除數據緩存的函數,這個函數的具體實現很簡 單,依情況而定,比如舉個例子:

   volatile int tmp;static int dummy[N];     //N 是需要清理緩存的字節數void clear_cache( void ){int i, sum = 0;for( i=1; idummy[i] = 2;for( i=1; isum += dummy[i];tmp = sum;

}

具體原理很簡單,定義一個數組并在其上執行一個計算,計算過程中的數據會覆蓋高速數據緩存中原有的數 據。每一次的 store 和 load 都會讓高速數據緩存 cache 這個數組,而定義為 volatile 的 tmp 則保證這段代碼不會被優化。

   這樣做,是不是就萬無一失了呢?不是的,因為大多數處理器, L2 高速緩存是不分指令和數據的,這樣 clear_cache 會讓所有 p 的指令也被清除,只不過: L1 緩存中的指令還會保留而已。其實上面提到的諸多原因,都是我們不能控制的,我們無法控制讓高速緩存去加載什么,不去加載什么, 加載時去掉什么。保留什么。而且,這些誤差通常都是會過高估計真實的運行時間。那么具體使用時,有沒有什么辦法來改善這種情況呢?有,就是 The K-Best Measurement Scheme 。這其實很麻煩,所以在具體實踐中都不用它。

四、 gettimeofday 函數計時 [4]

   gettimeofday 是一個庫函數,包含在 time.h 中。它的功能是查詢系統時鐘,以確定當前的日期和時間。相對于間隔計數的小適用范圍和周期計數的麻煩性, gettimeofday 是一個可移植性更好相對較準確的方法。它的原型如下:struct timeval{long tv_sec;  // 秒 域long tv_usec;       // 微妙域

}

int gettimeofday( struct timeval *tv, NULL);

   這個機制呢,具體的實現方式在不同系統上是不一樣的,而且具體的精確程度是和系統相關的:比如在 Linux 下,是用周期計數來實現這個函數的,所以和周期計數的精確度差不多,但是在 Windows NT 下,是使用間隔計數實現的,精確度就很低了。具體使用,就是在要計算運行時間的程序段之前和之后分別加上 gettimeofday( &tvstart, NULL) 、 gettimeofday( &tvend, NULL) ,然后計算:

(tvend.tv_sec-tvstart.tv_sec)+(tvend.tv_usec-tvstart.tv_usec)/1000000

就得到了以秒為單位的計時時間。

五、 clock 函數

   clock 也是一個庫函數,仍然包含在 time.h 中,函數原型是:clock_t clock( void );

功能:返回自程序開始運行的處理器時間,如果無可用信息,返回 -1 。轉換返回值若以秒計需除以 CLOCKS_PER_SECOND 。(注:如果編譯器是 POSIX 兼 容的, CLOCKS_PER_SECOND 定義為 1000000 。) [5]

   使用 clock 函數也比較簡單:在要計 時程序段前后分別調用 clock 函數,用后一次的返回值減去前一次的返回值就得到運行的處理器時間,然后再轉換為秒。舉例如下:clock_t starttime, endtime;double totaltime;starttime = clock();…endtime = clock();totaltime = (double)( (endtime - starttime)/(double)CLOCKS_PER_SEC );

六、 time 函數

   在 time.h 中還包含另一個時間函 數: time 。文獻 [6] 對其進行了詳細的介紹。通 過 time() 函數來獲得日歷時間( Calendar Time ),其原型為: time_t time( time_t * timer ) 。通過 difftime 函數可以計算前后 兩次的時間差: double difftime( time_t time1, time_t time0 ) 。用 time_t 表示的時間(日歷時 間)是從一個時間點(例如: 1970 年 1 月 1 日 0 時 0 分 0 秒)到此時的秒數,則此函數的前后兩次時間差也是以秒為單位。比如:time_t startT, endT;double totalT;startT = time( NULL );…endT = time( NULL );totalT = difftime( startT, endT);關于此函數的其他應用請參見文獻 [6] 。

總結:

   使用相應的方法,調用相應的函數,還需要關注它們可以表示的范圍和精度,這樣才能“挑肥揀瘦”。先 來看看時間函數中經常用到的兩個數據類型的定義:// clock_t 的定義

#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif

// time_t 的定義

#ifndef _TIME_T_DEFINED
typedef long time_t;

#define _TIME_T_DEFINED

#endif

   long 型數據的取值范圍是 -2147483648 ~ +2147483647 。所以, gettimeofday 函數取得的時間最大值為 2147483647 + 2147483647 / 1000000 = 2147485794.483647 s ,大約為 68.096 年; clock 函 數取得的時間最大值為 2147483647 / 1000000 = 2147.483647 s ,大約為 35.79 分 鐘;

time 函數取得的時間最大值為 2147483647 s ,大約為 68 年。

   這里只是介紹 Linux 平臺下 c 語言中計算程序運行時間的方法, 它們各有利弊,依據自己的需要可以使用對應的方法。在 Windows 平臺下還有其他計算程序運 行時間的方法,在此不敘。

參考文獻

[1] “ linux time 命令詳解”, http://www.admin99.net/read.php/185.htm ;

[2] “ Linux 命令詳解—— time ”,

http://blog.csdn.net/thinkerABC/archive/2006/04/01/647272.aspx ;

[3] “測量程序運行時間的幾種方法”, http://oss.lzu.edu.cn/blog/article.php?tid_905.html ;

[4] “如何精確測量程序運行時間”, http://www.forwind.cn/2008/05/10/measure-time-preciely/ ;

[5] “ clock ”, http://blog.csdn.net/xxyakoo/archive/2008/12/17/3539590.aspx ;

[6] “ c 語言對時間的處理函數和計時的實 現”,

http://blog.csdn.net/adm_qxx/archive/2007/05/02/1594788.aspx 。

總結

以上是生活随笔為你收集整理的计算程序运行时间(time_t, clock_t)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲精品乱码久久久久久9色 | 人妻少妇被猛烈进入中文字幕 | 中文文字幕文字幕高清 | 伊人久久九 | 1级片在线观看 | 国产精品国产三级国产播12软件 | 东北熟女一区二区三区 | 日韩区在线观看 | 极品少妇xxxx精品少妇 | 日韩一二三区视频 | 国产视频一 | 青青色在线视频 | 成人免费短视频 | 在线成人av网站 | 女性生殖扒开酷刑vk | 一级生活毛片 | 国产性生活一级片 | 国产色啪 | 中国色视频 | 99免费| 美女一区二区视频 | 国产综合激情 | 99精品欧美一区二区三区综合在线 | 天天色综 | 国产综合视频 | 波多野一区二区 | 国产私拍视频 | 91福利视频网站 | 欧美女优在线观看 | 午夜小视频在线播放 | 日日躁夜夜躁狠狠久久av | www.777奇米影视 | 成人午夜视频一区二区播放 | wwwav在线播放| 久综合网 | 国产网站大全 | 成人28深夜影院 | 手机av电影在线 | 四虎福利 | 国产午夜福利视频在线观看 | 国产精品视频在线观看 | 亚洲国产欧美在线 | 夜夜操夜夜骑 | www.com捏胸挤出奶 | www网站在线免费观看 | 插插操操 | 精产国品一二三产品蜜桃 | 色偷偷人人澡人人爽人人模 | 国产无遮挡a片又黄又爽 | 黑巨茎大战欧美白妞 | 亚洲久久一区 | 久久人人爽 | 波多野结衣伦理 | 国产区欧美区日韩区 | 免费一区视频 | 成人午夜一区二区 | 清纯唯美亚洲 | 婷婷婷色| 新97超碰 | 中文字幕+乱码+中文乱 | 青青草婷婷 | 国产精品视频一区二区三区在3 | 在线播放视频高清在线观看 | 91资源在线观看 | 在线观看中文字幕2021 | 亚洲区成人 | 女人毛片视频 | www国产在线| 91av在线视频观看 | 中国在线观看视频高清免费 | 亚洲国产黄色片 | 免费毛片小视频 | 亚洲日本中文字幕在线 | 久久久久久九九九 | 欧洲美女与动交zozzo | 手机av免费看 | 99精品福利视频 | 国产精品久久午夜夜伦鲁鲁 | 在线观看黄色免费视频 | 成人毛片av| 亚洲一二三区视频 | 日本一区二区三区久久久久 | 粉嫩久久99精品久久久久久夜 | 国产九九在线 | 久久国产黄色片 | 亚洲第十页 | 欧美日韩视频无码一区二区三 | 免费观看在线观看 | 影音先锋久久久久av综合网成人 | 午夜一区在线 | 99热首页| 台湾少妇xxxx做受 | 91精品视频一区二区三区 | 亚洲色图日韩 | 日日夜夜婷婷 | 真实的国产乱xxxx在线91 | 亚洲人在线视频 | 亚洲av无码乱码在线观看富二代 | 亚洲 小说区 图片区 |