//このページが表示される方は、URLから「action=SOURCE&」を削除してみてください [[R備忘録 - 記事一覧]] !!!R(R言語)で並列処理 - Atlasを使う *投稿者: みゅ *カテゴリ: なし *優先度: 普通 *状態: 完了 *日時: 2009年01月15日 19時48分27秒 //{{bugstate}} !!内容 Rで並列処理を行うためのtipsを書いていこうと思います.「snow」とか「multicore」とかいったパッケージについても、そのうち触れてみたいと思います. まずは「[Atlas|http://math-atlas.sourceforge.net/]」.[Atlas|http://math-atlas.sourceforge.net/]はAutomatically Tuned Linear Algebra Softwareの略です. みゅ自身もよくわかっていませんが、 *行列演算をCPUのキャッシュを効率よく使えるように分割して実行 *使えるCPUが2個以上の場合はスレッド化して複数のCPUを使って行列演算を行う. というものです. 基本的に、大きな行列の演算に対して、すばらしいパフォーマンスを発揮してくれます. *経験上、数ギガとかある行列の演算で、10時間以上かかっていた計算が、Atlasを使うことで数分で終わりました. *一方、小さなサイズの行列演算に関しては、スレッド化する分だけほんの少しパフォーマンスは落ちます. !リンク *[数値計算マニュアル:線型代数 (FAQ)|http://www.mlab.ice.uec.ac.jp/~ej-sib/numerical/numerical_lapack_faq.html] !メモ *ATLASをインストールしてlapackを使うためには、先にちゃんとlapackをインストールというかビルドしなければならない模様.ちゃんと読めば書いてあった・・・ ../ATLAS/configure -b 32 -t 2 -Fa alg -fPIC --with-netlib-lapack=../lapack-3.2.1/lapack_LINUX.a *lapackインストール **make.incに以下が必要 OPTS = -fPIC NOOPT = -fPIC *http://www.netlib.org/lapack/lawn81/node1.html When linking, remember that order is important. So, if you want uniprocessor libs, your link line would contain IN THIS ORDER: -LLIBDIR -llapack -lcblas -lf77blas -latlas And if you want to utilize an SMP version, it would be: -LLIBDIR -llapack -lptcblas -lptf77blas -latlas !!環境 いろいろな条件でパフォーマンスを計測できるように、仮想化環境(vmware)を使用します. *ホストOSはWINDOWS XP **CPU Athlon x2 Dual Core BE-2400 2.3GHz **メモリ 4Gバイト(ただしOSで認識できるのは3.37Gバイト) *ゲストOSはGentooLinux **amd64でカーネルを構築 => 変更 ***amd64だと、時間が正確に測れないので、x86バージョンに **パフォーマンスの計測のみなのでとりあえずメモリは512Mバイトにしておきます. **また、2CPUの場合と1CPUの場合の違いを見るために、1CPUのゲストと2CPUを使うゲスト、2種類を用意します. こんな感じです. Rをインストールする前に、blasとlapackをインストールしておきます.Gentooだとportageにあるのでらくちん. emerge -v lapack これで、blasとlapackがインストールされます. Atlasを入れる前と入れた後での違いを見るために、Atlasはここではインストールしません. !!Rのインストール *Rをインストールします.「R-2.8.1.tar.gz」をダウンロードしてきて、解凍. $ ./configure --with-blas --with-lapack --enable-R-shlib 「--enable-R-shlib」オプションは計算速度とは関係ないのですが、あとで必要になるかもしれないので、とりあえず入れておきます.これは「libR.so」という共有ライブラリを作成するためのオプションです. コンフィギュアが終わると R is now configured for x86_64-unknown-linux-gnu Source directory: . Installation directory: /usr/local C compiler: gcc -std=gnu99 -g -O2 Fortran 77 compiler: gfortran -g -O2 C++ compiler: g++ -g -O2 Fortran 90/95 compiler: gfortran -g -O2 Obj-C compiler: Interfaces supported: X11 External libraries: readline, BLAS(generic), LAPACK(generic) Additional capabilities: iconv, MBCS, NLS Options enabled: shared R library, R profiling Recommended packages: yes configure: WARNING: you cannot build DVI versions of the R manuals configure: WARNING: you cannot build PDF versions of the R manuals configure: WARNING: I could not determine a browser configure: WARNING: I could not determine a PDF viewer と出力されて、BLASとLAPACKがライブラリとして使用されることがわかります.ただしまだatlasではありません. *make make LANG=C LC_ALL=C make check *インストール.rootになって make install !!1CPUと2CPUの比較 *注意! : まだ、AtlasをリンクしたRではありません. *1プロセスでは1個のCPUしか使えませんから、1CPUでも2CPUでも、パフォーマンスは同じはずです.ホストOSや、ほかのゲストOSで負荷がかかっていない状態で実行します. *Rjpにもでてくるtest2関数 test2 <- function ( n=500, iter=10, stime=5 ) { A<-array(rnorm(n^2), dim=c(n,n)) B<-array(rnorm(n^2), dim=c(n,n)) C<-array(rnorm(n^2), dim=c(n,n)) D<-array(rnorm(n^2), dim=c(n,n)) BA <- B%*%A Sys.sleep(stime) old_time <- Sys.time() print(old_time) for( i in 1:iter )print(system.time(A%*%solve(t(BA)%*%BA+C)%*%BA%*%D )) Sys.sleep(stime) cur_time <- Sys.time() print(cur_time) print( cur_time - old_time - stime ) NULL } *これで、比較できると思ったのですが、思わぬ落とし穴が.このamd64 + WindowsXPが影響しているかどうか不明ですが、2CPUの場合負荷をかけた計算ではclockが異常に遅れます.そのため体感では1CPUでも2CPUでも計算にかかっている時間は変わらないのですが、表示される計算時間が2CPUでは、短くなってしまいます.つまり2CPUの方が、早く計算できていることに.負荷をかけるとclockが遅れるので、こうなってしまうのですが・・・ *と、いうことでホストOSは同じで *ゲストOSにGentoo LinuxのX86版にしてみたところ、clockの遅れはほとんどでなくなったのでこちらで検証を行うことにしました. *1CPUの場合 > test2(stime=0) [1] "2009-01-17 14:09:46 JST" user system elapsed 2.190 0.060 2.253 user system elapsed 2.170 0.060 2.249 user system elapsed 2.230 0.030 2.272 user system elapsed 2.190 0.040 2.258 user system elapsed 2.220 0.040 2.257 user system elapsed 2.160 0.050 2.228 user system elapsed 2.27 0.03 2.33 user system elapsed 2.170 0.080 2.261 user system elapsed 2.200 0.050 2.266 user system elapsed 2.14 0.11 2.26 [1] "2009-01-17 14:10:09 JST" Time difference of 22.85281 secs で、約23秒. *2CPUの場合 > test2(stime=0) [1] "2009-01-17 14:07:11 JST" user system elapsed 2.210 0.080 2.289 user system elapsed 2.250 0.050 2.306 user system elapsed 2.200 0.110 2.305 user system elapsed 2.260 0.040 2.297 user system elapsed 2.220 0.100 2.317 user system elapsed 2.210 0.120 2.329 user system elapsed 2.260 0.060 2.313 user system elapsed 2.270 0.050 2.321 user system elapsed 2.160 0.120 2.283 user system elapsed 2.290 0.050 2.341 [1] "2009-01-17 14:07:34 JST" Time difference of 23.34357 secs で、約23秒をちょっと超えるくらい. *仮想化環境で実行した場合ゲストOSのクライアントが2CPUを使うオーバーヘッドがあるんでしょうか.2CPUを割り当てたゲストOSの実行速度が若干遅くなる感じがします. *ですが、その分を考慮に入れても約24秒、ほとんど一緒です. !!1CPUと2CPUの比較、プロセスを同時に2個走らせた場合 *一方、プロセスを同時に2個走らせた場合は、1CPUは同時に使えるCPUが1個しかありませんから、2CPUよりも時間がかかるはずです. *1CPUの場合 **プロセス1 > test2(stime=0) [1] "2009-01-17 14:15:22 JST" user system elapsed 2.12 0.09 4.30 user system elapsed 2.170 0.060 4.447 user system elapsed 2.19 0.10 4.51 user system elapsed 2.160 0.070 4.521 user system elapsed 2.150 0.080 4.458 user system elapsed 2.180 0.050 4.421 user system elapsed 2.200 0.040 4.508 user system elapsed 2.120 0.080 4.513 user system elapsed 2.150 0.100 4.464 user system elapsed 2.200 0.080 4.457 [1] "2009-01-17 14:16:07 JST" Time difference of 45.01486 secs **プロセス2 > test2(stime=0) [1] "2009-01-17 14:15:24 JST" user system elapsed 2.210 0.070 4.532 user system elapsed 2.200 0.050 4.576 user system elapsed 2.210 0.030 4.492 user system elapsed 2.20 0.06 4.59 user system elapsed 2.180 0.060 4.506 user system elapsed 2.230 0.080 4.581 user system elapsed 2.170 0.070 4.472 user system elapsed 2.160 0.100 4.572 user system elapsed 2.170 0.040 4.526 user system elapsed 2.170 0.060 3.155 [1] "2009-01-17 14:16:09 JST" Time difference of 44.4571 secs と、このように、2倍の時間かかっています. *2CPUの場合 **プロセス1 > test2(stime=0) [1] "2009-01-17 14:14:05 JST" user system elapsed 2.440 0.090 2.584 user system elapsed 2.470 0.080 2.555 user system elapsed 2.440 0.090 2.535 user system elapsed 2.470 0.060 2.543 user system elapsed 2.410 0.090 2.504 user system elapsed 2.470 0.060 2.535 user system elapsed 2.430 0.100 2.526 user system elapsed 2.42 0.10 2.53 user system elapsed 2.450 0.070 2.521 user system elapsed 2.330 0.120 2.453 [1] "2009-01-17 14:14:31 JST" Time difference of 25.53348 secs **プロセス2 > test2(stime=0) [1] "2009-01-17 14:14:06 JST" user system elapsed 2.41 0.09 2.50 user system elapsed 2.320 0.140 2.453 user system elapsed 2.460 0.060 2.516 user system elapsed 2.490 0.050 2.535 user system elapsed 2.460 0.080 2.541 user system elapsed 2.38 0.10 2.48 user system elapsed 2.420 0.100 2.522 user system elapsed 2.44 0.08 2.52 user system elapsed 2.410 0.110 2.533 user system elapsed 2.320 0.120 2.445 [1] "2009-01-17 14:14:32 JST" Time difference of 25.27888 secs と、このように、若干時間は延びたものの、ほぼ同じパフォーマンスを出すことができます. *CPU(コア)が2個あっても、データのとおるパイプラインは共通ですし、1プロセスとまったく同様のパフォーマンスを出すことができるわけではありません.でも、1CPUに比べると、この計算に関してはパフォーマンスの落ち込みはほとんど無いことがわかります. !!AtlasをリンクしたRをインストールする. *Atlasをインストールする前の環境をとっておくために、1CPUバージョン2CPUバージョン両方とも仮想化環境をコピーしました.つまりこんな感じ ,CPU数,1,2 ,Atlasなし,, ,Atlasあり,, *Rをインストールする前に、まずはインストールしてあるRをアンインストール !Atlasをインストール emerge -v lapack-atlas !1CPU *コンフィグ ./configure --disable-R-profiling \ --with-blas='-L/usr/lib/blas/atlas -lblas -L/usr/lib -latlas' \ --with-lapack="-L/usr/lib/blas/atlas -llapack -L/usr/lib -latlas" \ --enable-R-shlib *コンフィグの結果 R is now configured for i686-pc-linux-gnu Source directory: . Installation directory: /usr/local C compiler: gcc -std=gnu99 -g -O2 Fortran 77 compiler: gfortran -g -O2 C++ compiler: g++ -g -O2 Fortran 90/95 compiler: gfortran -g -O2 Obj-C compiler: Interfaces supported: X11, tcltk External libraries: readline, BLAS(ATLAS), LAPACK(generic) Additional capabilities: PNG, JPEG, TIFF, iconv, MBCS, NLS Options enabled: shared R library Recommended packages: yes configure: WARNING: you cannot build DVI versions of the R manuals configure: WARNING: you cannot build PDF versions of the R manuals configure: WARNING: I could not determine a browser configure: WARNING: I could not determine a PDF viewer *LAPACKがATLASになってません・・・が、気にせず続行・・・ **もしかして↓こうかも・・・?(ためしてません) ./configure --disable-R-profiling \ --with-blas='-L/usr/lib/blas/atlas -lblas -L/usr/lib -latlas' \ --with-lapack="-L/usr/lib/>>>lapack<< test2(stime=0) [1] "2009-01-17 17:27:40 JST" user system elapsed 0.430 0.090 0.537 user system elapsed 0.440 0.090 0.535 user system elapsed 0.420 0.110 0.532 user system elapsed 0.430 0.100 0.527 user system elapsed 0.450 0.090 0.538 user system elapsed 0.400 0.130 0.541 user system elapsed 0.490 0.080 0.568 user system elapsed 0.470 0.070 0.543 user system elapsed 0.470 0.070 0.539 user system elapsed 0.490 0.050 0.546 [1] "2009-01-17 17:27:46 JST" Time difference of 5.996144 secs このように、このケースでは約4倍早く計算することができるように、なりました.もっと大きな行列だと、もっと効果があると思います. *2CPUの場合 > test2(iter=10, stime=0) [1] "2009-01-17 19:06:55 JST" user system elapsed 0.440 0.070 0.487 user system elapsed 0.420 0.090 0.482 user system elapsed 0.400 0.090 0.477 user system elapsed 0.450 0.090 0.494 user system elapsed 0.350 0.090 0.445 user system elapsed 0.410 0.090 0.449 user system elapsed 0.380 0.080 0.461 user system elapsed 0.430 0.080 0.507 user system elapsed 0.280 0.090 0.379 user system elapsed 0.32 0.14 0.46 [1] "2009-01-17 19:07:00 JST" Time difference of 4.850254 secs このくらいの計算だと1CPUでも2CPUでもほとんどパフォーマンスは変わらないですね.気持ち早くなっていますが. !!Atlas導入の効果を見る *ということで、その効果を測るために、test2関数の引数を「n=1000」として、計算してみます. !2CPUで、Atlas導入前 **Atlas入れてないので、1CPUと計算速度は同じと思ってください. > test2(n=1000, stime=0) [1] "2009-01-17 19:07:52 JST" user system elapsed 19.600 0.450 21.123 user system elapsed 19.910 0.340 21.151 user system elapsed 19.700 0.470 21.074 user system elapsed 20.040 0.230 21.126 user system elapsed 19.930 0.410 21.101 user system elapsed 19.880 0.340 21.005 user system elapsed 19.570 0.470 20.994 user system elapsed 19.640 0.430 20.906 user system elapsed 19.51 0.32 20.72 user system elapsed 19.88 0.39 21.00 [1] "2009-01-17 19:11:22 JST" Time difference of 3.508183 mins こうなります.一回の計算に20秒以上.で「top」コマンドの表示を見ていると、RでのCPU使用率は100%.で、100%を超えません. !1CPU + Atlas > test2(n=1000, stime=0) [1] "2009-01-18 15:28:43 JST" user system elapsed 3.15 0.30 3.45 user system elapsed 3.11 0.32 3.43 user system elapsed 3.13 0.32 3.45 user system elapsed 3.09 0.32 3.41 user system elapsed 3.07 0.35 3.42 user system elapsed 3.22 0.26 3.50 user system elapsed 3.16 0.27 3.43 user system elapsed 3.08 0.35 3.43 user system elapsed 3.20 0.26 3.46 user system elapsed 3.15 0.26 3.41 [1] "2009-01-18 15:29:18 JST" Time difference of 34.67962 secs Atlasを導入することで、かなり早くなっています. *2CPU+Atlasなら、スレッド化して分割で計算してくれますから、CPU使用率は100%を超えるはず.そしてパフォーマンスも良いはず. !2CPUで、Atlas導入後 > test2(n=1000, stime=0) [1] "2009-01-17 19:17:04 JST" user system elapsed 3.18 0.40 2.45 user system elapsed 3.020 0.420 2.284 user system elapsed 3.110 0.410 2.437 user system elapsed 3.230 0.340 2.409 user system elapsed 3.170 0.450 2.374 user system elapsed 3.060 0.360 2.388 user system elapsed 3.080 0.390 2.326 user system elapsed 3.170 0.320 2.392 user system elapsed 2.970 0.390 2.328 user system elapsed 3.170 0.360 2.422 [1] "2009-01-17 19:17:28 JST" Time difference of 24.15007 secs どうですか、奥様!! *CPU使用率も150%くらいまで上がって、パフォーマンスも劇速. **2CPUでスレッド化しても、パイプラインとか共通なので、200%にはなりませんよね. *ちょうど、パフォーマンスも1.5倍くらいですか. !!結果とか感想とか *ということで、Atlasを使う計算であれば、CPUが2個以上乗っていれば、行列演算を効率よく分割して、スレッド化して計算してくれるので、並列処理していると、言っていいでしょう. *スレッド化するだけでなく、CPUのキャッシュをうまく使うような行列演算に分割してくれるので???1CPUだけでもAtlasの効果はあります. *仮想化環境も使い方によっては最高! *さて次はなにしよう・・・multicoreかな・・・ !!コメント //{{comment}}