1. 程式人生 > >CUDA Hello World 程式

CUDA Hello World 程式

CUDA(Compute Unified Device Architecture)是NVIDIA(英偉達)公司基於其生產的圖形處理器GPU(Graphics Processing Unit)開發的一個平行計算平臺和程式設計模型。

基於CPU程式設計,程式都是執行在CPU上的;基於GPU編寫的程式,程式執行在GPU上。在原有CPU平臺上新增GPU裝置後,通過增加額外的計算單元,可以有效的提高程式的執行效率。
一般將CPU端叫做Host, 將GPU端叫做Device. 如何寫一個執行在GPU端的Hello world程式呢?
簡單的看了Manual後,可能會這麼寫:

#include <stdio.h>

__global__ void hello() {
    printf("Hello world from device");
}

int main() {
    hello<<<1, 1>>>();
    printf("Hello world from host");
    return 0;
}

將上面檔案命名為helloWorld.cu,用nvcc編譯:

nvcc -o helloWorld helloWorld.cu

執行./helloWorld,發現只會打印出"hello world from host"。
檢視NVIDIA的開發文件,device端的printf其實和裝置端的printf函式是不同的實現,那為什麼include一個標準庫的標頭檔案就可以使用device端的printf函式?其實這是源於cuda實現的一些技術細節,標準庫的標頭檔案只是給出了一個函式原型的提示,當在不同架構的計算機上編譯時,通過函式過載,會呼叫不同的函式,這裡有人給出了詳細解釋)。而device端的輸出其實是輸出到device端的一個環形buffer(超出size後會覆寫之前的內容),要flush到host端,需要採用下面任一操作:

  1. Kernel launch via <<<>>> or cuLaunchKernel()
  2. Synchronization via cudaDeviceSynchronize(), cuCtxSynchronize(), cudaStreamSynchronize(), cuStreamSynchronize(),
    cudaEventSynchronize(), or cuEventSynchronize(),
  3. Memory copies via any blocking version of cudaMemcpy*() or cuMemcpy*(),
  4. Module loading/unloading via cuModuleLoad() or cuModuleUnload(),
  5. Context destruction via cudaDeviceReset() or cuCtxDestroy().
  6. Prior to executing a stream callback added by cudaStreamAddCallback or cuStreamAddCallback.

這裡,新增cudaDeviceSynchronize(),發現就可以正常輸出了:

#include <stdio.h>

__global__ void hello() {
    printf("Hello world from device");
}

int main() {
    hello<<<1, 1>>>();
    printf("Hello world from host");
    cudaDeviceSynchronize();
    return 0;
}