如何調整時間命令以測量程序執行時間
我正在嘗試獲取我的程序完成所需的時間(也就是經過的時間),所以我使用的是 common
time
.我這樣做得到的是 3 個度量:使用者、系統和總數。這很好,但我發現我感興趣的使用者時間只有兩位小數,我需要更多。有什麼辦法可以讓我的時間命令得到更多的小數位?
範例:
time ./myCProgram
輸出:0.17s user 1.21s system 130% cpu 0.187 total
希望輸出:0.17000s 使用者 1.21s 系統 130% cpu 0.187 總(或更多小數位)
如果您想要的只是經過的時間,那麼使用 zsh 或 ksh93:
$ typeset -F SECONDS=0; sleep 1; print "$SECONDS" 1.0012850761
現在,這種精確度是否有意義是另一回事。
使用bash計算時間(以納秒為單位) 。
GNU/Linux
警告這篇文章被那裡討論的一種新的好方法變得過時了:Profiling bash (3 answers)和完整的即用型 bash源文件:Elap-bash V3
檢索可靠值的方法
有一些方法可以請求比一秒更精細的時間。
第一,但不是最好的:1/100 秒
對於 1/100 秒,您可以簡單地參考
/proc/uptime
:sed 's/ .*$//' /proc/uptime 276440.58
為計算實際 UTC 時間而添加的時間偏移量可以通過以下方式之一獲得:
ps ho lstart 1 | date -f - +%s 1357193821
或者
date +%s.%N-$(sed 's/ .*$//' /proc/uptime ) | bc -l 1357193821.088187101
由於偏移量是靜態的,因此該值只能在腳本開始時計算 1 次。
1/1000000000 秒,
proc
僅使用條目:對於納秒計算,有一個
proc entry
, named/proc/timer_list
包含uptime
和offset
:sed < /proc/timer_list -ne '/now at/p;/offset/{p;q}' now at 276350507668586 nsecs .offset: 1357193821075753443 nsecs
所以這
echo $(($(sed < /proc/timer_list -ne ' /^now at/{s/now at \([0-9]*\) ns.*$/\1/;H}; /offset/{s/^.*: *\([0-9]*\) ns.*$/\1/;G;s/\n\+/+/;p;q}'))) 1357470173543424035
是從過去的整數****納秒
1970-1-1 00:00:00 UTC
。對於在bash下計算整數,不需要使用
bc
和解析 proc 文件,我們可以使用內置mapfile
的bash:# first, some static variables (with fork, but only 1 time, at begin;): nowAtLine=$(($(sed -ne < /proc/timer_list '/now at/{=;q}')-1)) offset=$(sed -ne < /proc/timer_list ' /offset/{s/^.*: *\([0-9]*\) n.*$/\1/p;q}') # than this will be a lot quicker than a fork: mapfile -n 1 -s $nowAtLine timerList </proc/timer_list && timerList=($timerList) && echo $((${timerList[2]}+offset)) 1357470173543424035
1/1000000000 秒,使用
date
二進制工具:最後,如果它們不存在,我們可以
date
記住,這fork
比閱讀花費更多的時間proc files
,只停留在一個 bash 會話中。date +%s%N 1357470074808968375
我的
elap.bash
功能基於此,我編寫了一個elap bash 函式,有兩個計數器:1 用於每次呼叫,另一個用於
overall duration
.用法:
首先,這是一個函式,而不是腳本。您必須
source
在目前的 bash 會話中使用它們才能使用它。. elap.bash
句法:
elap [ [ -r | -R ] | [ -n ] [ -t | -T ] [<simple text report>] ] -r reset first counter only, don't output anything, like -R... -R reset both counters, (both -r and -R must by unique argument) -n don't reset any counter (just print) -t print both counters (reset first counter) -T print and reset
在使用它之前重置兩個計數器:
elap -R find /usr/bin >/dev/null elap browsing /usr/bin 0.025389543 browsing /usr/bin
所以你可以在腳本中添加一些標記:
#!/bin/bash . elap.bash elap -R tar -cf /tmp/test.tar -C / bin elap making a tarball of $(stat -c %s /tmp/test.tar) bytes gzip /tmp/test.tar elap compressing them to $(stat -c %s /tmp/test.tar.gz) bytes scp /tmp/test.tar.gz backup@elswhere.net:backups/ elap sending file to backup server rm /tmp/test.tar.gz elap removing compressed tarball elap -t total duration 0.043223957 making a tarball of 5877760 bytes 0.667249628 compressing them to 2742537 bytes test.tar.gz 100% 2678KB 2.6MB/s 00:00 0.380779818 sending file to backup server 0.010262259 removing compressed tarball 0.003566335 1.105081997 total duration
用於
trap debug
以下步驟使用或不使用
-t
開關,trap debug
逐步使用 for,減少腳本更改(在腳本頂部添加四行,在底部添加一行):由於在執行之前會發生調試陷阱,因此我們需要將變數內容儲存到變數中以便正確列印,並在腳本底部添加一個虛擬命令。
$BASH_COMMAND``$BASH_LAST
#!/bin/bash . elap.bash elap -R export BASH_LAST=Starting trap 'elap -t $BASH_LAST;BASH_LAST=$BASH_COMMAND' debug tar -cf /tmp/test.tar -C / bin gzip /tmp/test.tar scp /tmp/test.tar.gz backup@elswhere.net:backups/ rm /tmp/test.tar.gz exit $?
該
exit $?
命令需要在最後一個命令之後rm
轉儲統計資訊。0.001011086 0.001011086 Starting 0.045175969 0.046187055 tar -cf /tmp/test.tar -C / bin 0.651394209 0.697581264 gzip /tmp/test.tar test.tar.gz 100% 2678KB 2.6MB/s 00:00 0.374499354 1.072080618 scp /tmp/test.tar.gz backup@elswhere.net:backups/ 0.007160101 1.079240719 rm /tmp/test.tar.gz
函式源
uptime
如果您更喜歡使用 forkdate +%s%N
而不是使用 1/100 秒的粒度,那麼您可以在哪里切割(或重新排序)零件。# # Bash source file for fine elapsed time reporting # based on /proc/timer_list, display elapsed time in nanosecs # or /proc/uptime if timer_list not present, for 100th of secs. # if none of them if present, fall back to *fork* `date +%s%N`. # # (C) 2011-2012 Felix Hauri - felix@f-hauri.ch # Licensed under terms of LGPL v3. www.gnu.org # Usage: # load script into bash using ``source elap.bash'' # # Syntaxe: elap [ [ -r | -R ] | [ -n ] [ -t | -T ] [<simple text report>] ] # -r reset first counter only, don't output anything, like -R... # -R reset both counters, (both -r and -R must by unique argument) # -n don't reset any counter (just print) # -t print both counters (reset first counter) # -T print and reset # # nota: using ``-n'' in combinaison with any of ``-r'' or ``-R'' is buggy. export _elaP_now _elaP_last _elaP_elap _elaP_last2 _elaP_dec if [ -r /proc/timer_list ] ;then _elaP_file=/proc/timer_list _elaP_dec=9 _elaP_field=2 mapfile < $_elaP_file _elaP_now _elaP_line=0 while [ "${_elaP_now[_elaP_line]}" == \ "${_elaP_now[_elaP_line]#*now at}" ] ;do ((_elaP_line++)) done eval 'function elap_getNow() { mapfile -n 1 -s '$_elaP_line' <'$_elaP_file' _elaP_now _elaP_now=($_elaP_now) _elaP_now=${_elaP_now[_elaP_field]} }' else # --- To be removed for nanoseconds only if [ -r /proc/uptime ] ;then _elaP_dec=2 function elap_getNow() { read -a _elaP_now </proc/uptime _elaP_now _elaP_now=${_elaP_now//./} } else # --- End of part to be removed for ns only. _elaP_dec=9 function elap_getNow() { _elaP_now=$(date +%s%N) ;} fi # --- Remove this line too for ns only. fi export -f elap_getNow elap() { local _Z9=000000000 local _elaP_setLast=true [ "$1" == "-n" ] && shift && _elaP_setLast=false [ "$2" == "-n" ] && set -- $1 ${@:3} && _elaP_setLast=false elap_getNow _elaP_elap=$((_elaP_now - _elaP_last)) [ ${#_elaP_elap} -lt $_elaP_dec ] && \ _elaP_elap=${_Z9:0:_elaP_dec-${#_elaP_elap}}$_elaP_elap [ "${*}" == "-R" ] && _elaP_last2=$_elaP_now || \ [ "${*}" == "-r" ] || if [ "$1" == "-t" ] || [ "$1" == "-T" ] ;then local _elaP_setLast2=false [ "$1" == "-T" ] && _elaP_setLast2=true shift _elaP_elap2=$((_elaP_now - _elaP_last2)) [ ${#_elaP_elap2} -lt $_elaP_dec ] && \ _elaP_elap2="${_Z9:0:_elaP_dec-${#_elaP_elap2}}$_elaP_elap2" printf "%6d.%s %6d.%s %s\n" \ "${_elaP_elap:0:${#_elaP_elap}-$_elaP_dec}" \ "${_elaP_elap:${#_elaP_elap}-_elaP_dec}" \ "${_elaP_elap2:0:${#_elaP_elap2}-$_elaP_dec}" \ "${_elaP_elap2:${#_elaP_elap2}-_elaP_dec}" "${*}" $_elaP_setLast2 && _elaP_last2=$_elaP_now else printf "%6d.%s %s\n" \ "${_elaP_elap:0:${#_elaP_elap}-$_elaP_dec}" \ "${_elaP_elap:${#_elaP_elap}-_elaP_dec}" "${*}" fi $_elaP_setLast && _elaP_last=$_elaP_now } export -f elap