1. 程式人生 > >Linux系統使用time計算命令執行的時間

Linux系統使用time計算命令執行的時間

 轉自:https://www.cnblogs.com/liuzhipenglove/p/7058726.html

參考:

https://www.cnblogs.com/bittorrent/p/3761247.html

https://blog.csdn.net/wangjianno2/article/details/50452919

 

注意: 命令後面一定要有分號;

http://codingstandards.iteye.com/blog/798788   

用途說明

time命令常用於測量一個命令的執行時間,注意不是用來顯示和修改系統時間的(這是date命令乾的事情)。但是今天我通過檢視time命令的手冊頁,發現它能做的不僅僅是測量執行時間,還可以測量記憶體、I/O等的使用情況,手冊頁上的說法是time a simple command or give resource usage,其中time一詞我認為它應該是測量或測定的意思,並不單指時間。一個程式在執行時使用的系統資源通常包括CPU、Memory和I/O等,其中CPU資源的統計包括實際使用時間(real time)、使用者態使用時間(the process spent in user mode)、核心態使用時間(the process spent in kernel mode)。但是簡單的使用time命令並不能得到記憶體和I/O的統計資料,請看後文慢慢道來。

常用引數

time命令最常用的使用方式就是在其後面直接跟上命令和引數:

time <command> [<arguments...>]

在命令執行完成之後就會打印出CPU的使用情況:

real    0m5.064s      <== 實際使用時間(real time) 
user    0m0.020s     <== 使用者態使用時間(the process spent in user mode) 
sys     0m0.040s      <== 核心態使用時間(the process spent in kernel mode)

time命令跟上-p引數可以只打印時間數值(秒數),不列印單位。

使用示例

示例一 統計執行時間

[[email protected] root]# time find . -name "mysql.sh" 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh

real    0m14.837s
user    0m0.030s
sys     0m0.120s
[

[email protected] root]#

注:real遠大於user加上sys,因為find需要遍歷各個目錄,需要大量的I/O操作,而磁碟I/O通常是最慢的環節,因此大部分時間find程序都在等待磁碟I/O完成。

[[email protected] root]# time find . -name "mysql.sh" 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh

real    0m0.230s
user    0m0.040s
sys     0m0.030s

注:再次執行的時候,發現real time變得很小了,應該是作業系統將剛才操作過的一些檔案快取了的緣故,因而大大減少了磁碟I/O。 
[[email protected] root]# time -p find . -name "mysql.sh" 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh
real 0.15
user 0.04
sys 0.03

注:使用-p引數時,直接列印所需時間的數值,單位為秒,而不是更友好的格式,包括分鐘、秒鐘的顯示方式。 
[[email protected] root]#

示例二 Linux系統中time命令其實不止一個

看過手冊頁的朋友,會發現有個-f引數可以來指定統計資訊的輸出格式,我們也來試一下。

[[email protected] root]# time -f "real %f\nuser %f\nsys %f\n" find . -name "mysql.sh"  
-bash: -f: command not found

real    0m0.024s
user    0m0.000s
sys     0m0.000s

怪哉,不靈啊。使用type -a來看一下。使用這個shell內建命令經常會有意想不到的發現。

[[email protected] root]# type -a time 
time is a shell keyword
time is /usr/bin/time

注:通過這條命令我們可以發現我們常用的time其實是一個Shell關鍵字,還有一個外部命令/usr/bin/time,它有何不同呢? 
[[email protected] root]# /usr/bin/time 
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--help] command [arg...]

注:外部命令/usr/bin/time功能更強大,下面來嘗試一下。

[[email protected] root]# /usr/bin/time find . -name "mysql.sh" 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh
0.03user 0.04system 0:00.12elapsed 55%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (154major+63minor)pagefaults 0swaps

注:注意後面兩行,列印了很多資訊,但看不太清楚。它有一個引數-v,可以列印得更清楚些。 
[[email protected] root]# /usr/bin/time -v find . -name "mysql.sh" 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh
        Command being timed: "find . -name mysql.sh"
        User time (seconds): 0.03
        System time (seconds): 0.05
        Percent of CPU this job got: 47%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.17
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 0
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 153
        Minor (reclaiming a frame) page faults: 64
        Voluntary context switches: 0
        Involuntary context switches: 0
        Swaps: 0
        File system inputs: 0
        File system outputs: 0
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0
[[email protected] root]#

嘗試完這個之後,我看了一下Google搜尋的結果,發現有位大蝦早已發現了這個祕密,見相關資料【1】。

示例三 解決time命令輸出資訊的重定向問題

time命令的輸出資訊是列印在標準錯誤輸出上的, 我們通過一個簡單的嘗試來驗證一下。

[[email protected] root]# time find . -name "mysql.sh" >1.txt 

real    0m0.081s
user    0m0.060s
sys     0m0.020s
[[email protected] root]# time find . -name "mysql.sh" 2>2.txt 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh

real    0m0.068s
user    0m0.040s
sys     0m0.030s

通過上面的嘗試,發現無法將time的輸出資訊重定向到檔案裡面,為什麼?因為time是shell的關鍵字,shell做了特殊處理,它會把time命令後面的命令列作為一個整體來進行處理,在重定向時,實際上是針對後面的命令來的,time命令本身的輸出並不會被重定向的。那現在怎麼辦呢?網上提供了兩種解決方法【2,3】,我們一一嘗試一下。

第一種解決方法,就是將time命令和將要執行的命令列放到一個shell程式碼塊中,也就是一對大括號中,要注意空格和分號的使用。 
[[email protected] root]# {time find . -name "mysql.sh"} 2>2.txt

好像成功了。慢,看一下對不對。 
[[email protected] root]# cat 2.txt 
-bash: {time: command not found

原來bash把 {time 作為一個整體來處理了,前後都加上空格試試。 
[[email protected] root]# { time find . -name "mysql.sh" } 2>2.txt 
> Ctrl+C

這次Bash認為命令都沒有輸入完成,少了分號。因為Bash認為後面的 } 是find命令的引數。 
[[email protected] root]# { time find . -name "mysql.sh"; } 2>2.txt 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh
[[email protected] root]# cat 2.txt 

real    0m0.068s
user    0m0.030s
sys     0m0.040s

第一種方式的嘗試成功了,總結起來就是 { time command-line; } 2>file  注意分隔符的使用。

另外一種方式就是使用子Shell的方式,如下所示:

[[email protected] root]# (time find . -name "mysql.sh") 2>2.txt 
./work186/sms/bin/mysql.sh
./work186/sms/src/scripts/mysql.sh
./work186/sms/src/scripts1/mysql.sh
./work186/sms1/bin/mysql.sh
./work186/sms1/src/scripts/mysql.sh
./temp/sms/bin/mysql.sh
./temp/sms/src/scripts/mysql.sh
[[email protected] root]# cat 2.txt 

real    0m0.083s
user    0m0.040s
sys     0m0.020s
[[email protected] root]#

第二種方式的嘗試也成功了,總結起來就是 (time command-line) 2>file 這裡time緊貼著小括號(也可以的,命令列結束也不必帶分號。當然最好還是用第一種方式,畢竟啟動一個子shell是要多佔些資源的。

問題思考

1. 為什麼執行find命令的多次時間統計差別很大,一次實際時間需要12秒,另外幾次卻不足1秒?