2009年1月28日水曜日

ifortでのベクトル化

今後、なにかと計算規模をスケールアップさせたいんだが、何が問題って計算時間である。今ので一個あたり16時間~20時間かかっていて、扱う状態の数を2倍にすれば、行列要素は4倍になるので単純に考えて4日ぐらいかかるのか。4~5日ですめばいいけど、基本的にあちこち入れ子になったループが存在しまくっているので実際にはもっと時間かかるんじゃねーかと。さすがに処理の高速化をぼちぼち図らないといけないか。

処理を早くするには並列化が基本みたいだ。どんな作業も一人ですべてやるよか何人かで手分けしたほうが早く終わるにきまってる。でも手分けするときに作業内容とかを説明したり、終わったあとに作業内容を統合する必要が出てくる。PCでも同じことで、スケジューリングやらバリア同期をしなあかんのでよっぽど並列処理に向いている部分がないと、並列化させたところでさほど恩恵があるわけではないらしい。(アムダールの法則ってやつか)並列計算に向いてるのは検索、大規模行列の線形代数な演算とからしい。

並列化で最も手っ取り早いというかなんとかつかえそうなのが、ベクトル化とマルチスレッドやろうと思ったので調べてみる。
最近ifortでコンパイルしてるとしょっちゅうdo ループがベクトル化されました っていうメッセージが出てくる。ベクトル化ってスパコンしか関係ない話じゃねーのと思ってたのでなんか不思議に思ってたが、IA-32なCPUでは疑似ベクトル化ができるらしい。
ベクトル化ってのがそもそもなんやねんって話だが、要はレジスタを塊で使って一気に大量の数値を演算しようっていうことみたいだ。


do i=1,10
x(i)=a(i)+b(i)
end do

みたいに演算の順番を変えようがまったく影響ないループだと、aの1~10、bの1~10を一次元配列に格納してその配列の和を計算するのと同等なので、レジスタの集合を配列のように使えば10回計算しなあかんところを一回で済む。10回程度だと大してなんも変わらないけど一万回が一回に化けるとだいぶ違う。地球シミュレータとかSXシリーズとかのスパコンはそれ専用のベクトルレジスタを大量に積んでてそれゆえ行列演算が異様に早いっぽい。(とはいえベクトル型のスパコンを作ってるのはいまやNECのみらしいが)こういう並列化の仕方は、SIMD(Single Instruction Multi Data)というらしい。

実はIA-32なアレにはこのSIMDな処理ができる部分が存在するらしい。CPUのレジスタというと32ビットの汎用レジスタeaxなどなどが使われてるイメージだが、実は128ビットのレジスタxmm0~xmm7というのが存在するそうな。128ビットなので倍精度実数なら2個格納できる。浮動小数点演算は通常、名前も浮動小数点計算ユニットであるFPUとかゆーst(0)~st(7)レジスタを持つところで行うらしいが、xmmレジスタをつかうこともできる。xmmレジスタをまとめて使ってベクトル化したような処理をおこなうための拡張命令がSSE/SSE2/SSE3(SSEはStreaming SIMD Extensionsらしい)
SSEはもともとインテルがつくったのでインテルのコンパイラはこれを使えるのが多い。ifortで出てくるベクトル化しましたってのは実はこのSSE2やらSSE3やらをつかってxmmレジスタで疑似ベクトル化してるということみたいだ。実際、-Sオプションで、アセンブラコードを吐かせてみると、movsd だの %xmm0だのそれつかってるぽい形跡がちらほら。ちなみにmovsdはmovのSSE2バージョンぽい。やはりインテルのコンパイラは頭ええんだな。ところで、DOループ中にprint,read,writeがあるとこのベクトル化ができなかったりする。ベクトル化の詳細レポートがほしい時には-vec_report3とするとよし。

0 コメント: