CUDAプログラミングを始めて、
ほぼ最初に混乱するのがこの2つです。
__device____global__
「どっちもGPUで動くんでしょ?」
という理解のまま進むと、確実に詰みます。
この記事では、
CUDA初心者が最初に理解すべき __device__ と __global__ の違い を
実体験ベースで解説します。
CUDAプログラミングの前提
CUDAでは、コードは大きく2つの場所で実行されます。
- CPU(ホスト)
- GPU(デバイス)
そしてCUDAでは、
「どこで実行される関数か」を 修飾子 で明示します。
global とは何か
__global__ は、
CPUから呼び出され、GPU上で実行される関数です。
いわゆる カーネル関数 です。
__global__ void add(int* a, int* b, int* c) {
int idx = threadIdx.x;
c[idx] = a[idx] + b[idx];
}
特徴
- CPU(ホスト)から呼び出す
- GPU(デバイス)で実行される
- 戻り値は
void固定 - <<< >>> という特殊な呼び出し構文を使う
add<<<1, 256>>>(a, b, c);
device とは何か
__device__ は、
GPU上でのみ呼び出される関数です。
__device__ int square(int x) {
return x * x;
}
特徴
- GPU上からのみ呼び出せる
- CPUから直接呼ぶことはできない
- 通常の関数のように戻り値を持てる
global と device の関係
重要なのはここです。
__global__ void kernel() {
int x = square(4);
}
-
__global__→ GPUで実行される入口 -
__device__→ GPU内部で使う部品関数
という関係になります。
よくある勘違い
勘違い1:device を CPU から呼べる
square(4); // ❌ コンパイルエラー
__device__ 関数は
CPUから直接呼べません。
勘違い2:global を普通の関数みたいに呼ぶ
kernel(); // ❌ ダメ
__global__ 関数は必ず、
kernel<<<grid, block>>>();
という形で呼ぶ必要があります。
なぜ分かりにくいのか
CUDA初心者が混乱する理由は単純です。
- 同じC/C++の文法に見える
- でも実行場所が全く違う
- エラーメッセージが分かりにくい
特に、
「なぜコンパイルは通るのに動かないのか」
という状況に陥りがちです。
実際にハマったポイント
初心者時代にやらかしがちな例です。
-
__device__関数を CPU から呼ぼうとする - GPUメモリとCPUメモリの区別が曖昧
- どのコードがGPUで動いているか分からなくなる
この段階で、
「CUDA難しすぎる…」
となる人が多いです。
最初はこう覚えると楽
シンプルに覚えるならこれです。
-
__global__
→ GPUで動くメイン処理(入口) -
__device__
→ GPU内で使う補助関数
これだけ理解できれば、
最初の壁は越えられます。
まとめ
- CUDAでは実行場所が明確に分かれている
-
__global__は CPU → GPU の入口 -
__device__は GPU 内専用関数 - 呼び出し方を間違えると即詰む
CUDAは最初こそ取っつきにくいですが、
この2つを理解できると一気に視界が開けます。
CUDAを触り始めた人の
「最初のつまずきポイント」を
少しでも減らせれば幸いです。