CUDA Kernel内でのポインタの指しているメモリ判定
消えたCUDA関連の旧ブログ記事を復元するひとり Advent Calendar 2024の記事です。
CUDAではポインタを引数にとってそれがどの記憶領域を指しているかを返す関数があります.
それがこの4つです.
- __isConstant
- __isGlobal
- __isLocal
- __isShared
#include <iostream>
__constant__ float c;
template <class T>
__device__ void print_memory(const T* const ptr, const char* name) {
if (__isConstant(ptr)) {
printf("%7s [%p] : constant\n", name, ptr);
} else if (__isGlobal(ptr)) {
printf("%7s [%p] : global\n", name, ptr);
} else if (__isLocal(ptr)) {
printf("%7s [%p] : local\n", name, ptr);
} else if (__isShared(ptr)) {
printf("%7s [%p] : shared\n", name, ptr);
} else {
printf("%7s [%p] : else\n", name, ptr);
}
}
__global__ void kernel(const float* const g, const float* const h) {
__shared__ float s;
float r;
print_memory(g, "g");
print_memory(h, "h");
print_memory(&s, "s");
print_memory(&r, "r");
print_memory(&c, "c");
print_memory(reinterpret_cast<void*>(0), "null");
}
int main() {
float *g, *h;
cudaMalloc(&g, sizeof(float));
cudaMallocHost(&h, sizeof(float));
kernel<<<1, 1>>>(g, h);
cudaDeviceSynchronize();
}
g [0x7f9adb400000] : global h [0x7f9adb600000] : global s [0x7f9b04000000] : shared r [0x7f9b06fffce0] : local c [0x7f9ae0800000] : constant null [(nil)] : globalnullptrはGlobalメモリ扱いなんですね.
当然コンパイル時には判別しようがないことなので実行時に判定するのですが,PTXではどうなっているかと言うと,それぞれ
- isspacep.const
- isspacep.global
- isspacep.local
- isspacep.shared
しかしアドレスを見れば空間の判定なんてできそうな気がしますよね?
そんなことを思いSASSを見てみたところ,適当にアドレスにマスクをかけて判定する系のコードに変わっていました.
流石にハードウェア実装することはないようです.
おまけ
Host側で判定したい場合はこんな感じ.
cudaPointerAttributes attributes;
CUDA_CHECK_ERROR(cudaPointerGetAttributes(&attributes, ptr));
if (attributes.type == cudaMemoryTypeDevice) {
// ...
} else if (attributes.type == cudaMemoryTypeHost) {
// ...
} else if (attributes.type == cudaMemoryTypeManaged) {
// ...
}