技术开发 频道

第一個 CUDA 程式

  利用 CUDA 進行運算

  到目前為止,我們的程式並沒有做什麼有用的工作。所以,現在我們加入一個簡單的動作,就是把一大堆數字,計算出它的平方和。

  首先,把程式最前面的 include 部份改成:

#include <stdio.h>
#include
<stdlib.h>
#include
<cuda_runtime.h>
#define DATA_SIZE
1048576
int data[DATA_SIZE];

並加入一個新函式 GenerateNumbers:

void GenerateNumbers(int *number, int size)
{
    
for(int i = 0; i < size; i++) {
        number[i]
= rand() % 10;
    }
}

  這個函式會產生一大堆 0 ~ 9 之間的亂數。

  要利用 CUDA 進行計算之前,要先把資料複製到顯示記憶體中,才能讓顯示晶片使用。因此,需要取得一塊適當大小的顯示記憶體,再把產生好的資料複製進去。在 main 函式中加入:

    GenerateNumbers(data, DATA_SIZE);
    
int* gpudata, *result;
    cudaMalloc((
void**) &gpudata, sizeof(int) * DATA_SIZE);
    cudaMalloc((
void**) &result, sizeof(int));
    cudaMemcpy(gpudata, data, sizeof(
int) * DATA_SIZE,
        cudaMemcpyHostToDevice);

  上面這段程式會先呼叫 GenerateNumbers 產生亂數,並呼叫 cudaMalloc 取得一塊顯示記憶體(result 則是用來存取計算結果,在稍後會用到),並透過 cudaMemcpy 將產生的亂數複製到顯示記憶體中。cudaMalloc 和 cudaMemcpy 的用法和一般的 malloc 及 memcpy 類似,不過 cudaMemcpy 則多出一個參數,指示複製記憶體的方向。在這裡因為是從主記憶體複製到顯示記憶體,所以使用 cudaMemcpyHostToDevice。如果是從顯示記憶體到主記憶體,則使用 cudaMemcpyDeviceToHost。這在之後會用到。

  接下來是要寫在顯示晶片上執行的程式。在 CUDA 中,在函式前面加上 __global__ 表示這個函式是要在顯示晶片上執行的。因此,加入以下的函式:

__global__ static void sumOfSquares(int *num, int* result)
{
    
int sum = 0;
    
int i;
    
for(i = 0; i < DATA_SIZE; i++) {
        sum
+= num[i] * num[i];
    }
    
*result = sum;
}

  在顯示晶片上執行的程式有一些限制,例如它不能有傳回值。其它的限制會在之後提到。

  接下來是要讓 CUDA 執行這個函式。在 CUDA 中,要執行一個函式,使用以下的語法:

  函式名稱<<>>(參數...);

  呼叫完後,還要把結果從顯示晶片複製回主記憶體上。在 main 函式中加入以下的程式:

    sumOfSquares<<<1, 1, 0>>>(gpudata, result);
    
int sum;
    cudaMemcpy(
&sum, result, sizeof(int), cudaMemcpyDeviceToHost);
    cudaFree(gpudata);
    cudaFree(result);
    printf(
"sum: %d\n", sum);

  因為這個程式只使用一個 thread,所以 block 數目、thread 數目都是 1。我們也沒有使用到任何 shared memory,所以設為 0。編譯後執行,應該可以看到執行的結果。

  為了確定執行的結果正確,我們可以加上一段以 CPU 執行的程式碼,來驗證結果:

    sum = 0;
    
for(int i = 0; i < DATA_SIZE; i++) {
        sum
+= data[i] * data[i];
    }
    printf(
"sum (CPU): %d\n", sum);

  編譯後執行,確認兩個結果相同。

0
相关文章