会社案内 (近況 2009/06)
先月 翌月「近況を更新せよ!」と当社顧客よりお叱りを頂いたので、特にネタは無いが 更新してみる。更新が無いのは遊びほうけているからでは無く、いろいろな新 製品を準備してはいるがまだ報告できる状況ではない、ということなのであーる。
というわけで大した話では無いのだが :
当社のあらゆるソフトウェアの管理スクリプト (インストールやバックアップ
用のスクリプト) はなぜか sh ではなく csh で書かれている。これはなぜか
というと、私が学生だった頃に自分で使うために最初に書いたインストールス
クリプトが csh だった、という過去をひきずっているからであり、なぜその
時 csh を選んだかというと普段使っていた shell が csh だったから、とい
うだけ (今は zsh)。つまりロクに考えずに偶然で決まった。
で、いつの間にかそのスクリプトが私や同僚によって拡張され、人手にも渡っ てさらに改変が加えられ、「そろそろ csh で処理するには複雑すぎる規模に なってきたな」と思った頃には、既に sh に移植したくない分量になってしま い、そのまま今日に至っているわけである。
csh の一番嫌な点は、関数を記述できないことだと思う。そのためコードがコ ピー & ペーストの嵐になってしまう。
しかし本日、その問題の解決策を発見した。csh の goto は、飛び先のラベル に変数を使えるのだ (大昔に私が goto を使っていた頃の BASIC では、変数 どころかラベルすら使えず、飛び先はすべて行番号で指定していたのだが。約 30 年前の話である (遠い目))。この機能を使えば関数のようなものを実装で きる。ラベル指定用の変数を用意しておき、goto の直前でこの変数に戻り先 の値をセットしてから goto すれば、戻り先を自由に設定できる。引数を渡し たければ引数用の変数も用意しておけば良い。引数をスタックに積んで渡すと いう実装も可能だが、現段階ではそこまでやる必要はないのでやめておく。
# # main program # set label_for_ret = LABEL1 set arg_for_func = ( "arg1" "arg2" "arg3" ) goto aFunction LABEL1: # do something... set label_for_ret = LABEL2 set arg_for_func = ( "arg4" "arg5" "arg6" ) goto aFunction LABEL2: # do something... exit 0 # # sub program # aFunction: echo $arg_for_func # do something... goto $label_for_ret
これでズバッと解決、と思いきや、while 文中からこの方法で外にいったん出 て戻ってくると、その状態はすでに while 文中にいるものとは見なされず、 while に対応する end に到達した時点でエラー終了してしまう、といったショー もない挙動を示すことが発覚してしまった。出戻り息子なんぞ勘当だ! 状態。 もういい、そういうことならループに while 使うのやめる。全部 goto でや る。
こんな感じでもうしばらく csh のまま行こうと思う。なお perl や ruby を 使って良いならば一瞬で移行するのだが、インストールスクリプトを実行する ためだけに、わざわざそれらの環境をユーザに強いることは避けたい、という のが当社の方針。
ここしばらく、GRAPE-DR や GPU などの SIMD 型ハードウェアアクセラレータ 向け開発環境 Goose というものを密かに開発していた。いまここに書 いてしまったので密かではなくなってしまったが。
Goose は C や Fortran などの高級言語 (注 : ここは笑うところではありま せん) で記述したコードを、コード自体にはできるだけ手を加えずにアクセラ レータ上で実行するための開発環境だ。
まず手始めに、C 言語で記述したコードを GRAPE-DR で実行するためのツール、 goosecc を作った。コードのうち GRAPE-DR 上で実行させたい箇所を ディレクティブ (#pragma) で指定すると、goosecc によって、その部分の記 述から GRAPE-DR 用のマイクロコードが生成される。マイクロコードを GRAPE-DR に転送するためのコード (C で記述) も生成される。さらに、元の C のコードのディレクティブで指定した箇所は、GRAPE-DR を呼び出すための API コールに置き換えられる。
要するにこのツールを使うと、OpenMP の #pragma omp parallel for と同じ ような記述で GRAPE-DR を使えるようになる。OpenMP を知らない読者にはこ れだけでは何だか良く分からないと思うので、以下に具体例を挙げて説明しよ う (偉そうで申し訳ない)。例えば C で書いた force.c というコードの 2 重 for loop に #pragma を付加する。
kawai@tazenda[1]> cat force.c #include <stdio.h> (前略) int main(void) { (中略) #pragma goose parallel for icnt(i) jcnt(j) res (a[i][0..2], p[i]) // icnt は外側の for loop のカウンタに使用する変数を指定する。 // jcnt は内側の for loop のカウンタに使用する変数を指定する。 // res は得たい計算結果を格納する変数を指定する。 for (i = 0; i < ni; i++) { for (j = 0; j < nj; j++) { // ここから double r2 = eps2[i]; for (k = 0; k < 3; k++) { dx[k] = x[j][k] - x[i][k]; } for (k = 0; k < 3; k++) { r2 += dx[k]*dx[k]; } rinv = rsqrt(r2); mf = m[j]*rinv*rinv*rinv; for (k = 0; k < 3; k++) { a[i][k] += mf * dx[k]; } p[i] = - m[j] * rinv; // ここまでがアクセラレータに載る。 } } (後略) }
これを goosecc で処理すると
kawai@tazenda[2]> goosecc --goose-arch gdr -o force -O2 force.c foo.c bar.c -lm
が生成される。これらのコードは残りの C のコードとともに、goosecc に よって通常の C コンパイラへ渡される。
gcc -o force -O2 force.vsmgen.c force_gdr.c foo.c bar.c -lm
C コンパイラによって実行ファイル force が生成され、これを実行すると、 force.c, foo.c, bar.c で記述されたプログラムのうち、#pragma 指定した 2 重 for loop 部分が GRAPE-DR 上で実行される。その他の部分は PC 上で実行 される。
GRAPE-DR (model 1800) を 1 ボード挿した PC で force を実行すると、ボー ド上に搭載されている 2048 個の PE (processor element) によって、2 重 for loop 中の i と j の異なる組み合わせ 2048 通り注 に対する演算が並列実行されることになる。
注: PE すべてを遊ばせること無く稼働させるためには i 方向の並列度が 128 以上必要 (詳細はどっかよそのページで GRAPE-DR チップの内部構成を参照のこと)。
こう書くと C で書いたコードが何でもかんでも GRAPE-DR に載るかのような 気がするが、実際には #pragma は 2 重 for loop にしか付加できない。とは いえ loop になっていない部分はそもそもアルゴリズム自体に並列性が無いの で、GRAPE-DR に載せてもどうせ速くならない。従って実用上はこれで充分だ と思う。たぶん。
goosecc のサポートするオプションは、今のところこんな感じ:
kawai@tazenda[4]>../bin/goosecc --help usage: goosecc [options] inputfile(s)... options: --goose-arch <arch> : architecture type of the hardware accelerator. [gdr] --goose-backannotate : back annotate the assembly code. -o <outputfile> : name of executable file to be generated. [a.out] --verbose : be verbose. -v --moreverbose : output messages for debugging purpose. -vv --help : print this help. -h -Wcc "options" : options passed on to gcc. inputfile(s) : input C source file containing Goose directive. input is taken from stdin if omitted. files without Goose directive are directly passed on to gcc. Note that all options not listed above are implicitly passed on to gcc, in addition to those explicitly specified by '-Wcc'.
ツールドスイス開幕前には α リリースの予定。--goose-arch の引数には今 のところ gdr しか指定できないが、ヴェルタエスパーニャ開幕前には ati と か nvidia とかいう引数を指定できるようになっているはず、、、だといいなぁ。
え? Fortran 版? 要るの? やっぱり? わかりましたよ。作りますよ。ツールド フランスがパリに戻ってくる頃には何とか。まずは Fortran の文法を勉強す るところから始めなくては。がんばれ、俺超がんばれ。