time命令_Linux time命令:測量命令的執行時間或者系統資源的使用情況

2020-07-16 10:04:30
這裡我們要學習的 time 命令是用來測量 Linux 程式執行時間的命令,而不是用來顯示系統時間的命令。不是吧,這也太分裂了吧,那顯示系統時間的命令是什麼呢?是 date,馬上百度一下,你就清楚了。

Linux 手冊中是這樣介紹 time 命令的:“time a simple command or give resource usage”,即測量命令的執行時間,或者給出系統資源的使用情況。

time 的簡單用法

如果你想檢視一條命令(比如 ls)到底執行了多長時間,我們可以這樣做:
[[email protected] ~]$ time ls
program  public_html  repo  rocscm
 
real    0m0.002s
user    0m0.002s
sys 0m0.000s

看到沒有,執行時間一下子就統計出來了。但輸出內容中有三個統計時間,real、user 和 sys,它們都代表什麼含義呢?哪個才是 ls 命令的執行時間呢?下面我們就一起來看看這三個統計時間。

(1) real:從進程 ls 開始執行到完成所耗費的 CPU 總時間。該時間包括 ls 進程執行時實際使用的 CPU 時間,ls 進程耗費在阻塞上的時間(如等待完成 I/O 操作)和其他進程所耗費的時間(Linux 是多進程系統,ls 在執行過程中,可能會有別的進程搶占 CPU)。

(2) user:進程 ls 執行使用者態程式碼所耗費的 CPU 時間。該時間僅指 ls 進程執行時實際使用的 CPU 時間,而不包括其他進程所使用的時間和本進程阻塞的時間。

(3) sys:進程 ls 在核心態執行所耗費的 CPU 時間,即執行核心系統呼叫所耗費的 CPU 時間。

現在,我們應該對這三個時間非常清楚了吧。ls 命令的真正執行時間是多少?答案就是 user+sys 的時間,但一般情況下,real=user+sys,因而我們就使用 real 的時間作為 ls 的執行時間了(注意,這裡會有幾個坑,我們將在後面進行介紹)。

好了,time 的最基本用法介紹完畢,就這麼簡單。

消失的時間

上面說 real 時間中會有幾個坑,下面我們就來詳細地看一看。

情景一:
[[email protected] ~]$ time sudo find / -name php.ini
 
real    0m0.193s
user    0m0.076s
sys 0m0.115s

咦,是我數學不好,還是命令執行出錯了呢?為什麼 0.193s(real)>0.076s(user)+0.115s(sys),而不是相等呢?哈哈,同學,你挺細心的嘛。這既不是你的數學不好,也不是命令執行出錯,而是我們對命令執行時間的理解有幾個誤區。

誤區一:real_time=user_time+sys_time

如果你認為上面的等式一定成立的話,那麼請你再理解一下前面關於 real、user 和 sys 的介紹。在前面的表述中,real time 是包含了其他進程的執行時間和進程阻塞時間的,而 usr time+sys time 顯然是不包括其他進程的執行時間和進程阻塞時間的。因此,real_time>user_time+sys_time 是非常有可能的。

誤區二:real_time>user_time+sys_time

根據上面的分析,這個關係式應該是成立的吧?嘿嘿,不一定喲。一般來說,在單核 CPU 系統中,這個關係式是成立的,但如果我們的系統是多核 CPU 的話,而有些程式是能夠同時利用到多核 CPU 的計算能力的,在這種情況下這個關係式就不成立了。

程式利用多核 CPU 的計算能力,可以並行地處理多項事務。就像一件工作,原來是一個 CPU 核去做,現在是兩個 CPU 核並行做,那麼完成同樣工作所花費的總時間是 user_time+sys_time,而兩個人並行做卻能夠在更短的時間內完成,耗時為 real_time。因此,這種情況下,便出現了 real_time<user_time+sys_time 的情況。

誤區三:real_time<user_time+sys_time

多核情況下,real_time<user_time+sys_time 是成立的,那單核呢?顯然是 real_time>user_time+sys_time。

上面的三個誤區有點繞,但結論很重要,就是 real_time 和 user_time+sys_time 的大小關係不是恆久不變的,你需要了解你的 Linux 伺服器,是單核,還是多核,這樣才能正確地確定它們的關係。

情景二:
[[email protected] ~]$ time sudo find / -name mysql.sh
/etc/profile.d/mysql.sh
 
real    0m6.776s
user    0m1.101s
sys 0m1.363s
我們執行 find/-name mysql.sh 搜尋檔案的命令,顯示的命令耗時是 6.776 秒。

如果我們再執行一次完全相同的命令:
[[email protected] ~]$ time sudo find / -name mysql.sh
/etc/profile.d/mysql.sh
 
real    0m3.059s
user    0m1.189s
sys 0m1.435s

咦,怎麼 real 的時間縮減到了 3.059 秒了,生生少了 3 秒多鐘,這又是怎麼回事呢?為什麼同樣的命令在第二次執行時快這麼多呢?

這個現象跟 Linux 作業系統的執行原理有關,find 命令在第一次執行後,系統會對一些檔案做快取,在第二次執行時,就正好使用到了這些快取中的資料,因此執行速度就變快了很多。

