LoginSignup
5
5

More than 5 years have passed since last update.

WebCLでライフゲームしてみる

Posted at

この記事は CUDA & OpenCL Advent Calendar 2014 の 6 日目です。

という煽りを見たのでWebCLを触ってみました

http://webcl.nokiaresearch.com/
webcl.nokiaresearch.com screenshot
とあるので、その通りFirefox35をインストールしました。Firefox37 Nightlyはダメでした。

webcl firefox addon screenshot
こんなが入ります

webcl.nokiaresearch.com screenshot
準備できました

とりあえずWebCL Tutorialというチュートリアルのコードを写経して雰囲気を掴んでいきます。

前日_likrさんがWebCLプログラミング入門というのを書かれているので解説は省きます。

OpenCL C言語についてはOpenCL 1.1 Reference Pagesを覗きながら書きました

また、OpenCLもGPGPUも初めてでしたので、ローカルワークサイズとグローバルワークサイズについてはワークアイテム・ワークグループ・次元数についてという記事を眺めてました

こうしてできたのがこちらになります

この実装では

globalWS = [width, height]
cmdQueue.enqueueNDRangeKernel(kernel, globalWS.length, null, globalWS)

というように次元数2でローカルワークアイテムを使わずグローバルワークアイテムのみをつかう実装にしました。

ところが、これで2000x2000のライフゲームを100ステップ動かしてみると、GPUよりCPUを使った方が早いという結果になりました

カーネルからグローバルメモリにアクセスしているのが原因のようです。

kernel void cell(global char* vectorIn1,
                 global char* vectorOut,
                 uint   vectorWidth){
  int x = get_global_id(0);
  int y = get_global_id(1);
  int width  = get_global_size(0);
  int height = get_global_size(1);
  int index = width * y + x;
  int xplus  = (x+1 <= width-1  ? x+1 : 0);
  int yplus  = (y+1 <= height-1 ? y+1 : 0);
  int xminus = (0   <= x-1      ? x-1 : width-1);
  int yminus = (0   <= y-1      ? y-1 : height-1);
  int mylife = vectorIn1[width * y + x] > 0;
  //グローバルメモリに9回アクセスしている
  int nears[8] = {
    vectorIn1[width * yplus  + xminus],
    vectorIn1[width * yplus  + x     ],
    vectorIn1[width * yplus  + xplus ],
    vectorIn1[width * y      + xminus],
 // vectorIn1[width * y      + x     ],
    vectorIn1[width * y      + xplus ],
    vectorIn1[width * yminus + xminus],
    vectorIn1[width * yminus + x     ],
    vectorIn1[width * yminus + xplus ]
  };
  int lives = 0;
  for(int i=0; i<8; i++){
    if(nears[i]) lives++;
  }
  if(mylife){
    if(lives == 0 || lives == 1){
      vectorOut[index] = 0;
    }else if(lives == 2 || lives == 3){
      vectorOut[index] = 1;
    }else{
      vectorOut[index] = 0;
    }
  }else{
    if(lives == 3){
      vectorOut[index] = 1;
    }else{
      vectorOut[index] = 0;
    }
  }
}

OpenCLではメモリが階層化されており、アクセスの高速な順に次のようになっています

  1. プライベートメモリ
  2. ローカルメモリ
  3. コンスタントメモリ
  4. グローバルメモリ
  5. ホストメモリ

グローバルメモリはカーネルが直接アクセスできるメモリの中で一番遅いようです

そこでローカルメモリを利用したプログラムを書こうと思ったのですが・・・

というように普段ブラウザで富豪プログラミングしてる私にはつらい領域に達してきたので今回はここまでです

ローカルメモリを使った実装はまた今度挑戦します

Advent Calendarの次の担当は@ykstさんです。

5
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5