sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

benchmark.txt (12784B)


      1 注意: ここに載せるのはループで回した時の時間である。parse 等の時間は含まれないと考えるべき。
      2 注意: 何故か評価の順序によって時間が変わったりするので何度か試すのが良い。
      3 
      4 * commands
      5 
      6   which -> type (関数 エイリアス 組込コマンドに注意)
      7   date -> printf %()T
      8   expr, bc -> 算術式
      9   正規表現 -> [[ ... =~ ... ]]
     10   enable (builtin を自分で作る)
     11   cat, $(< ...) -> read
     12 
     13   組込コマンドで実装する:
     14     wc -l, tac, tee, cat, paste, ...
     15     od, base64, wc -c, uuencode (ascii85)
     16 
     17   裏機能
     18     プロセス存在確認 -> kill -0
     19     ポーリング -> read -t 0
     20 
     21 * test
     22 
     23   [ よりは test, test よりは [[。
     24 
     25     [[ a ]]
     26       time   2.00 usec/eval
     27     test a
     28       time   5.40 usec/eval
     29     [ a ]
     30       time   6.10 usec/eval
     31 
     32     "[ よりは test" というのは今迄の経験と一致する。
     33     "test よりは [[" というのは当たり前の事である。
     34     これに関しては単語分割が速度を支配している気がする。
     35     [ は単語が余分に一個多い。[[ は毎回の実行時に単語分割はしない。
     36 
     37   変数名の quote はしない。
     38 
     39     [[ $dir == / ]]
     40       time   5.00 usec/eval
     41     [[ "$dir" == / ]]
     42       time   7.40 usec/eval
     43 
     44   変数名は長くても短くても殆ど違いはない。でも、微妙に短い方が良い?
     45 
     46     [[ $d == / ]]
     47       time   5.00 usec/eval
     48     [[ $dir == / ]]
     49       time   5.10 usec/eval
     50     [[ $dirverylonglong == / ]]
     51       time   5.50 usec/eval
     52 
     53   右辺の glob パターンは特別な文字が含まれていなくても下手に quote しない方が速い。
     54 
     55     [[ $dir == / ]]
     56       time   5.10 usec/eval
     57     [[ $dir == '/' ]]
     58       time   5.90 usec/eval
     59     [[ $dir == "/" ]]
     60       time   6.90 usec/eval
     61 
     62   startsWith
     63 
     64     glob による一致が最も速い。というか単純な == / の比較と大して変わらない速度。
     65     パラメータ展開を用いるのは多少時間が掛かる。新しい文字列インスタンスを作るからか。
     66     正規表現を用いる方法はさすがに遅い。しかし思った程には悪くないようだ。
     67 
     68     [[ $d == /* ]]
     69       time   5.10 usec/eval
     70     [[ ${d::1} == / ]]
     71       time  10.30 usec/eval
     72     [[ ! ${d##/*} ]]
     73       time  10.50 usec/eval
     74     [[ $d =~ ^/ ]]
     75       time  26.40 usec/eval
     76 
     77   contains
     78 
     79     同じ傾向だ。
     80 
     81     [[ $d == */* ]]
     82       time   5.60 usec/eval
     83     [[ ! ${d##*/*} ]]
     84       time  11.00 usec/eval
     85     [[ $d =~ / ]]
     86       time  20.20 usec/eval
     87 
     88 
     89 * 代入
     90 
     91   右辺の quote はない方が良い。
     92 
     93     変数の代入の右辺は単語分割の対象ではないので、quote する必要はない。
     94     (quote の必要があるのはチルダ展開ぐらいだろうか。)
     95     これは declare a=$b の形式でも同様である。
     96 
     97     d=$d
     98       time   3.50 usec/eval
     99     d="$d"
    100       time   6.20 usec/eval
    101 
    102   複数の変数の代入はまとめてした方が速い
    103 
    104     a=$d b=$d
    105       time   6.70 usec/eval
    106     a=$d; b=$d
    107       time   9.40 usec/eval
    108 
    109 * 算術式
    110 
    111   代入は直接文字列として実行した方が速い。
    112 
    113     a=0
    114       time   1.40 usec/eval
    115     ((a=0))
    116       time   3.80 usec/eval
    117 
    118     a=0 b=0
    119       time   2.70 usec/eval
    120     ((a=0,b=0))
    121       time   5.80 usec/eval
    122 
    123   呼出は (( )) が一番速い。
    124 
    125     やはり単純な (( )) が一番速い。
    126     意外にも let は変数の代入を用いる方法よりも遅い。やはり単語分割が遅い説?
    127 
    128     ((a++))
    129       time   4.20 usec/eval
    130     (('a++'))
    131       time   4.70 usec/eval
    132     a=$((a+1))
    133       time   7.20 usec/eval
    134     let a++
    135       time   7.70 usec/eval
    136     let 'a++'
    137       time   8.50 usec/eval
    138 
    139   条件判定
    140 
    141     表現が正規化されている事が前提で、かつ等値判定 (== !=) ならば文字列としての比較が最速だ。
    142     それ以外の場合 (変数内に数式があるかもしれない or 不等判定(< > <= =>)) は算術式を使うのが良い。
    143 
    144     [[ a == 0 ]] && x=1
    145       time   5.30 usec/eval
    146     ((a==0)) && x=1
    147       time   8.40 usec/eval
    148     [[ a -eq 0 ]] && x=1
    149       time  11.10 usec/eval
    150 
    151   条件分岐も算術式の内部でした方が速い
    152 
    153     算術式 && vs コマンド && vs if (真)
    154 
    155     ((a==0&&(x=1)))
    156       time   6.50 usec/eval
    157     ((a==0)) && x=1
    158       time   8.20 usec/eval
    159     ((a==0)) && ((x=1))
    160       time  10.30 usec/eval
    161     if ((a==0)); then ((x=1)); fi
    162       time  10.40 usec/eval
    163 
    164     算術式 && vs コマンド && vs if (偽)
    165 
    166     →内部の式が評価されない場合には "コマンド &&" の方が速い様だ。
    167 
    168     ((a==1&&(x=1)))
    169       time   5.70 usec/eval
    170     ((a==1)) && ((x=1))
    171       time   4.60 usec/eval
    172     if ((a==1)); then ((x=1)); fi
    173       time   4.90 usec/eval
    174 
    175     三項条件式 vs if-else (真)
    176 
    177     ((a==0?(x=1):(y=1)))
    178       time   9.00 usec/eval
    179     if ((a==0)); then ((x=1)); else ((y=1)); fi
    180       time  11.00 usec/eval
    181 
    182     三項条件式 vs if-else (偽)
    183 
    184     ((a==1?(x=1):(y=1)))
    185       time   8.80 usec/eval
    186     if ((a==1)); then ((x=1)); else ((y=1)); fi
    187       time  10.70 usec/eval
    188 
    189     複雑な条件分岐の場合
    190     →条件を多少複雑にしても基本的に算術式が速い様である。
    191 
    192     ((x=a==1?1:(a==2?8:(a==3?4:3))))
    193       time  12.30 usec/eval
    194     ((a==1?(x=1):(a==2?(x=8):(a==3?(x=4):(x=3)))))
    195       time  18.30 usec/eval
    196     if [[ a == 1 ]]; then x=1; elif [[ a == 2 ]]; then x=8; elif [[ a == 3 ]]; then x=4; else x=3; fi
    197       time  21.80 usec/eval
    198     if ((a==1)); then ((x=1)); elif ((a==2)); then ((x=8)); elif ((a==3)); then ((x=4)); else ((x=3)); fi
    199       time  24.10 usec/eval
    200 
    201 * 関数呼出
    202 
    203   関数呼出はそんなに遅くないという感覚でいたがまあ確かにそんなに遅くない。
    204   しかしそうは言っても完全に無視できる速さという訳ではない。
    205   が代替の場合は関数にしてもそんなに問題はない・効果はないだろう。
    206   一応関数名が短い方が多少速い。
    207 
    208   function _empty { :; }
    209   function very_very_long_long_function_name { :; }
    210 
    211   :
    212     time   3.30 usec/eval
    213   _empty
    214     time  14.20 usec/eval
    215   very_very_long_long_function_name
    216     time  18.40 usec/eval
    217 
    218 * ループ
    219 
    220   1 ずつ増える変数についての固定長のループならば、
    221   ループのサイズに関係なくブレース展開の方が微妙に速い。
    222   但しブレース展開は以下の制限がある。
    223   + 上限と下限が変数の場合は使えない → ループが十分大きければ eval にすれば OK.
    224   + set +o braceexpand (+B) としている時には利用できない.
    225 
    226   a=0; for i in {0..10}; do ((a+=i)); done
    227     time 132.80 usec/eval
    228   a=0; for ((i=0;i<10;i++)); do ((a+=i)); done
    229     time 187.80 usec/eval
    230   a=0; for i in {0..10000}; do ((a+=i)); done
    231     time 131972.70 usec/eval
    232   a=0; for ((i=0;i<10000;i++)); do ((a+=i)); done
    233     time 185972.70 usec/eval
    234 
    235 ------------------------------------------------------------------------------
    236   配列操作
    237 ------------------------------------------------------------------------------
    238 
    239 push
    240 
    241   j=0; for i in {0..1000}; do a[j++]=$i; done
    242     time 15772.50 usec/eval
    243   for i in {0..1000}; do a+=($i); done
    244     time 16872.50 usec/eval
    245   for i in {0..1000}; do a[${#a[@]}]=$i; done
    246     time 19172.50 usec/eval
    247   for i in {0..1000}; do a=("${a[@]}" $i); done
    248     time 2470972.50 usec/eval
    249 
    250 巨大配列と他の配列を混ぜてループすると滅茶苦茶遅い O(N^2)
    251 
    252   A a=(); ble-measure "for ((i=0;i<$n;i++)); do ((a[i]=i*i,b[i]=i)); done"
    253   B a=({0..1000000}); ble-measure "for ((i=0;i<$n;i++)); do ((a[i]=i*i,b[i]=i)); done"
    254   C a=({0..1000000}); ble-measure "for ((i=0;i<$n;i++)); do ((a[i]=i*i)); done; for ((i=0;i<$n;i++)); do ((b[i]=i)); done"
    255 
    256             usec/eval A  usec/eval B   usec/eval C
    257   n=10      300.20       302.00        453.90
    258   n=20      598.20       595.00        889.90
    259   n=50      1522.20      1522.00       2211.90
    260   n=100     3072.20      3082.00       4471.90
    261   n=200     6252.20      6222.00       8991.90
    262   n=500     16772.20     16472.00      22271.90
    263   n=1000    41072.20     38572.00      49571.90
    264   n=2000    95472.20     89472.00      102171.90
    265   n=5000    159972.20    240972.20     239971.90
    266   n=10000   315972.20    631972.20     485971.90
    267   n=20000   638972.20    2052972.00    971971.90
    268   n=50000   1599972.20   13345972.20   2435972.20
    269   n=100000  3231972.20   67832972.20   4969972.20
    270   n=200000  6508972.20                 9975972.20
    271   n=500000                             25708972.00
    272   n=1000000                            53124972.00
    273 
    274   予想:
    275     bash は配列を双方向リストで実装している。
    276     末尾または先頭へのアクセスは高速にできる。
    277     シーケンシャルなアクセスも高速にできる様に、前回アクセスした配列と位置を記録している。
    278     他の配列に触ると前回アクセスした位置は失われる。
    279 
    280   別の変数に触る場合は遅くならない。
    281 
    282   x=0; for ((i=0;i<200000;i++)); do ((a[i]=i*i,x=i)); done
    283     time 5647972.00 usec/eval
    284 
    285 100k    21.978s 4
    286 200k    33.204s 16
    287 300k    50.981s 34
    288 1000k 6m56.349s
    289 
    290 
    291 globpat による配列要素のフィルタ
    292 
    293   配列要素一つずつに対して [[ ]] で検索するのが素直な実装である。
    294   一方で compgen にも同様の機能がある。
    295   配列要素数が少ない内は compgen を用いた方が速いが、
    296   配列要素が多くなってくると compgen を用いた方法は遅くなっていく。
    297   (compgen 自体が悪いのか単語分割が遅いのかは分からない)。
    298 
    299   | a=({0..99999})
    300   | function filter1 { i=0 b=(); for x in "${a[@]}"; do [[ $x == *1?2 ]] && b[i++]=$x; done; }
    301   | function filter2 { veval b 'compgen -X "!*1?2" -W "${a[*]}"'; b=($b); }
    302   | ble-measure 'filter1'
    303   | ble-measure 'filter2'
    304   | function filter2base { veval b 'type filter2base'; }
    305 
    306   a length  filter1     filter2     (usec/eval)
    307   --------  ----------  ----------
    308     1000      13171.50     4721.50
    309    10000     139971.50    79671.50
    310   100000    1529971.30  4670971.40
    311 
    312   filter2base ... 343.50 usec
    313 
    314 ------------------------------------------------------------------------------
    315   コマンド起動
    316 ------------------------------------------------------------------------------
    317 
    318   * fork test
    319 
    320     http://qiita.com/b4b4r07/items/726df1543fc48d2cb20b
    321 
    322     printf -v A '%d + ' {1..10000}; echo $((${A}0))
    323       time 40071.90 usec/eval
    324     n=0; for i in {1..10000}; do ((n+=i)); done; echo $n
    325       time 134971.90 usec/eval
    326     for i in $(seq 10000); do printf "$i + "; [ $i -eq 10000 ] && printf "0\n"; done | bc
    327       time 408971.90 usec/eval
    328     n=0; for i in $(seq 10000); do n=$(echo $n + $i | bc); done; echo $n
    329       time 29894971.90 usec/eval
    330 
    331   * ... vs builtin ...
    332 
    333     builtin を先頭につければパスを探索する必要がないと思ったが別に速くはならない。
    334     というか良く考えたら builtin を検索するのにも同じだけ時間が掛かる。
    335 
    336 
    337   * 間接代入 (ある変数に代入先の変数名が入っている場合)
    338 
    339     こういう奴です: eval "$var=\"\$value\""
    340 
    341     (($var=value)) ※値が整数値の場合限定
    342       time   5.50 usec/eval
    343     printf -v "$var" %s "$value"
    344       time  16.00 usec/eval
    345     eval "$var=\"\$value\""
    346       time  31.30 usec/eval
    347     IFS= read -r -d '' "$var" <<< "$value"
    348       time 111.60 usec/eval
    349 
    350   * コマンド置換
    351 
    352 ------------------------------------------------------------------------------
    353   Bash 状態
    354 ------------------------------------------------------------------------------
    355 
    356   * shopt -q optname
    357 
    358     shopt -s/-u optname による設定の確認。
    359     shopt -q はリダイレクトを伴うからか遅い。というか >/dev/null は不要っぽい。
    360     また使いやすい様に関数を定義してみたりしたが関数呼出はやはり遅くなる様だ。
    361 
    362     shopt -q extquote
    363       time   8.40 usec/eval
    364     [[ :$BASHOPTS: == *:extquote:* ]]
    365       time  11.40 usec/eval
    366     function ble/util/has-shopt { [[ :$BASHOPTS: == *:"$1":* ]]; }
    367     ble/util/has-shopt extquote
    368       time  29.00 usec/eval
    369     shopt -q extquote &>/dev/null
    370       time  32.40 usec/eval
    371 
    372   * [[ -o option-name ]]
    373 
    374     set -o/+o ... による設定の確認。
    375     基本的には [[ -o name ]] で確認することが出来る (bash-3.0 以降確認済, 他未確認)。
    376     一部の option-name に関してはシェル変数 $- を用いて確認する事も出来る。
    377     しかし [[ -o name ]] を使うのが速い様である。
    378 
    379     [[ -o hashall ]]
    380       time   3.60 usec/eval
    381     [[ $- == *h* ]]
    382       time   5.60 usec/eval
    383     [[ :$SHELLOPTS: == *:hashall:* ]]
    384       time   8.90 usec/eval