我剛開始學習CUDA
編程。我簡單地通過一些簡單的CUDA C
例子,一切都在順風順水。然後!突然!推力!我認爲自己熟悉的C++函數子,並在差異CUDA C
和Thrust
CUDA C訴Thrust,我錯過了什麼?
之間嚇了一跳我覺得很難相信,
__global__ void square(float *a, int N) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N) {
a[idx] = a[idx] * a[idx];
}
}
int main(int argc, char** argv) {
float *aHost, *aDevice;
const int N = 10;
size_t size = N * sizeof(float);
aHost = (float*)malloc(size);
cudaMalloc((void**)&aDevice, size);
for (int i = 0; i < N; i++) {
aHost[i] = (float)i;
}
cudaMemcpy(aDevice, aHost, size, cudaMemcpyHostToDevice);
int block = 4;
int nBlock = N/block + (N % block == 0 ? 0:1);
square<<<nBlock, block>>>(aDevice, N);
cudaMemcpy(aHost, aDevice, size, cudaMemcpyDeviceToHost);
for (int i = 0; i < N; i++) {
printf("%d, %f\n", i, aHost[i]);
}
free(aHost);
cudaFree(aDevice);
}
等同放着清單
template <typename T>
struct square {
__host__ __device__ T operator()(const T& x) const {
return x * x;
}
};
int main(int argc, char** argv) {
const int N = 10;
thrust::device_vector<float> dVec(N);
thrust::sequence(dVec.begin(), dVec.end());
thrust::transform(dVec.begin(), dVec.end(), dVec.begin(), square<float>());
thrust::copy(dVec.begin(), dVec.end(), std::ostream_iterator<float>(std::cout, "\n"));
}
我缺少的東西?上面的代碼是否在GPU上運行? Thrust是一個很好的工具,但我懷疑它需要處理所有沉重的C風格內存管理。
Thrust
代碼是否在GPU上執行?我怎麼知道?Thrust
如何消除喚起內核的奇怪語法?- 是
Thrust
實際上喚起了一個內核? Thrust
是否自動處理線程索引計算?
謝謝你的時間。很抱歉,如果這些都是愚蠢的問題,但是我發現我所看到的例子已經從可以被描述爲Model T到M3的瞬間立即轉變,我感到不可思議。
那麼'thrust :: transform'函數會喚起我的'方形內核?它如何知道如何分配線程? –
是的,它調用你的* functor *,作爲*內核*的一部分,它創建「底層」。 Thrust是一個開源庫;你可以自己檢查一下。並且有GPU分析工具可以用來確認推力確實在使用GPU。關於線程的分配,在創建大量輸出時,CUDA編程中的一個常見策略是爲每個輸出元素分配一個線程。看看你的函子和整體算法,我發現輸入和輸出之間存在1:1的關係(通常是'transform'),所以每個數據元素有一個線程是有意義的。 –