wiki:CALプログラミング(1)

Version 11 (modified by nakasato, 16 years ago) (diff)

--

リモート接続して利用する方法

  • CALを利用するプログラムは、DISPLAY環境変数を正しく設定しないと動作しない。
      [host0 (GPUあり)] <--- [host1]
    
  • 上の図のような状況で、host0のコンソールにログインして利用する場合は、DISPLAYが自動的に":0.0"(つまりローカル)になるので、問題ない。
  • host1からssh接続でhost0に接続して、GPUを使いたい場合、DISPLAYを":0.0"(host0のX server)にしなくてはならない。sshで接続したままだと、X forwarding機能によりDISPLAYは"localhost:10.0"となるので、そのまま実行するとCALのプログラムは動かない。
  • まずhost0のコンソールにログインして、以下のコマンドを実行しておく。すべての計算機がローカルネットワークにあるなら、セキュリティ上よろしくないが、誰でも"host0:0.0"にwindowを開くことを許可する設定。これは起動の度に一度おこなえばよい。コンソールはログインしたまま放置する(ほうがいい?(検討))。
    xhost +
    
  • host1からhost0にsshでloginしたあと、DISPLAYを以下のようにする。
    export DISPLAY=:0.0
    
  • 以上がリモートからCALプログラミングするための前準備。

簡単なプログラム

  • 一番簡単なテストプログラムが"/usr/local/amdcal/samples/app/hellocal"(CALをインストールしたディレクトリ)にある。これをコピーして、不必要なものを取り除いたバージョンのプログラムが添付したCALTEST.tar.gzにあるので、これを自分のホームディレクトリに展開する。
  • makeすることで、"hellocal"というプログラムが作られる。
  • まずはこのプログラムを実行してみること。何かキーを押したら終了する。
    • 実行例
      gpu1[~/CALTEST] ./hellocal                                                                                    
      0.000000 0.500000 1.000000 1.500000 2.000000 2.500000 3.000000 3.500000
      128.000000 128.500000 129.000000 129.500000 130.000000 130.500000 131.000000 131.500000
      256.000000 256.500000 257.000000 257.500000 258.000000 258.500000 259.000000 259.500000
      384.000000 384.500000 385.000000 385.500000 386.000000 386.500000 387.000000 387.500000
      512.000000 512.500000 513.000000 513.500000 514.000000 514.500000 515.000000 515.500000
      640.000000 640.500000 641.000000 641.500000 642.000000 642.500000 643.000000 643.500000
      768.000000 768.500000 769.000000 769.500000 770.000000 770.500000 771.000000 771.500000
      896.000000 896.500000 897.000000 897.500000 898.000000 898.500000 899.000000 899.500000
      
      Press enter to exit...
      

