C

如何調整時間命令以測量程序執行時間

  • July 5, 2014

我正在嘗試獲取我的程序完成所需的時間(也就是經過的時間),所以我使用的是 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包含uptimeoffset

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 文件,我們可以使用內置mapfilebash

# 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

引用自:https://unix.stackexchange.com/questions/55322