速度測定をするプログラムは./a.out。これに適当な引数を与え、100回走らせることを考える。プログラムをひとつづつ連続的に走らせる方法と、プログラムをP個づつ並列に走らせる方法とがある。
まずは適当な引数を100個収めたファイルを作る。ここでは、null文字を100個収めたファイルnull.txtを作成。
$ for i in `seq 1 100`; do echo -n -e "\0000"; done > null.txt $ ls -l null.txt -rw-r--r-- 1 **** **** 100 Jan 6 01:50 null.txt
このファイルから引数をひとつづつ読み込んでxargsに渡すには以下のようにする。-aは引数を収めたファイル、-0は引数の区切り文字をnull文字にするオプション、-nはプログラムに与える引数の数。-rは引数が無い場合にはプログラムを起動しないオプション。-tはプログラム起動前にsterrに起動するコマンドを表示するオプション。ここではechoコマンドを走らせている。
$ xargs -a null.txt -0 -n1 -r -t echo echo echo ... echo echo
本当に100回起動されたか確認。
$ xargs -a null.txt -0 -n1 -r -t echo 2>&1 | grep echo | wc 100 100 700
上の例では、それぞれの引数を1つずつechoコマンドを走らせている。xargsを使って、10並列でプログラムを起動するには、-Pオプションを使って、以下のようにする。最初の例は-P1と同じことである。
$ xargs -a null.txt -0 -n1 -r -P10 -t echo 2>&1 | grep echo | wc 100 100 700 $ xargs -a null.txt -0 -n1 -r -P10 -t echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo ... echo echo
bash組み込みのtimeコマンドを使って、上記2つの場合について速度を比較すると以下のような結果が得られる。並列度10にすることで、xargsの起動から終了までにかかる時間がおよそ10分の一になっていることがわかる。
$ time xargs -a null.txt -0 -n1 -P1 -r -t echo 1>/dev/null 2>/dev/null real 0m9.913s user 0m0.068s sys 0m0.000s $ time xargs -a null.txt -0 -n1 -P10 -r -t echo 1>/dev/null 2>/dev/null real 0m1.132s user 0m0.020s sys 0m0.000s
並列度を変化させることで、xargsの起動から終了までにかかる時間が変化する様子を調べると、以下のようになる。便宜的に並列度を出力している。
$ i=0; while [ 0 ]; do i=`expr $i + 1`; echo $i; time xargs -a null.txt -0 -n1 -P$i -r -t echo 1>/dev/null 2>/dev/null; done 1 real 0m10.036s user 0m0.036s sys 0m0.000s 2 real 0m4.920s user 0m0.008s sys 0m0.000s 3 real 0m3.380s user 0m0.008s sys 0m0.000s 4 real 0m2.551s user 0m0.008s sys 0m0.000s ...
timeコマンドの出力が見づらいので、出力フォーマットを指定する。これにはTIMEFORMAT変数を使う。以下のようになる。
$ i=0; while [ 0 ]; do i=`expr $i + 1`; TIMEFORMAT=$i$'\t%3R\t%3U\t%3S'; time xargs -a null.txt -0 -n1 -P$i -r -t echo 1>/dev/null 2>/dev/null; done 1 9.764 0.020 0.000 2 5.106 0.020 0.004 3 3.376 0.008 0.000 4 2.555 0.028 0.000 5 2.103 0.048 0.000 6 1.775 0.044 0.004 7 1.599 0.056 0.012 8 1.384 0.004 0.008 9 1.292 0.012 0.000 10 1.112 0.000 0.008 11 1.068 0.004 0.004 12 1.013 0.004 0.008 13 0.868 0.008 0.000 14 0.872 0.016 0.000 15 0.795 0.000 0.008 16 0.805 0.008 0.000 17 0.715 0.008 0.000 18 0.707 0.000 0.008 19 0.701 0.008 0.000 20 0.671 0.000 0.008 21 0.691 0.008 0.008 22 0.621 0.012 0.000 23 0.619 0.008 0.000 24 0.605 0.000 0.008 25 0.648 0.032 0.000 26 0.636 0.008 0.000 27 0.566 0.008 0.000 28 0.563 0.008 0.000 29 0.561 0.008 0.000 30 0.510 0.008 0.000 31 0.486 0.012 0.000 32 0.597 0.000 0.008
実際に速度を測定したいプログラムを使ってテストを行う。以下のようにすれば良い。これまでのechoだった部分を"./a.out args"のように書き換える。timeコマンドの結果はstderrに吐き出されるので、null_result.stderrを見ると上のような結果が得られるはずである。
$ i=0; while [ 0 ]; do i=`expr $i + 1`; TIMEFORMAT=$i$'\t%3R\t%3U\t%3S'; time xargs -a null.txt -0 -n1 -P$i -r ./a.out args 1>/dev/null 2>/dev/null; done 1>null_result.stdout 2>null_result.stderr;
結果は以下のようになった。
$ cat null_result.stderr 1 2231.087 745.335 0.760 2 1124.442 738.622 0.748 3 908.133 745.207 0.864 4 763.334 754.663 0.728 5 683.871 744.787 0.648 6 625.984 743.258 0.644 7 602.584 748.495 0.700 8 563.021 740.770 0.596 9 565.600 762.632 0.684 10 544.916 761.512 0.692 11 521.619 751.451 0.604 12 503.836 746.031 0.604 13 506.959 756.531 0.636 14 494.386 757.923 0.740 15 486.060 749.827 0.516 16 490.879 775.648 0.836 17 483.918 769.444 0.712 18 479.095 762.464 0.688 19 476.927 777.509 0.712 20 485.698 796.518 0.788 21 467.004 765.268 0.736 22 463.364 762.036 0.732 23 461.189 761.072 0.556 24 462.172 783.633 0.716 25 444.407 756.083 0.612 26 445.948 759.835 0.652 27 448.918 759.539 0.644 28 451.934 767.004 0.708 29 449.246 768.168 0.732 30 454.193 769.976 0.748 31 446.738 767.532 0.652 32 447.351 786.585 0.792 33 436.138 767.104 0.748 34 433.883 762.136 0.624 35 434.963 767.620 0.768 36 425.329 749.183 0.700 37 426.545 753.271 0.644 38 424.011 750.539 0.596 39 427.766 757.179 0.648 40 439.302 774.432 0.640 41 429.527 760.288 0.616 42 431.858 765.164 0.660 43 420.383 746.231 0.588 44 436.645 769.828 0.692 45 433.256 764.844 0.648 46 430.029 762.780 0.596 47 431.488 763.760 0.632 48 423.816 768.032 0.696 49 423.298 775.164 0.728 50 428.359 770.068 0.888 51 431.649 775.944 0.864 52 435.586 779.437 0.652 53 430.384 770.820 0.756 54 429.638 771.364 1.284 55 432.674 773.464 1.504 56 426.718 775.732 0.768 57 430.906 788.725 0.784 58 426.632 779.757 0.604 59 421.790 774.300 0.748 60 431.381 785.629 0.732 61 419.327 768.572 0.656 62 423.703 774.852 0.804 63 418.136 766.016 0.852 64 421.852 774.152 0.752 65 441.128 808.671 0.800 66 452.106 824.768 0.844 67 438.597 804.358 0.832 68 443.580 814.139 0.792 69 434.589 792.294 0.848 70 420.656 768.780 0.828 71 412.692 755.023 0.708 72 432.970 795.366 0.616 73 424.758 776.497 0.748 74 428.825 787.397 0.760 75 418.555 765.460 0.788 76 416.814 764.396 0.816 77 409.508 749.803 0.692 78 414.816 761.104 0.716 79 419.677 768.580 0.784 80 453.185 835.932 0.700 81 419.973 772.328 0.664 82 419.565 770.188 0.900 83 416.712 764.336 0.832 84 436.502 801.018 0.820 85 408.737 750.091 0.752 86 418.378 764.428 0.924 87 425.620 780.813 0.904 88 423.889 778.313 0.776 89 416.633 761.368 0.680 90 415.428 760.608 0.740 91 431.925 794.134 0.688 92 417.406 768.136 0.592 93 408.748 749.823 0.764 94 412.365 753.531 0.724 95 394.567 751.211 0.604 96 400.393 760.612 0.616
以下のgnuplotスクリプトでグラフを書いてみる。
$ cat null_result.plt #!/usr/bin/gnuplot set terminal png set output 'null_result.png' set grid set ytics nomirror set y2tics set yrange [0:] set y2range [0:] set ylabel "real time, user time [sec]" set y2label "sys time [sec]" set xlabel "parallel process [num.]" plot 'null_result.stderr' using 1:2 title "real",\ '' using 1:3 title "user",\ '' using 1:4 title "sys" axis x1y2 $ gnuplot < null_result.plt
グラフは以下のようになる。