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
[
注: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秒?