尽管 CudaSuccess,CUDA cudaMemCpy 似乎没有复制
CUDA cudaMemCpy doesn't appear to copy despite CudaSuccess
我刚刚开始使用 CUDA,这是我的第一个项目。我搜索了这个问题,虽然我注意到其他人也有类似的问题,但 none 的建议似乎与我的具体问题相关或对我的情况有所帮助。
作为练习,我正在尝试使用 CUDA 编写 n 体模拟。在这个阶段,我对我的具体实现是否有效不感兴趣,我只是在寻找有用的东西,我可以在以后改进它。我还需要稍后更新代码,一旦它工作,就可以处理我的 SLI 配置。
以下是流程的简要概述:
- 创建 X 和 Y 位置、速度、加速度向量。
- 在 GPU 上创建相同的向量并跨
复制值
- 在循环中:(i) 计算迭代加速度,(ii) 将加速度应用于速度和位置,以及 (iii) 将位置复制回主机以供显示。
(显示还未实现,稍后再做)
暂时不用担心加速度计算函数,这里是更新函数:
__global__ void apply_acc(double* pos_x, double* pos_y, double* vel_x, double* vel_y, double* acc_x, double* acc_y, int N)
{
int i = threadIdx.x;
if (i < N);
{
vel_x[i] += acc_x[i];
vel_y[i] += acc_y[i];
pos_x[i] += vel_x[i];
pos_y[i] += vel_y[i];
}
}
下面是主要方法中的一些代码:
cudaError t;
t = cudaMalloc(&d_pos_x, N * sizeof(double));
t = cudaMalloc(&d_pos_y, N * sizeof(double));
t = cudaMalloc(&d_vel_x, N * sizeof(double));
t = cudaMalloc(&d_vel_y, N * sizeof(double));
t = cudaMalloc(&d_acc_x, N * sizeof(double));
t = cudaMalloc(&d_acc_y, N * sizeof(double));
t = cudaMemcpy(d_pos_x, pos_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_pos_y, pos_y, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_vel_x, vel_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_vel_y, vel_y, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_acc_x, acc_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_acc_y, acc_y, N * sizeof(double), cudaMemcpyHostToDevice);
while (true)
{
calc_acc<<<1, N>>>(d_pos_x, d_pos_y, d_vel_x, d_vel_y, d_acc_x, d_acc_y, N);
apply_acc<<<1, N>>>(d_pos_x, d_pos_y, d_vel_x, d_vel_y, d_acc_x, d_acc_y, N);
t = cudaMemcpy(pos_x, d_pos_x, N * sizeof(double), cudaMemcpyDeviceToHost);
t = cudaMemcpy(pos_y, d_pos_y, N * sizeof(double), cudaMemcpyDeviceToHost);
std::cout << pos_x[0] << std::endl;
}
每个循环,cout
写入相同的值,无论最初创建位置数组时设置的随机值是什么。如果我将 apply_acc
中的代码更改为:
__global__ void apply_acc(double* pos_x, double* pos_y, double* vel_x, double* vel_y, double* acc_x, double* acc_y, int N)
{
int i = threadIdx.x;
if (i < N);
{
pos_x[i] += 1.0;
pos_y[i] += 1.0;
}
}
然后它仍然给出相同的值,所以要么 apply_acc
没有被调用,要么 cudaMemcpy
没有复制数据。
所有 cudaMalloc
和 cudaMemcpy
调用 return cudaScuccess
.
Here 的一个 PasteBin link 到完整的代码。它应该很容易理解,因为各种数组有很多重复。
就像我说的,我以前从未编写过 CUDA 代码,我是根据来自 NVidia 的 #2 CUDA 示例视频编写的,其中有人编写了并行数组加法代码。我不确定它是否有任何区别,但我使用的是带有最新 NVidia 驱动程序和 CUDA 7.0 RC 的 2x GTX970,并且我选择在安装 CUDA 时不安装捆绑的驱动程序,因为它们比我拥有的驱动程序旧。
这行不通:
const int N = 100000;
...
calc_acc<<<1, N>>>(...);
apply_acc<<<1, N>>>(...);
内核启动配置 (<<<...>>>
) 的第二个参数是每个块参数的线程数。它被限制为 512 或 1024,具体取决于您的编译方式。这些内核将不会启动,并且需要使用正确的 CUDA error checking 来捕获由此产生的错误类型。简单地查看后续 CUDA API 函数的 return 值不会表明存在此类错误(这就是为什么您随后会看到 cudaSuccess
)。
关于概念本身,建议大家多了解一下CUDA thread and block hierarchy。要启动大量线程,您需要使用内核启动配置的 both 参数(即前两个参数都不应为 1)。从性能的角度来看,这通常也是可取的。
我刚刚开始使用 CUDA,这是我的第一个项目。我搜索了这个问题,虽然我注意到其他人也有类似的问题,但 none 的建议似乎与我的具体问题相关或对我的情况有所帮助。
作为练习,我正在尝试使用 CUDA 编写 n 体模拟。在这个阶段,我对我的具体实现是否有效不感兴趣,我只是在寻找有用的东西,我可以在以后改进它。我还需要稍后更新代码,一旦它工作,就可以处理我的 SLI 配置。
以下是流程的简要概述:
- 创建 X 和 Y 位置、速度、加速度向量。
- 在 GPU 上创建相同的向量并跨 复制值
- 在循环中:(i) 计算迭代加速度,(ii) 将加速度应用于速度和位置,以及 (iii) 将位置复制回主机以供显示。
(显示还未实现,稍后再做)
暂时不用担心加速度计算函数,这里是更新函数:
__global__ void apply_acc(double* pos_x, double* pos_y, double* vel_x, double* vel_y, double* acc_x, double* acc_y, int N)
{
int i = threadIdx.x;
if (i < N);
{
vel_x[i] += acc_x[i];
vel_y[i] += acc_y[i];
pos_x[i] += vel_x[i];
pos_y[i] += vel_y[i];
}
}
下面是主要方法中的一些代码:
cudaError t;
t = cudaMalloc(&d_pos_x, N * sizeof(double));
t = cudaMalloc(&d_pos_y, N * sizeof(double));
t = cudaMalloc(&d_vel_x, N * sizeof(double));
t = cudaMalloc(&d_vel_y, N * sizeof(double));
t = cudaMalloc(&d_acc_x, N * sizeof(double));
t = cudaMalloc(&d_acc_y, N * sizeof(double));
t = cudaMemcpy(d_pos_x, pos_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_pos_y, pos_y, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_vel_x, vel_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_vel_y, vel_y, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_acc_x, acc_x, N * sizeof(double), cudaMemcpyHostToDevice);
t = cudaMemcpy(d_acc_y, acc_y, N * sizeof(double), cudaMemcpyHostToDevice);
while (true)
{
calc_acc<<<1, N>>>(d_pos_x, d_pos_y, d_vel_x, d_vel_y, d_acc_x, d_acc_y, N);
apply_acc<<<1, N>>>(d_pos_x, d_pos_y, d_vel_x, d_vel_y, d_acc_x, d_acc_y, N);
t = cudaMemcpy(pos_x, d_pos_x, N * sizeof(double), cudaMemcpyDeviceToHost);
t = cudaMemcpy(pos_y, d_pos_y, N * sizeof(double), cudaMemcpyDeviceToHost);
std::cout << pos_x[0] << std::endl;
}
每个循环,cout
写入相同的值,无论最初创建位置数组时设置的随机值是什么。如果我将 apply_acc
中的代码更改为:
__global__ void apply_acc(double* pos_x, double* pos_y, double* vel_x, double* vel_y, double* acc_x, double* acc_y, int N)
{
int i = threadIdx.x;
if (i < N);
{
pos_x[i] += 1.0;
pos_y[i] += 1.0;
}
}
然后它仍然给出相同的值,所以要么 apply_acc
没有被调用,要么 cudaMemcpy
没有复制数据。
所有 cudaMalloc
和 cudaMemcpy
调用 return cudaScuccess
.
Here 的一个 PasteBin link 到完整的代码。它应该很容易理解,因为各种数组有很多重复。
就像我说的,我以前从未编写过 CUDA 代码,我是根据来自 NVidia 的 #2 CUDA 示例视频编写的,其中有人编写了并行数组加法代码。我不确定它是否有任何区别,但我使用的是带有最新 NVidia 驱动程序和 CUDA 7.0 RC 的 2x GTX970,并且我选择在安装 CUDA 时不安装捆绑的驱动程序,因为它们比我拥有的驱动程序旧。
这行不通:
const int N = 100000;
...
calc_acc<<<1, N>>>(...);
apply_acc<<<1, N>>>(...);
内核启动配置 (<<<...>>>
) 的第二个参数是每个块参数的线程数。它被限制为 512 或 1024,具体取决于您的编译方式。这些内核将不会启动,并且需要使用正确的 CUDA error checking 来捕获由此产生的错误类型。简单地查看后续 CUDA API 函数的 return 值不会表明存在此类错误(这就是为什么您随后会看到 cudaSuccess
)。
关于概念本身,建议大家多了解一下CUDA thread and block hierarchy。要启动大量线程,您需要使用内核启动配置的 both 参数(即前两个参数都不应为 1)。从性能的角度来看,这通常也是可取的。