繰り返し文字生成の実行時間
2024/08/31 19:08
https://genzouw.com/entry/2020/10/29/211143/2094/
選択肢が割とあって「お、おう……」となったので「実行速度」で選ぶことにした記事。
シェルスクリプトなので、普段は実行時間なんて気にしないのだけど。
ここで結論を先に書いておくと、ビルトインコマンドである for 文(for *1; do echo -n '='; done)を利用するのが最強のようです。
次点で、print (printf "=%0.s" 0..9)でした。
テスト環境
テスト環境は、以下のような状況です。$ uname -moi armv7l unknown GNU/Linux $ $ bash -version | head -n 1 GNU bash, バージョン 5.1.4(1)-release (arm-unknown-linux-gnueabihf) $ $ . /etc/os-release $ echo ${PRETTY_NAME} Raspbian GNU/Linux 11 (bullseye)
テスト方法
スクリプトにしておいて、シンプルに time で計測します。作成したスクリプトおよび内容は、以下の通りです。
$ ls -1 test-A.sh test-B.sh test-C.sh test-D.sh test-E.sh test-F.sh test-G.sh work.sh $ $ for i in *.sh do echo "### ${i}" echo "----------------------------------------------------" cat ${i} echo "----------------------------------------------------" echo "" done ### test-A.sh ---------------------------------------------------- #!/bin/bash printf "=%0.s" {0..9} ---------------------------------------------------- ### test-B.sh ---------------------------------------------------- #!/bin/bash yes = | head -n 10 | tr -d '\n' ---------------------------------------------------- ### test-C.sh ---------------------------------------------------- #!/bin/bash seq -s '=' 0 10 | tr -d '[0-9]' ---------------------------------------------------- ### test-D.sh ---------------------------------------------------- #!/bin/bash seq -s '=' 0 10 | sed "s/[0-9]//g" ---------------------------------------------------- ### test-E.sh ---------------------------------------------------- #!/bin/bash for ((i=0; i<10; i++)); do echo -n '='; done ---------------------------------------------------- ### test-F.sh ---------------------------------------------------- #!/bin/bash seq 10 | xargs -i echo -n = ---------------------------------------------------- ### test-G.sh ---------------------------------------------------- #!/bin/bash seq 10 | xargs -i printf "=" ---------------------------------------------------- ### work.sh ---------------------------------------------------- #!/bin/bash fnChecker() { echo "### ${1}" time ./${1} } fnChecker test-A.sh fnChecker test-B.sh fnChecker test-C.sh fnChecker test-D.sh fnChecker test-E.sh fnChecker test-F.sh fnChecker test-G.sh ---------------------------------------------------- $
計測
傾向が見えればよいと考えたため、とりあえず1回実行したところが、以下の数値です。$ ./work.sh ### test-A.sh ========== real 0m0.016s user 0m0.013s sys 0m0.003s ### test-B.sh ========== real 0m0.028s user 0m0.020s sys 0m0.030s ### test-C.sh ========== real 0m0.023s user 0m0.024s sys 0m0.007s ### test-D.sh ========== real 0m0.028s user 0m0.009s sys 0m0.028s ### test-E.sh ========== real 0m0.014s user 0m0.001s sys 0m0.013s ### test-F.sh ========== real 0m0.082s user 0m0.026s sys 0m0.067s ### test-G.sh ========== real 0m0.080s user 0m0.036s sys 0m0.051s $
結論
for コマンドを使います。感想
printf コマンド(test-A.sh)もなかなか良い数字なんだけど、ビルトインコマンドの for によるループ(test-E.sh)が強いですね。その他、普通は bash の予約語なので利用されない time コマンドを使ってみての計測なんかもしてみましたが、メモリ使用率なんかは変化が少ないようです。
wait
time コマンドで計測できる wait の内容は、次の通り(man bash の引用)。wait の回数、つまりそのプログラムが自発的にコンテキストスイッチされた回数。
例えば、I/O 操作の完了を待っている間などが該当する。
$ type time time はシェルの予約語です $ $ which time /usr/bin/time $ $ for i in test-*.sh > do > /usr/bin/time -f "\nwait: %w" ./${i} > done ========== wait: 1 ========== wait: 8 ========== wait: 7 ========== wait: 5 ========== wait: 1 ========== wait: 31 ========== wait: 36 $計測した結果は上記の通りですが、printf と for でのループ、待ちなんてほとんど発生してませんね。
その他
あと、こんな感じで他にもいろいろ計測できたりします。これは、メモリ(プロセス生存中のそのプロセスの resident set size の最大値)。
$ for i in test-*.sh do echo "### ${i}" /usr/bin/time -f "\n Memory: %MKB" ./${i} done ### test-A.sh ========== Memory: 2752KB ### test-B.sh ========== Memory: 2820KB ### test-C.sh ========== Memory: 2820KB ### test-D.sh ========== Memory: 2816KB ### test-E.sh ========== Memory: 2692KB ### test-F.sh ========== Memory: 2868KB ### test-G.sh ========== Memory: 2868KB $うん。だいたい 3MB 程度ですね。
メジャーページフォルトの回数
外部コマンドでは、メジャーページフォルトの回数を計測も出来たりします。$ for i in test-*.sh do echo "### ${i}" /usr/bin/time -f "\n Page: %F" ./${i} done有意な差がないので結果は載せないですが、test-C.sh (seq -s '=' 0 10 | tr -d '[0-9]') はちょこちょこページフォルトが発生している模様。
他のも、合ったりなかったり。
$ for i in test-*.sh do echo "### ${i}" /usr/bin/time -f "\n Memory: %MKB" ./${i} done