hellocalの解説

  • このテストプログラムは、入力されたデータに0.5を掛けるという演算をGPUでおこなって、結果を得るというプログラムである。
  • 入力データは"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)から、結果を回収して出力していることを確認すること。
  • 入力データが256x256であることから、計算に利用されるdomainが決定される(176行にて定義)。domainとは、単純には計算に利用されるGPU上のプロセッサの(論理的な)数だと思えばよい。つまりこの場合、論理的には256x256=65536個のプロセッサにより、65536個の入力データへの演算が並列に実行されると考える。この時に並列に実行されるプログラムをCALでの「kernelプログラム」と呼ぶ。
  • このプログラムの場合、kernelプログラムは24-33行で定義されている。コピーすると以下の通り(先頭は行番号):
     1 il_ps_2_0
     2 dcl_input_interp(linear) v0.xy
     3 dcl_output_generic o0
     4 dcl_cb cb0[1]
     5 dcl_resource_id(0)_type(2d,unnorm)_fmtx(float)_fmty(float)_fmtz(float)_fmtw(float)
     6 sample_resource(0)_sampler(0) r0, v0.xyxx
     7 mul o0, r0, cb0[0]
     8 ret_dyn
    
  • このkernelプログラムが、個々の論理的なプロセッサで並列に(独立に)実行されるというのが、CALのプログラミングモデルである(これ重要)。kernelプログラムが実行されるときには、個々のプロセッサに、一意の番号が割り振られる。この番号は、UNIXなどでの"process id"に相当するものである。CALプログラミングにおいては、この番号はdomainの定義に応じて2次元で表される。つまり、このプログラムの場合には、(0,0)から(255,255)までの65536個の番号が割り振られることになる。
  • このkernelプログラムにおいて、「入力されたデータに0.5を掛けるという演算」は7行で定義されている。CALのILアセンブラは、"命令 出力変数 入力1 入力2"というフォーマットなので、この行の意味は「r0にcb0[0]を掛けてo0に格納する」ことになる。変数cb0[0]は4行で定義されており、これは大きさが1であるcb0という定数配列を定義するという宣言文である。また、変数o0は3行で定義されており、これはこの変数を出力に利用するという宣言文である。
  • 残ったのは変数r0であり、これが入力データに対応する。6行は、他の変数とは違い宣言文ではなく、「変数r0に入力データを読み込む」という意味を持つ。5行目のような宣言文とセットで利用すると覚えること。
  • さて、問題は、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という「一意の番号」が個々のプロセッサに割りあてられることになる。
  • よって、6行目の意味を具体的に書くと「変数r0に入力リソース0(2次元)のv0.xy番地を読み込む」という意味となる。C言語で書き直すと、以下のような意味となる:
     r0 = i0[v0.x][v0.y]
    
  • なお、入力データがなぜ"i0"という変数になるかというと、6行で"resource(0)"となっているから。この変数"i0"はhellocal.cppの165行にあらわれる。これにより、inputResがkernelプログラムの"i0"という変数に対応することがわかる。
  • 変数o0については、なぜかデータが保存される番地が自動的に決定される。実は、その番地はv0.xyと同じである。よって、6行と7行を合わせて、具体的に書くと以下のようなC言語のプログラムとなる(変数は全てfloat変数。ただしcb0については次の説明に注意すること):
     o0[v0.x][v0.y] = i0[v0.x][v0.y]*cb0[0]
    
  • すなわち、変数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の代入に対応する。具体的には以下のようになる:
     constPtr[0] -> cb0[0].x
     constPtr[1] -> cb0[0].y
     constPtr[2] -> cb0[0].z
     constPtr[3] -> cb0[0].w
    
  • 結果として、このプログラムを実行した場合、kernelプログラムのcb0[0]は以下のようになる。
     cb0[0].x = 0.5, cb0[0].y = 0.0, cb0[0].z = 0.0, cb0[0].w = 0.0
    

CALプログラミング(1)課題

  • hellocal.cppを変更して「入力されたデータに0.1を掛けるという演算」を実行するようにせよ。
    • 実行例:
      gpu1[~/CALTEST] ./hellocal                                                                              
      10.000000 11.000000 12.000000 13.000000 14.000000 15.000000 16.000000 17.000000
      266.000000 267.000000 268.000000 269.000000 270.000000 271.000000 272.000000 273.000000
      522.000000 523.000000 524.000000 525.000000 526.000000 527.000000 528.000000 529.000000
      778.000000 779.000000 780.000000 781.000000 782.000000 783.000000 784.000000 785.000000
      1034.000000 1035.000000 1036.000000 1037.000000 1038.000000 1039.000000 1040.000000 1041.000000
      1290.000000 1291.000000 1292.000000 1293.000000 1294.000000 1295.000000 1296.000000 1297.000000
      1546.000000 1547.000000 1548.000000 1549.000000 1550.000000 1551.000000 1552.000000 1553.000000
      1802.000000 1803.000000 1804.000000 1805.000000 1806.000000 1807.000000 1808.000000 1809.000000
      
      Press enter to exit...
      
  • hellocal.cppを変更して「入力されたデータに0.1を掛けて、さらに10.0を足すという演算」を実行するようにせよ。
    • 実行例:
      gpu1[~/CALTEST] ./hellocal                                                     
      10.000000 10.100000 10.200000 10.300000 10.400000 10.500000 10.600000 10.700000
      35.599998 35.700001 35.799999 35.900002 36.000000 36.100002 36.200001 36.299999
      61.200001 61.299999 61.400002 61.500000 61.600002 61.700001 61.799999 61.900002
      86.800003 86.900002 87.000000 87.099998 87.200005 87.300003 87.400002 87.500000
      112.400002 112.500000 112.599998 112.700005 112.800003 112.900002 113.000000 113.099998
      138.000000 138.100006 138.199997 138.300003 138.400009 138.500000 138.600006 138.699997
      163.600006 163.699997 163.800003 163.900009 164.000000 164.100006 164.199997 164.300003
      189.199997 189.300003 189.400009 189.500000 189.600006 189.699997 189.800003 189.900009
       
      Press enter to exit...
      

Attachments (1)

Download all attachments as: .zip