CUDA入門 > メモリ > Page-Lockedメモリで転送(応用編)

Page-Lockedメモリで転送(応用編)


Page-Lockedメモリ(応用編)
OpenCVなどを使用していると、ホスト側のメモリ領域は勝手に作成されるため、
Page-Lockedメモリを使用して転送することができません。

memcpyでメモリーをホスト側で一旦コピーすればできますが、
そのコピー時間が無駄となります。
(ホスト-デバイス間の転送速度が遅い場合は、コピーも有効です)

少しイレギュラーな使い方かもしれませんが、
出力(デバイスからホストに転送)するメモリを、
Page-Lockedメモリにし、元のポインタが指すアドレスを、
Page-Lockedメモリのアドレスに変更してしまう方法があります。

プログラム例
#include <stdio.h> #include <cutil.h> #define N 1000 int main(int argc, char** argv){ float *h_in, *h_out, *h_pinned, *d_mem; // ホスト側のメモリ領域確保 h_in = (float *)calloc(sizeof(float), N); h_out = (float *)calloc(sizeof(float), N); // ホスト側にCUDA用のメモリ領域確保 CUDA_SAFE_CALL(cudaMallocHost((void**)&h_pinned, sizeof(float) * N)); // デバイス(GPU)のメモリ領域確保 CUDA_SAFE_CALL(cudaMalloc((void**)&d_mem, sizeof(float) * N)); // ホスト側のデータを初期化 for(int i = 0; i < N; i++){ h_in[i] = (float)i; h_out[i] = -1.0; } // ホストからデバイスへ転送 CUDA_SAFE_CALL(cudaMemcpy(d_mem, h_in, sizeof(float) * N, cudaMemcpyHostToDevice)); // デバイスからホストへ転送(ホスト側はpinnedメモリ) CUDA_SAFE_CALL(cudaMemcpy(h_pinned, d_mem, sizeof(float) * N, cudaMemcpyDeviceToHost)); // h_outが指すアドレスをh_pinnedが指すアドレスに変更 h_out = h_pinned; // 内容が変わっているか確認 bool flg = true; for(int i = 0; i < N; i++){ if(h_out[i] < 0){ printf("失敗...\n"); flg = false; break; } } if(flg){ printf("成功!\n"); } // ホストメモリ解放 free(h_in); free(h_out); cudaFreeHost(h_pinned); // デバイスメモリ解放 cudaFree(d_mem); // 終了処理 CUT_EXIT(argc, argv); return 0; }

ソースの説明
CUDA_SAFE_CALL(cudaMemcpy(h_pinned, d_mem, sizeof(float) * N, cudaMemcpyDeviceToHost));
h_out = h_pinned;

一旦pinnedメモリに転送して、
h_outのアドレスをpinnedメモリのアドレスに変更してしまっています。
「h_out = h_pinned」はアドレスを代入しているだけなので、
殆ど時間はかかりません。

※後ほどOpenCVを利用したソースも公開します。
 基本的には同じで、「h_out」が「->imageData」となるだけです。