看過這個範例後,如果仍有同學不問青紅皂白地抱怨 time 命令的計時誤差大,那可真是冤枉 time 啦。

time 的 man 手冊中說,它不僅可以測量執行時間,還可以測量記憶體、I/O 等的使用情況,但為什麼上面範例中的 time 命令的結果中卻沒有顯示出這些資訊呢?難道是 man 手冊出現了錯誤?

NO,NO,NO(重要的事情要說三遍),其實上面使用的 time 真的是“巧婦難為無米之炊”,我們之前所用的 time 命令是 Bash 的內建命令,功能比較弱;而更強大的 time 命令隱藏在 /usr/bin/ 目錄下,這個命令才是世外高人。

如果我們在 /user/bin/ 中並沒有找到傳說中那個強大的 time 命令,那麼應該是沒有安裝 time 這個工具,安裝方法也很簡單:
[[email protected] ~]# yum install time

安裝完成後,我們就一起來見識 time 命令的廬山真面目吧!我們特意在 time 命令前加了一個斜線(),就是為了呼叫那個強大的 time 命令,而非 Bash 內建的 time 命令。
[[email protected] ~]# time ls
bin dev   lib     media  proc  seLinux   tmp
boot    etc   lib64   mnt   root  srv  usr
cgroup  home  lost+found  opt    sbin  sys  var
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 956maxresident)k
0inputs+0outputs (0major+289minor)pagefaults 0swaps

請注意輸出內容中的最後兩行,列印了很多指標資料,但似乎有點晦澀難懂。這時我們可以使用一個 -v 選項,這樣可以列印出更詳細的資訊。
[[email protected] /]# time -v ls
bin dev   lib     media  proc  seLinux   tmp
boot    etc   lib64   mnt   root  srv  usr
cgroup  home  lost+found  opt    sbin  sys  var
    Command being timed: "ls"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 0%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    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): 956
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 292
    Voluntary context switches: 1
    Involuntary context switches: 1
    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

注意,上面的 Elapsed(wall clock)time(h:mm:ss or m:ss):0:00.00,值是 0,難道執行 ls 命令沒有消耗時間?

非也,事情的真相是這樣的:在 time 命令的輸出中,Elapsed time 是通過系統呼叫 gettimeofday 獲取到的結束時間和起始時間相減得到的。因此,time 對於執行時間較短的任務計時時,會產生一定誤差。time 命令輸出的時間統計精度基本在 10 毫秒級。

原來是精度的問題啊,少於 10 毫秒的程式,真的是連 time 也無法精確計時。

time 命令輸出指標介紹

time 命令可以顯示的資源共有三大項,分別是:時間、記憶體和 I/O。下面來具體看看 time 命令都顯示了哪些指標資料。

(1) 時間
指 標 含 義
Elapsed (wall clock) time 執行命令所花費的時間,格式是:[hour]:minute:second
System time 命令執行時在核心模式所花費的時間,單位是秒
User time 命令執行時在使用者模式所花費的時間,單位是秒
Percent of CPU this job got 命令執行時 CPU 的佔用比例。
其實這個數位就是核心模式的 CPU 時間加上使用者模式的 CPU 時間除以總時間

(2) 記憶體
指 標 含 義
Maximum resident set size 執行程式所佔用記憶體的最大值。單位是 KB
Average resident set size 執行程式所佔用記憶體的平均值,單位是 KB
Average total size 執行程式所佔用的記憶體總量(stack+data+text)的平均大小, 單位是 KB
Average unshared data size 執行程式所佔用的私有資料區(unshared data area)的平均 大小,單位是 KB
Average stack size 執行程式所佔用的私有堆疊(unshared stack)的平均大小, 單位是 KB
Average shared text size 執行程式間共用內容(shared text)的平均值,單位是 KB
Page size 系統記憶體頁的大小,單位是 byte。對於同一個系統來說,這 是個常數

(3) I/O
指 標 含 義
Major (requiring I/O) page faults 此程式的主要記憶體頁錯誤發生的次數。
所謂的主要記憶體頁錯誤是指某一記憶體頁己經詈換到 SWAP 分割區中,又被其他程式使用過,該頁的內容必須從 SWAP 分割區裡再讀出來才能使用
Minor (reclaiming a frame) page faults 此程式的次要記憶體頁錯誤發生的次數。
所謂的次要記憶體頁錯誤是指某一記憶體頁雖然己經詈換到 SWAP 中,但尚未被其他程式使用。此時該頁的內容並未 被破壞,不必從 SWAP 分割區裡讀出來即可直接使用
Swaps 此程式被交換到 SWAP 分割區的次數
Involuntary context switches 此程式被強迫中斷(如 CPU 時間耗盡)的次數
Voluntary context switches 此程式自願中斷(I/O 執行完畢,磁碟讀取完成等)的次數
File system inputs 此程式所輸入的檔案數
File system outputs 此程式所輸出的檔案數
Socket messages received 此程式所收到的 Socket Message
Socket messages sent 此程式所送出的 Socket Message
Signals delivered 此程式所收到的信號數
Exit status 命令退出狀態