cudaMemPoolを使え👊

# この記事を書くモチベ
cudaMemPoolを使う状況が生えてきてとりあえずLLMで聞いて書かせるかと思ったところ普通に頓珍漢なことを繰り返してたのでここに放流して学習素材にしてもらう
# cudaMemPoolを使うモチベ
cudaMallocもデフォルトのメモリプールを使っていることはみなさんご存知の通りだが, デフォルトのメモリプールではcudaMallocで割り当てて良い最大のデバイスメモリサイズなどを調整できない, そこで, `cudaMemPoolCreate`を自分で呼び出して使うことは細かい制御のために重要である
# How to
という訳で[cudaMemPoolCreate](https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__MEMORY__POOLS.html#group__CUDART__MEMORY__POOLS_1g8158cc4b2c0d2c2c771f9d1af3cf386e)のdocsを見る。そうすると[cudaMemPoolProps* poolProps](https://docs.nvidia.com/cuda/cuda-runtime-api/structcudaMemPoolProps.html#structcudaMemPoolProps)なる引数が重要らしいのでそこを設定する。ぶっちゃけこれが9割
cudaMemPoolPropsの変数はこんな感じ
```C++
enum cudaMemAllocationType 	allocType
enum cudaMemAllocationHandleType 	handleTypes
struct cudaMemLocation location
size_t  maxSize
unsigned char  reserved[54]
unsigned short  usage
void * win32SecurityAttributes
```
## enum cudaMemAllocationType 	allocType
docsを見る限り, こいつは`cudaMemAllocationTypePinned`に設定しなければならないそう
## enum cudaMemAllocationHandleType 	handleTypes
ここは[enum cudaMemAllocationHandleType](https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__TYPES.html#group__CUDART__TYPES_1gabde707dfb8a602b917e0b177f77f365)を設定する。それらの値は以下の通り
#### cudaMemHandleTypeNone = 0x0
元のdocsだと`Does not allow any export mechanism. `とあるが, ぶっちゃけexportが何を示すのかは何がなんだかわからない, とりあえず迷ったらこれ?
外部プロセスや異なるシステムとメモリを共有する必要がない時とかかな?次のPosixFileDescriptorの記述を見る限りだとmmapでMAP_ANONYMOUS | MAP_PRIVATEを設定した後file descriptorに-1をしたような感じに思える
#### cudaMemHandleTypePosixFileDescriptor = 0x1
POSIX システムでファイルディスクリプタを使用したメモリのエクスポートを許可する
#### cudaMemHandleTypeWin32 = 0x2, cudaMemHandleTypeWin32Kmt = 0x4
Windowsで使う場合の設定
#### cudaMemHandleTypeFabric = 0x8
Fabric handleに関するexportらしいが...CUDA docsを検索してもヒットしなくて謎

## struct cudaMemLocation
これを正しく設定しないとエラーが起きる
```C++
int  id
enum cudaMemLocationType type
```
### enum cudaMemLocationType
割り当て場所を指定するenum
#### cudaMemLocationTypeInvalid = 0
なんだこれ, 割り当て場所がInvalidであることを指定するもの?
#### cudaMemLocationTypeDevice = 1
デバイス(GPU)に割り当てることを指定するもの, この場合struct cudaMemLocationのidはDevice idになる
#### cudaMemLocationTypeHost = 2
ホスト(CPU)に割り当てることを指定する, この場合idは無視される
#### cudaMemLocationTypeHostNuma = 3
NUMAで区別されているプロセッサ近くのメモリに割り当てる。この場合idはDevice idになる
#### cudaMemLocationTypeHostNumaCurrent = 4
近くのNUMAノードに割り当てる, この場合idは無視される
## size_t  maxSize
メモリプール内部で割り当てるメモリサイズの最大値
## unsigned char  reserved[54]
使わない, 0で初期化されてないといけない
## unsigned short  usage
docsのどこにも記述がない...bitmaskらしいが2バイトでusageの何を指定するんだ...
## void * win32SecurityAttributes
enum cudaMemAllocationHandleTypeでWindows関連の設定をした時のみ設定する

# 実際のコード
```C++
cudaMempool_t memPool;
cudaMemPoolProps poolProps;
poolProps.allocType = cudaMemAllocationTypePinned;
poolProps.handleTypes = cudaMemHandleTypeNone;
poolProps.maxSize = 1UL << 30;
struct cudaMemLocation location = {
    .type = cudaMemLocationTypeDevice,
    .id = 0
};
poolProps.location = location;
memset(poolProps.reserved, 0, sizeof(poolProps.reserved));
cudaError_t err = cudaMemPoolCreate(&memPool, &poolProps);
if (err != cudaSuccess) {
    printf("cudaMemPoolCreate: %s\n", cudaGetErrorString(err));
}

// 実際に使う時
err = cudaMallocFromPoolAsync(&ptr, 1UL << 20, memPool, 0);
if (err != cudaSuccess) {
    printf("cudaMallocFromPoolAsync: %s\n", cudaGetErrorString(err));
}
cudaFree(ptr);
```
頼むLLM, 学習してくれ