在下面的代码中,cudaMemcpy无效,它返回错误,程序退出。可能是什么问题?在我看来,我做的事情并不违法,而且矢量的大小对我来说似乎很好。
算法可能会在某些时候出错,但我想这个想法是正确的。代码是通过并行执行一些部分和来对n个数进行求和,然后重新迭代。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
__device__ int aug_vec(int *vec, const int& i, const int& size) {
return (i >= size) ? 0 : vec[i];
}
__global__ void sumVectorElements(int *vec,const int& size) {
const int i = (blockDim.x*blockIdx.x + threadIdx.x);
vec[i] = aug_vec(vec, 2*i, size) + aug_vec(vec, 2 * i + 1, size);
}
__host__ int parallel_sum(int *vec,const int& size) {
cudaError_t err;
int *d_vec, *cp_vec;
int n_threads = (size >> 1) + (size & 1);
cp_vec = new int[size];
err = cudaMalloc((void**)&d_vec, size * sizeof(int));
if (err != cudaSuccess) {
std::cout << "error in cudaMalloc!" << std::endl;
exit(1);
}
err = cudaMemcpy(d_vec, vec, size*sizeof(int), cudaMemcpyHostToDevice);
if (err != cudaSuccess) {
std::cout << "error in cudaMemcpy!" << std::endl;
exit(1);
}
int curr_size = size;
while (curr_size > 1) {
std::cout << "size = " << curr_size << std::endl;
sumVectorElements<<<1,n_threads>>>(d_vec, curr_size);
curr_size = (curr_size >> 1) + (curr_size & 1);
}
err = cudaMemcpy(cp_vec, d_vec, size*sizeof(int), cudaMemcpyDeviceToHost); //THIS LINE IS THE PROBLEM!
if (err != cudaSuccess) {
std::cout << "error in cudaMemcpy" << std::endl;
exit(1);
}
err = cudaFree(d_vec);
if (err != cudaSuccess) {
std::cout << "error in cudaFree" << std::endl;
exit(1);
}
int rval = cp_vec[0];
delete[] cp_vec;
return rval;
}
int main(int argc, char **argv) {
const int n_blocks = 1;
const int n_threads_per_block = 12;
int vec[12] = { 0 };
for (auto i = 0; i < n_threads_per_block; ++i) vec[i] = i + 1;
int sum = parallel_sum(vec, n_threads_per_block);
std::cout << "Sum = " << sum << std::endl;
system("pause");
return 0;
}
答案 0 :(得分:2)
内核之后的cudaMemcpy
操作实际上是异步报告由于内核执行而导致的错误。您的错误报告是原始的。如果您有错误代码,可以通过打印将错误代码传递给cudaGetErrorString()
的结果来获得更多有用的信息。
由于使用了引用参数,内核中发生错误:
__global__ void sumVectorElements(int *vec,const int& size) {
^^^^^^^^^^^^^^^
传递给内核并期望在内核代码中可用的任何参数必须引用通过值传递的数据,或者是可从设备代码访问/引用的数据。例如,将主机指针传递给设备代码在CUDA中通常是不合法的,因为尝试取消引用设备代码中的主机指针将失败。
上述例外情况是设备代码中可访问的数据/指针/引用。 Unified memory和pinned/mapped data是两个例子,这两个都没有在这里使用。
因此,引用参数涉及主机内存中项(size
)的引用(基本上是地址)。当内核代码尝试使用此项时,它必须首先取消引用它。在CUDA中取消引用设备代码中的主机项是非法的(除非使用UM或固定内存)。
这种情况下的解决方案很简单:转换为普通的按值传递情况:
__global__ void sumVectorElements(int *vec,const int size) ...
^
remove ampersand