使用Bash choroba的答案计算程序的平均执行时间

问题描述 投票:6回答:3

要获得任何可执行文件的执行时间,比如a.out,我可以简单地写time ./a.out。这将输出实时,用户时间和系统时间。

是否有可能编写一个运行程序多次的bash脚本并计算并输出平均实际执行时间?

bash time execution
3个回答
5
投票

您可以编写一个循环并收集time命令的输出并将其传输到awk以计算平均值:

avg_time() {
    #
    # usage: avg_time n command ...
    #
    n=$1; shift
    (($# > 0)) || return                   # bail if no command given
    for ((i = 0; i < n; i++)); do
        { time -p "$@" &>/dev/null; } 2>&1 # ignore the output of the command
                                           # but collect time's output in stdout
    done | awk '
        /real/ { real = real + $2; nr++ }
        /user/ { user = user + $2; nu++ }
        /sys/  { sys  = sys  + $2; ns++}
        END    {
                 if (nr>0) printf("real %f\n", real/nr);
                 if (nu>0) printf("user %f\n", user/nu);
                 if (ns>0) printf("sys %f\n",  sys/ns)
               }'
}

例:

avg_time 5 sleep 1

会给你的

real 1.000000
user 0.000000
sys 0.000000

这可以很容易地增强到:

  • 在执行之间睡一段时间
  • 在执行之间睡眠一段随机时间(在一定范围内)

来自time -pman time的含义:

   -p
      When in the POSIX locale, use the precise traditional format

      "real %f\nuser %f\nsys %f\n"

      (with  numbers  in seconds) where the number of decimals in the
      output for %f is unspecified but is sufficient to express the
      clock tick accuracy, and at least one.

您可能还想查看此命令行基准测试工具:

sharkdp/hyperfine


2
投票

Total execution time vs sum of single execution time

关心!除以N舍入执行时间之和是不精确的!

相反,我们可以划分N次迭代的总执行时间(N)

avg_time_alt() { 
    local -i n=$1
    local foo real sys user
    shift
    (($# > 0)) || return;
    { read foo real; read foo user; read foo sys ;} < <(
        { time -p for((;n--;)){ "$@" &>/dev/null ;} ;} 2>&1
    )
    printf "real: %.5f\nuser: %.5f\nsys : %.5f\n" $(
        bc -l <<<"$real/$n;$user/$n;$sys/$n;" )
}

注意:这使用bc而不是awk来计算平均值。为此,我们将创建一个临时的bc文件:

printf >/tmp/test-pi.bc "scale=%d;\npi=4*a(1);\nquit\n" 60

这将计算与小数点后60,然后安静地退出。 (您可以调整主机的小数位数。)

演示:

avg_time_alt 1000 sleep .001
real: 0.00195
user: 0.00008
sys : 0.00016

avg_time_alt 1000 bc -ql /tmp/test-pi.bc
real: 0.00172
user: 0.00120
sys : 0.00058

qazxsw poi将回答:

codeforester's function

Alternative, inspired by avg_time 1000 sleep .001 real 0.000000 user 0.000000 sys 0.000000 avg_time 1000 bc -ql /tmp/test-pi.bc real 0.000000 user 0.000000 sys 0.000000 , using Linux'schoroba's answer

好的,你可以考虑:

/proc

这是基于avgByProc() { local foo start end n=$1 e=$1 values times shift; export n; { read foo; read foo; read foo foo start foo } < /proc/timer_list; mapfile values < <( for((;n--;)){ "$@" &>/dev/null;} read -a endstat < /proc/self/stat { read foo read foo read foo foo end foo } </proc/timer_list printf -v times "%s/100/$e;" ${endstat[@]:13:4} bc -l <<<"$[end-start]/10^9/$e;$times" ) printf -v fmt "%-7s: %%.5f\\n" real utime stime cutime cstime printf "$fmt" ${values[@]} }

/proc

那么现在:

man 5 proc | grep [su]time\\\|timer.list | sed  's/^/>   /'
            (14) utime  %lu
            (15) stime  %lu
            (16) cutime  %ld
            (17) cstime  %ld
     /proc/timer_list (since Linux 2.6.21)

其中avgByProc 1000 sleep .001 real : 0.00242 utime : 0.00015 stime : 0.00021 cutime : 0.00082 cstime : 0.00020 utime代表用户时间和系统时间为bash本人和stimecutime代表儿童用户时间和儿童系统时间最有趣。

Nota:在这种情况下(qazxsw poi)命令不会使用大量资源。

cstime

这变得更加明确......当然,随着sleepavgByProc 1000 bc -ql /tmp/test-pi.bc real : 0.00175 utime : 0.00015 stime : 0.00025 cutime : 0.00108 cstime : 0.00032 连续但不是原子的访问,timer_list(基于nanosecs)和self/stat(基于刻度,即:1/100秒)之间的差异可能会出现!


0
投票

记录执行的开始和结束时间并将差异除以执行次数可能更容易。

real

我使用c?[su]time来计算平均值,因为bash不支持浮点算术。

要获得更高的精度,您可以切换到纳秒:

#!/bin/bash
times=10
start=$(date +%s)
for ((i=0; i < times; i++)) ; do
    run_your_executable_here
done
end=$(date +%s)
bc -l <<< "($end - $start) / $times"

bc类似。

© www.soinside.com 2019 - 2024. All rights reserved.