我试图获取我的程序完成所需的时间(又称经过时间),所以我使用通用的time
.
通过这样做,我得到了 3 个测量结果:用户、系统和总数。这很好,但我发现我感兴趣的用户时间只有两位小数,我需要更多。有什么办法可以从我的时间命令中获得更多的小数位吗?
示例:time ./myCProgram
输出:0.17s 用户 1.21s 系统 130% cpu 0.187 总计
想要的输出:0.17000s 用户 1.21s 系统 130% cpu 0.187 总计(或更多小数位)
答案1
如果您想要的只是经过的时间,那么使用 zsh 或 ksh93:
$ typeset -F SECONDS=0; sleep 1; print "$SECONDS"
1.0012850761
现在,这种精确度是否有意义是另一回事了。
答案2
计算时间在纳秒在下面GNU/Linux
, 使用巴什。
警告这篇文章因那里讨论的一种新的好方法而变得过时:分析 bash (3 个回答)并与充分可以使用 巴什那里的源文件: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
, 命名/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
。
用于计算下整数巴什,不需要使用bc
and 来解析 proc 文件,我们可以使用mapfile
which is abash 内置:
# 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 函数,有两个计数器:一个用于每次调用,另一个用于一种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 [email protected]: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
使用for ,减少脚本更改(在脚本顶部添加四行,在底部添加一行):trap debug
作为诱捕调试将会发生前 $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 [email protected]: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 [email protected]: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 - [email protected]
# 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