CUDAプログラミングのやり方は色々あるようだが、一つの方法としてはnvccというコンパイラからcuda用のコードをコンパイルするという方法がある。らしい。基本的に普通のccコマンドみたいな感じ。詳しくはcudatoolkitインストールすると入る /usr/local/cuda/doc/nvcc_2.3.pdf で。
#include <stdio.h> int main() { puts("Hello, world\n"); return 0; }
$ nvcc -o hello hello.cu $ ./hello Hello, world
わーちょうかんたんにGPUプログラミングができたよ!!!
まるでGPUを使っていないのでこれはGPUプログラミングではありません。でもとりあえずnvccが動くことを確認。
意味はないけど一応GPUを使っているハローワールド hello_cuda.cu。
#include <stdio.h> __device__ void dev_strcpy(char *dst, const char *src) { while (*dst++ = *src++); } __global__ void gen_hello(char *buf) { dev_strcpy(buf, "Hello, World!"); } int main(){ char *hello_ptr; char hello_buf[128]; cudaMalloc(&hello_ptr, 128); gen_hello<<<1,1>>>(hello_ptr); cudaMemcpy(hello_buf, hello_ptr, 128, cudaMemcpyDeviceToHost); cudaFree(hello_ptr); puts(hello_buf); return 0; }
cudaMemcpyDeviceToHostは組み込み定数だけどCAMEL_CASEじゃない。CUDAの定数は全部camelCaseなんだろか。
簡単なプログラムを書いてみよう - CUDA Information Siteそのままのプログラム。なにをしてるコードなのか詳細はリンク先参照。
$ nvcc -o hello_cuda hello_cuda.cu $ ./hello_cuda Hello, World!
動いているようです。
上では省いたが実際のコードは
#include <stdio.h> int main() { puts("Hello, world\n"); return 0; } // vim: set ft=cpp:
とvimのmodelineでc++として開くようにしている。cuda.vimとかを設定してもいいんだけど、あっちこっちで書いたりするのでとりあえずこの程度で。本腰据えてでかいの書く気分になったら設定する。
簡単な並列プログラムを書いてみよう - CUDA Information Siteを参考にして並列なFizzBuzzプログラムを書いてみる。
#include <stdio.h> #include <assert.h> #define COUNT 40 enum FizzBuzzEnum { FIZZBUZZ, FIZZ, BUZZ, NONE }; __device__ FizzBuzzEnum to_enum(int num) { return (num%15)==0 ? FIZZBUZZ : (num%3)==0 ? FIZZ : (num%5)==0 ? BUZZ : NONE; } __global__ void dev_fizzbuzz(FizzBuzzEnum *d_fizzbuzz) { int i = threadIdx.x; d_fizzbuzz[i] = to_enum(i+1); } int main() { FizzBuzzEnum h_fizzbuzz[COUNT]; FizzBuzzEnum *d_fizzbuzz; cudaMalloc(&d_fizzbuzz, sizeof(h_fizzbuzz)); dev_fizzbuzz<<<1,COUNT>>>(d_fizzbuzz); cudaMemcpy(h_fizzbuzz, d_fizzbuzz, sizeof(h_fizzbuzz), cudaMemcpyDeviceToHost); for (int i=0;i<COUNT;++i) { switch(h_fizzbuzz[i]) { case FIZZBUZZ: puts("FIZZBUZZ"); break; case FIZZ: puts("FIZZ"); break; case BUZZ: puts("BUZZ"); break; case NONE: printf("%d\n", i+1); break; default: assert(0); } } cudaFree(d_fizzbuzz); return 0; }
$ nvcc -o fizzbuzz01 fizzbuzz01.cu $ ./fizzbuzz01 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz
普通のマルチスレッドプログラミングよりも簡単な感じでマルチスレッドなプログラムが書けるしCUDAはすごいなあ! 詳細はリンク先で。
簡単な並列プログラムを書いてみよう2 - CUDA Information Site
曰く、
s<<<1,COUNT>>>/<<<COUNT,1>>>/;
s/threadIdx/blockIdx/g
でマルチブロックなプログラムになるらしい。CUDAアーキテクチャのデバイスは複数のSM(Streaming Multiprocessor)を持ち、SMはそれぞれ複数のSP(Streaming Processor)を持ち、SMで動く処理単位をブロック、SPで動く処理単位をスレッドと呼ぶらしい。
*1:デバイスのあれこれが新しいせいかhttp://www.yasuoka.mech.keio.ac.jp/cuda/が動かなかった。あれこれいじって動かそうとしたが、Knoppixはカスタマイズが面倒すぎる