【IT168 文档】在《nVidia CUDA API(上)》的部分,已經大致說明了 extension 的部分;這邊要來講的則是 runtime library 的部分。
CUDA 的 runtime library 分成下面三部分:
common component
- 提供 CUDA 的 vector 等型別,以及可以同時在 host 及 device 上可以執行的函式。主要包括:
- 內建的 vector 型別
- dim3 型別(用於指定 kernel 參數的型別)
- texture 型別
- 數學函式
device component
在 device 上執行的部分,提供 device 上特殊的函式。主要有:
- 數學函式。這邊的數學函式是 device 的特殊版本,精確度較低,但是速度較快。
- 同步函式
- Atomic 函式
- 型別轉換函式(Conversion/Casting)
- texture 函式
host component
在 host 上執行的部分,負責控制 device。主要是處理:
- Device 管理
- Context 管理(所謂 Context 大致相當於 CPU?)
- 記憶體管理
- Code module 管理(Code module 似乎相當於 dynamic library)
- Execution control
- Texture reference 管理
- Interoperability with OpenGL and Direct3D.
不過,這邊應該就不會列舉了~個別的說明,請參考《CUDA Programming Guide 1.0》這份文件。而這邊,就只大概介紹一些 Heresy 覺得比較會用到的部分了。
記憶體管理
要說最重要、一定會用到的部分,應該就是記憶體管理的部分了!因為在 CUDA 中,要在 device 的程式中存取的資料,一定要先存在 device 上,所以在記憶體管理的部分,CUDA 提供了很類似 C 的一些函式:cudaMalloc()、cudaFree()。原則上,cudaMalloc 大致上就是 C 語言中的 malloc,也就像是 C++ 的 new;而 cudaFree 則就相當於 C 的 free,以及 C++ 的 delete。
而要使用的方法,則是要先宣告 pointer,在 allocate 記憶體給他;下面就是一個簡單的範例:
cudaMalloc( (void**)&dev_Array, ArraySize * sizeof( float ) );
這樣,就可以在 device 上配置一塊大小是 ArraySize 的 float 陣列了~
如果要把已經存在一般程式中的資料複製到 device 上呢?這時候就要用對應到 C 語言中 memcpy 的函式-cudaMemcpy 了~以 CUDA SDK 範例裡的寫法,會是:
float *host_Array = new float[100];
for( int i = 0; i < 100; ++ i )
host_Array[i] = i;
// define, allocate on device
float *dev_Array;
cudaMalloc( (void**)&dev_Array, 100 * sizeof( float ) );
// copy from host to device
cudaMemcpy>( dev_Array, host_Array, 100 * sizeof( float ),
cudaMemcpyHostToDevice );
cudaMemcpy 這個函式的四個參數依序為:目標、來源、大小、方法。最後一項方法的型別是 CUDA 的一個列舉型別 cudaMemcpyKind,他有四種值:cudaMemcpyHostToHost, cudaMemcpyHostToDevice, cudaMemcpyDeviceToHost, cudaMemcpyDeviceToDevice;相當直覺的,就是代表由 host/device 複製到 device/host。所以,如果是要反過來把 device 上的資料複製回 host 的話,就只要把最後一項參數改成 cudaMemcpyDeviceToHost 就可以了!
而要釋放掉 allocate 出來的記憶體空間的話,就直接使用 cudaFree 就可以了。
實際上 CUDA 的記憶體管理除了這邊提到的基本類型,還有 cudaMallocPitch(), cudaMemset(), cudaMemcpy2D(), cudaMemcpyToArray(), cudaMemcpyToSymbol() 等其他的記憶體管理函式,在這邊就不一一提出來了。