GPU プログラミングでは、CPU ハードウェアと GPU ハードウェアの両方を考慮する必要があります。この種のプログラミングは異種混合プログラミングと呼ばれます。
コードは CPU 上で実行を開始し、大量の並列化が必要な部分に遭遇し、それを GPU 上で並列化し、他の計算のために結果を CPU に返します。
CPU上でのベクトル加算
- メモリ空間を解放し、
- 2 つのベクトルを初期化します。
- 加算をループするか、ベクトル化された加算を使用する
- 空きメモリ
この計算効率は帯域幅によって非常に制限されるため、たとえば、次のコードでは長さ 100 万の 2 つのベクトルの加算を計算する必要があります。
#include <iostream>
int main(void) {
int N = 1<<20; // 1M elements
float *x = new float[N]; // Allocate memory
float *y = new float[N];
// initialize x and y on the CPU
for (int i = 0; i < N; i++) {
x[i] = 1.0f; y[i] = 2.0f;
}
// Run on 1M elements on the CPU
add(N, x, y);
// Free memory
delete [] x; delete [] y;
return 0;
}
GPU上でのベクトル加算
GPU上で実行される関数をカーネル関数(kernel)と呼び、カーネル関数はCPUによって呼び出されます。
- GPU 上のメモリ空間 (ビデオ メモリ) を解放します。
- データをGPUにコピーする
- カーネル関数の実行
- 計算待ち
- 結果をCPUに返す
GPUシリアル演算ベクトル加算
float *x = new float[N];
float *y = new float[N];
int size = N*sizeof(float);
float *d_x, *d_y; // device copies of x y
cudaMalloc((void **)&d_x, size);//GPU上开辟内存
cudaMalloc((void **)&d_y, size);//GPU上开辟内存
cudaMemcpy(d_x, x, size, cudaMemcpyHostToDevice);//CPU到GPU转移数据
cudaMemcpy(d_y, y, size, cudaMemcpyHostToDevice);//CPU到GPU转移数据
// Run kernel on GPU
add<<<1,1>>>(N, d_x, d_y);//调用内核代码,<<<1,1>>>表示使用单线程计算
// Copy result back to host
cudaMemcpy(y, d_y, size, cudaMemcpyDeviceToHost);//将结果返还给CPU
// Free memory
cudaFree(d_x); cudaFree(d_y);
delete [] x; delete [] y;
// GPU function to add two vectors
__global__ //添加关键字表示以下函数为内核函数
void add(int n, float *x, float *y) {
for (int i = 0; i < n; i++)
y[i] = x[i] + y[i];
}
並列計算を使用して計算速度を向上させたい場合は、複数のスレッドを使用して同時に計算する必要があります。カーネル関数を書き直す必要がある
// GPU function to add two vectors
__global__
void add(int n, float *x, float *y) {
int index = threadIdx.x;//CUDA线程的索引
y[index] = x[index] + y[index];
}
add<<<1,256>>>(N, d_x, d_y);//使用一个线程块中的256个线程进行计算