通用非 bash `time` 基准测试替代方案?

agc*_*agc 10 shell shell-script timestamps benchmark portability

为了比较不同 shell 之间脚本的运行时间,一些 SE 答案建议使用bash内置 time命令,如下所示:

time bash -c 'foo.sh'
time dash -c 'foo.sh'
Run Code Online (Sandbox Code Playgroud)

...,用于每个要测试的外壳。此类基准测试无法消除每个 shell 加载和初始化自身所需的时间。例如,假设上述两种命令被存储在一缓慢的设备具有早期软盘的读取速度,(124KB /秒), dash(一〜150K可执行程序)将加载大约7倍的速度比bash〜1M),所述壳加载时间会扭曲time数字——这些炮弹的预装载时间与测量炮弹加载foo.sh每个炮弹下方的运行时间无关。

什么是最好的可移植和通用的 util 来运行脚本计时,可以从每个 shell运行?所以上面的代码看起来像:

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'
Run Code Online (Sandbox Code Playgroud)

注意:没有 shell内置 time命令,因为没有一个是可移植的或通用的。


如果 util 还能够对 shell 的内部命令和管道所花费的时间进行基准测试,而无需用户首先将它们包装在脚本中,那就更好了。像这样的人工语法会有所帮助:

general_timer_util "while read x ; do echo x ; done < foo"
Run Code Online (Sandbox Code Playgroud)

一些shell'time可以管理这个。例如bash -c "time while false ; do : ; done"作品。要查看系统上哪些有效(和无效),请尝试:

tail +2 /etc/shells | 
while read s ; do 
    echo $s ; $s -c "time while false ; do : ; done" ; echo ----
done
Run Code Online (Sandbox Code Playgroud)

mur*_*uru 10

您应该注意timePOSIX 指定的,并且 AFAICT POSIX 提到的唯一选项 ( -p) 被各种外壳正确支持:

$ bash -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ dash -c 'time -p echo'

real 0.01
user 0.00
sys 0.00
$ busybox sh -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ ksh -c 'time -p echo'       

real 0.00
user 0.00
sys 0.00
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 8

time正如您所注意到的,该实用程序通常内置于 shell 中,这使得它无法用作“中立”计时器。

但是,该实用程序通常也可作为外部实用程序使用,/usr/bin/time很可能用于执行您建议的计时实验。

$ bash -c '/usr/bin/time foo.sh'
Run Code Online (Sandbox Code Playgroud)


Rab*_*bin 7

我使用支持高分辨率计时器的GNU date命令:

START=$(date +%s.%N)
# do something #######################

"$@" &> /dev/null

#######################################
END=$(date +%s.%N)
DIFF=$( echo "scale=3; (${END} - ${START})*1000/1" | bc )
echo "${DIFF}"
Run Code Online (Sandbox Code Playgroud)

然后我像这样调用脚本:

/usr/local/bin/timing dig +short unix.stackexchange.com
141.835
Run Code Online (Sandbox Code Playgroud)

输出单位为毫秒。


Mic*_*mer 6

这是一个解决方案:

  1. 消除 [s] 每个 shell 加载和初始化自身所需的时间

  2. 可以每个 shell 中运行

  3. 用途

    没有 shell 内置time命令,因为没有一个是可移植的或通用的

  4. 适用于所有 POSIX 兼容的 shell。
  5. 适用于所有具有 C 编译器的POSIX 兼容和 XSI 兼容系统,或者您可以提前编译 C 可执行文件的系统。
  6. 在所有 shell 上使用相同的计时实现。

有两个部分:一个简短的 C 程序gettimeofday,它被弃用,但仍然比clock_gettime,以及一个简短的 shell 脚本,它使用该程序获取读取脚本两端的微秒精度时钟。C 程序是在时间戳上获得亚秒级精度的唯一可移植且开销最小的方法。

这是 C 程序epoch.c

#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
    struct timeval time;
    gettimeofday(&time, NULL);
    printf("%li.%06i", time.tv_sec, time.tv_usec);
}
Run Code Online (Sandbox Code Playgroud)

和 shell 脚本timer

#!/bin/echo Run this in the shell you want to test

START=$(./epoch)
. "$1"
END=$(./epoch)
echo "$END - $START" | bc
Run Code Online (Sandbox Code Playgroud)

这是标准的shell 命令语言bc应该在任何 POSIX 兼容的 shell 下作为脚本工作。

您可以将其用作:

$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662
Run Code Online (Sandbox Code Playgroud)

它不测量系统或用户时间,只测量非单调挂钟经过时间。如果在脚本执行期间系统时钟发生变化,这将给出错误的结果。如果系统在负载下,结果将是不可靠的。我认为没有更好的东西可以在 shell 之间移植。

可以使用修改后的计时器脚本eval来运行脚本之外的命令。


phk*_*phk 5

由于agc的输入,在很大程度上使用/proc/uptimedc//多次修改了解决方案:bcawk

#!/bin/sh

read -r before _ < /proc/uptime

sleep 2s # do something...

read -r after _ < /proc/uptime

duration=$(dc -e "${after} ${before} - n")
# Alternative using bc:
#   duration=$(echo "${after} - ${before}" | bc)
# Alternative using awk:
#   duration=$(echo "${after} ${before}" | awk '{print $1 - $2}')

echo "It took $duration seconds."
Run Code Online (Sandbox Code Playgroud)

显然假设/proc/uptime存在并且具有某种形式。

  • 这将使其能够在 shell 之间移植,但不能在 Unix 实现之间移植,因为有些只是缺少“/proc”文件系统。我不知道这是否是一个问题。 (3认同)