Changes between Version 15 and Version 16 of CALプログラミング(1)
- Timestamp:
- Mar 22, 2009 1:08:35 PM (16 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
CALプログラミング(1)
v15 v16 3 3 4 4 = 簡単なプログラム = 5 *一番簡単なテストプログラムが"/usr/local/amdcal/samples/app/hellocal"(CALをインストールしたディレクトリ)にある。これをコピーして、不必要なものを取り除いたバージョンのプログラムが[attachment:CALTEST.tar.gz]にあるので、これを自分のホームディレクトリに展開する。5 一番簡単なテストプログラムが"/usr/local/amdcal/samples/app/hellocal"(CALをインストールしたディレクトリ)にある。これをコピーして、不必要なものを取り除いたバージョンのプログラムが[attachment:CALTEST.tar.gz]にあるので、これを自分のホームディレクトリに展開する。 6 6 7 *makeすることで、"hellocal"というプログラムが作られる。7 makeすることで、"hellocal"というプログラムが作られる。 8 8 9 * まずはこのプログラムを実行してみること。何かキーを押したら終了する。 10 * 実行例 9 まずはこのプログラムを実行してみること。何かキーを押したら終了する。 10 11 実行例 11 12 {{{ 12 13 gpu1[~/CALTEST] ./hellocal … … 24 25 25 26 = hellocalの解説 = 26 *このテストプログラムは、'''入力されたデータに0.5を掛けるという演算'''をGPUでおこなって、結果を得るというプログラムである。27 このテストプログラムは、'''入力されたデータに0.5を掛けるという演算'''をGPUでおこなって、結果を得るというプログラムである。 27 28 28 * 入力データは"hellocal.cpp"の118行の2重ループで値が設定されている変数fdata[]である。102行で、inputResが定義されている。この定義から、inputResが256x256の浮動小数点変数であることがわかる。C言語の配列で書くとfloat array[256][256]になる。116行と117行において、inputResとfdataがマッピングされていることを確認すること。これにより、fdata[]に代入したデータは、GPU上のメモリ(inputRes)に転送されることになる。同様に、出力データが103行で定義されていて、結果を得るために、190行でfdata[](このポインタ変数は2重の役割を果たしている)にマッピングされている事を確認すること。191行からのループにより、GPU上のメモリ(outputRes)から、結果を回収して出力していることを確認すること。 29 入力データは"hellocal.cpp"の118行の2重ループで値が設定されている変数fdata[]である。102行で、inputResが定義されている。この定義から、inputResが256x256の浮動小数点変数であることがわかる。C言語の配列で書くとfloat array[256][256]になる。116行と117行において、inputResとfdataがマッピングされていることを確認すること。これにより、fdata[]に代入したデータは、GPU上のメモリ(inputRes)に転送されることになる。 29 30 30 * 入力データが256x256であることから、計算に利用されるdomainが決定される(176行にて定義)。domainとは、単純には計算に利用されるGPU上のプロセッサの(論理的な)数だと思えばよい。つまりこの場合、論理的には256x256=65536個のプロセッサにより、65536個の入力データへの演算が並列に実行されると考える。この時に並列に実行されるプログラムをCALでの「kernelプログラム」と呼ぶ。31 同様に、出力データが103行で定義されていて、結果を得るために、190行でfdata[](このポインタ変数は2重の役割を果たしている)にマッピングされている事を確認すること。191行からのループにより、GPU上のメモリ(outputRes)から、結果を回収して出力していることを確認すること。 31 32 32 * このプログラムの場合、kernelプログラムは24-33行で定義されている。コピーすると以下の通り(先頭は行番号): 33 入力データが256x256であることから、計算に利用されるdomainが決定される(176行にて定義)。domainとは、単純には計算に利用されるGPU上のプロセッサの(論理的な)数だと思えばよい。つまりこの場合、論理的には256x256=65536個のプロセッサにより、65536個の入力データへの演算が並列に実行されると考える。この時に並列に実行されるプログラムをCALでの「kernelプログラム」と呼ぶ。 34 35 このプログラムの場合、kernelプログラムは24-33行で定義されている。コピーすると以下の通り(先頭は行番号): 33 36 {{{ 34 37 1 il_ps_2_0 … … 42 45 }}} 43 46 44 *'''このkernelプログラムが、個々の論理的なプロセッサで並列に(独立に)実行されるというのが、CALのプログラミングモデルである'''(これ重要)。kernelプログラムが実行されるときには、個々のプロセッサに、一意の番号が割り振られる。この番号は、UNIXなどでの"process id"に相当するものである。CALプログラミングにおいては、この番号はdomainの定義に応じて2次元で表される。つまり、このプログラムの場合には、(0,0)から(255,255)までの65536個の番号が割り振られることになる。47 '''このkernelプログラムが、個々の論理的なプロセッサで並列に(独立に)実行されるというのが、CALのプログラミングモデルである'''(これ重要)。kernelプログラムが実行されるときには、個々のプロセッサに、一意の番号が割り振られる。この番号は、UNIXなどでの"process id"に相当するものである。CALプログラミングにおいては、この番号はdomainの定義に応じて2次元で表される。つまり、このプログラムの場合には、(0,0)から(255,255)までの65536個の番号が割り振られることになる。 45 48 46 *このkernelプログラムにおいて、「入力されたデータに0.5を掛けるという演算」は7行で定義されている。CALのILアセンブラは、"命令 出力変数 入力1 入力2"というフォーマットなので、この行の意味は「r0にcb0[0]を掛けてo0に格納する」ことになる。変数cb0[0]は4行で定義されており、これは大きさが1であるcb0という定数配列を定義するという宣言文である。また、変数o0は3行で定義されており、これはこの変数を出力に利用するという宣言文である。49 このkernelプログラムにおいて、「入力されたデータに0.5を掛けるという演算」は7行で定義されている。CALのILアセンブラは、"命令 出力変数 入力1 入力2"というフォーマットなので、この行の意味は「r0にcb0[0]を掛けてo0に格納する」ことになる。変数cb0[0]は4行で定義されており、これは大きさが1であるcb0という定数配列を定義するという宣言文である。また、変数o0は3行で定義されており、これはこの変数を出力に利用するという宣言文である。 47 50 48 *残ったのは変数r0であり、これが入力データに対応する。6行は、他の変数とは違い宣言文ではなく、「変数r0に入力データを読み込む」という意味を持つ。5行目のような宣言文とセットで利用すると覚えること。51 残ったのは変数r0であり、これが入力データに対応する。6行は、他の変数とは違い宣言文ではなく、「変数r0に入力データを読み込む」という意味を持つ。5行目のような宣言文とセットで利用すると覚えること。 49 52 50 *さて、問題は、256x256で設定された入力データfdata[]のどのデータが読み込まれるのかということである。実はこれは、6行のふたつめの変数である"v0.xyxx"にて指定されている。変数v0とはなんだろうか?これは2行目で宣言されている。この行は、上で説明した「一意の番号」を"v0.xy"に読み込むということを表している。この2行目の宣言により、1番目のプロセッサではv0.x=0, v0.y=0となり、2番目のプロセッサではv0.x=1, v0.y=0、3番目のプロセッサではv0.x=3, v0.y=0...と続き、65536番目のプロセッサではv0.x=255, v0.y=255という「一意の番号」が個々のプロセッサに割りあてられることになる。53 さて、問題は、256x256で設定された入力データfdata[]のどのデータが読み込まれるのかということである。実はこれは、6行のふたつめの変数である"v0.xyxx"にて指定されている。変数v0とはなんだろうか?これは2行目で宣言されている。この行は、上で説明した「一意の番号」を"v0.xy"に読み込むということを表している。この2行目の宣言により、1番目のプロセッサではv0.x=0, v0.y=0となり、2番目のプロセッサではv0.x=1, v0.y=0、3番目のプロセッサではv0.x=3, v0.y=0...と続き、65536番目のプロセッサではv0.x=255, v0.y=255という「一意の番号」が個々のプロセッサに割りあてられることになる。 51 54 52 *よって、6行目の意味を具体的に書くと「変数r0に入力リソース0(2次元)のv0.xy番地を読み込む」という意味となる。C言語で書き直すと、以下のような意味となる:55 よって、6行目の意味を具体的に書くと「変数r0に入力リソース0(2次元)のv0.xy番地を読み込む」という意味となる。C言語で書き直すと、以下のような意味となる: 53 56 {{{ 54 57 r0 = i0[v0.x][v0.y] 55 58 }}} 56 59 57 *なお、入力データがなぜ"i0"という変数になるかというと、6行で"resource(0)"となっているから。この変数"i0"はhellocal.cppの165行にあらわれる。これにより、inputResがkernelプログラムの"i0"という変数に対応することがわかる。60 なお、入力データがなぜ"i0"という変数になるかというと、6行で"resource(0)"となっているから。この変数"i0"はhellocal.cppの165行にあらわれる。これにより、inputResがkernelプログラムの"i0"という変数に対応することがわかる。 58 61 59 *変数o0については、なぜかデータが保存される番地が自動的に決定される。実は、その番地はv0.xyと同じである。よって、6行と7行を合わせて、具体的に書くと以下のようなC言語のプログラムとなる(変数は全てfloat変数。ただしcb0については次の説明に注意すること):62 変数o0については、なぜかデータが保存される番地が自動的に決定される。実は、その番地はv0.xyと同じである。よって、6行と7行を合わせて、具体的に書くと以下のようなC言語のプログラムとなる(変数は全てfloat変数。ただしcb0については次の説明に注意すること): 60 63 {{{ 61 64 o0[v0.x][v0.y] = i0[v0.x][v0.y]*cb0[0] 62 65 }}} 63 66 64 *すなわち、変数cb0[0]に0.5がはいっていれば、最初に書いた「入力されたデータに0.5を掛けるという演算」が実現できることになる。それをふまえた上で、hellocal.cppに戻ると、128-138行と166行において変数cb0[0]が定義、マッピングされていることがわかる。細かい点として、136,137行でcb0[0]に転送される定数データを指定しているが、実はkernelプログラムの4行における定数配列宣言は、4要素のベクトル定数の宣言になる。つまり、4行の宣言は、C言語では"cb0[0][4]"に相当する(CAL上では4要素へのアクセスを"xyzw"のmaskにより指定することに注意)。よって、hellocal.cppにおけるconstPtr[]への値の代入は、cb0[0].xyzwの代入に対応する。具体的には以下のようになる:67 すなわち、変数cb0[0]に0.5がはいっていれば、最初に書いた「入力されたデータに0.5を掛けるという演算」が実現できることになる。それをふまえた上で、hellocal.cppに戻ると、128-138行と166行において変数cb0[0]が定義、マッピングされていることがわかる。細かい点として、136,137行でcb0[0]に転送される定数データを指定しているが、実はkernelプログラムの4行における定数配列宣言は、4要素のベクトル定数の宣言になる。つまり、4行の宣言は、C言語では"cb0[0][4]"に相当する(CAL上では4要素へのアクセスを"xyzw"のmaskにより指定することに注意)。よって、hellocal.cppにおけるconstPtr[]への値の代入は、cb0[0].xyzwの代入に対応する。具体的には以下のようになる: 65 68 {{{ 66 69 constPtr[0] -> cb0[0].x … … 70 73 }}} 71 74 72 *結果として、このプログラムを実行した場合、kernelプログラムのcb0[0]は以下のようになる。75 結果として、このプログラムを実行した場合、kernelプログラムのcb0[0]は以下のようになる。 73 76 {{{ 74 77 cb0[0].x = 0.5, cb0[0].y = 0.0, cb0[0].z = 0.0, cb0[0].w = 0.0 … … 77 80 = CALプログラミング(1)課題 = 78 81 * hellocal.cppを変更して「入力されたデータに0.1を掛けるという演算」を実行するようにせよ。 79 *実行例:82 実行例: 80 83 {{{ 81 84 gpu1[~/CALTEST] ./hellocal [20:26] … … 93 96 94 97 * hellocal.cppを変更して「入力されたデータに0.1を掛けて、さらに10.0を足すという演算」を実行するようにせよ。 95 *実行例:98 実行例: 96 99 {{{ 97 100 gpu1[~/CALTEST] ./hellocal