web-dev-qa-db-ja.com

普遍的な非bashの「時間」ベンチマークの代替?

異なるシェル間でスクリプトの実行時間を比較するために、一部のSEの回答は、次のようにbashbuilt-intimeコマンドを使用することを提案しています。

time bash -c 'foo.sh'
time dash -c 'foo.sh'

...etc、テストするすべてのシェル用。このようなベンチマークでは、各シェルの読み込みと初期化に必要な時間itselfを排除できません。たとえば、上記の両方のコマンドが 初期のフロッピーディスクの読み取り速度の遅いデバイス 、(124KB/s)、dash(a 〜150K実行可能)は、約7xbash〜1M)よりも速くロードされ、シェルのロード時間はtimeの数値を歪めます-これらのシェルのプリロード時間は無関係です各シェルの下でのfoo.shの実行時間の測定afterシェルがロードされました。

within各シェルから実行できるスクリプトタイミングのために実行するのに最適なポータブルで一般的なユーティリティは何ですか?したがって、上記のコードは次のようになります。

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'

注意:Shell built-intimeコマンドはありません。移植可能なものや一般的なものはないためです。


Utilがシェルの内部コマンドとパイプラインにかかる時間をベンチマークでき、ユーザーが最初にそれらをスクリプトにラップする必要がない場合はさらに良いでしょう。このような人工構文は役に立ちます:

general_timer_util "while read x ; do echo x ; done < foo"

一部のシェルの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
10
agc

timeはPOSIXによって指定される であり、POSIXが言及する唯一のオプションはAFAICT(-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
10
muru

高解像度タイマーをサポートする[〜#〜] 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}"

そして、次のようにスクリプトを呼び出します。

/usr/local/bin/timing Dig +short unix.stackexchange.com
141.835

出力単位はミリ秒です。

7
Rabin

timeユーティリティは通常、シェルに組み込まれているため、「中立」タイマーとしては役に立たないようになっています。

ただし、このユーティリティは通常、外部ユーティリティ/usr/bin/timeとしても利用でき、提案したタイミング実験を実行するために使用できます。

$ bash -c '/usr/bin/time foo.sh'
6
Kusalananda

ここに解決策があります:

  1. 各シェルが自分自身をロードして初期化するのにかかる時間をなくす

  2. 各シェルからwithinから実行できます

  3. 使用

    シェル組み込みのtimeコマンドはありません。移植性や汎用性がないためです。

  4. すべてのPOSIX互換シェルで動作します。
  5. すべてのPOSIX互換およびXSI準拠のシステムでCコンパイラーを使用するか、事前にC実行可能ファイルをコンパイルできる場所で動作します。
  6. すべてのシェルで同じタイミング実装を使用します。

2つの部分があります。つまり、廃止予定ですが、_clock_gettime_よりも移植性が高い gettimeofday をラップする短いCプログラムと、そのプログラムを使用する短いシェルスクリプトです。スクリプトのソースの両側を読み取るマイクロ秒精度の時計を取得します。 Cプログラムは、タイムスタンプの1秒未満の精度を取得する唯一の移植可能な最小限のオーバーヘッドの方法です。

これが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);
}
_

そして、シェルスクリプトtimer

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

START=$(./Epoch)
. "$1"
END=$(./Epoch)
echo "$END - $START" | bc
_

これは標準の Shellコマンド言語 および bc であり、POSIX互換シェルの下でスクリプトとして機能するはずです。

これは次のように使用できます。

_$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662
_

システム時間やユーザー時間は測定されず、単調でない壁時計の経過時間のみが測定されます。スクリプトの実行中にシステムクロックが変化すると、正しくない結果が得られます。システムに負荷がかかっている場合、結果は信頼できなくなります。シェル間で移植できるものは他にないと思います。

変更されたタイマースクリプトは、スクリプトの外でコマンドを実行する代わりに eval を使用できます。

6
Michael Homer

による入力のおかげで、大きな部分で/proc/uptimeおよびdc/bc/awkを使用して複数回改訂されたソリューションagc

#!/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."

/proc/uptimeが存在し、特定の形式を持っていることは明らかです。

4
phk