内核调用后 CUDA 数组设置为 0
CUDA Array set to 0 after kernel call
我有一个包含 3 个数组的简单程序,它计算第三个数组有多少为 0,并且第一个和第二个具有相同的值。当它为真时,增加另一个数组索引。
问题是:
如果内核只有第一个if() then
函数数组A永远为0
如果我插入 if() then else
函数,数组 A 的值在索引 = 2 后设置为 0,并且不计算 A、B、C=0[=13 时的状态=]
这是代码
#include <stdio.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <stdlib.h>
#include <cuda_runtime_api.h>
// Kernel that executes on the CUDA device
__global__ void square_array(float *a, float *b, float *c, float *res)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (a[idx]=b[idx] && c[idx]==0) {
res[0]++;
}
else if (a[idx]=b[idx] && c[idx]==1){
res[1]++;
}
}
// main routine that executes on the host
int main(void)
{
float *a_h, *a_d; // Pointer to host & device arrays
float *b_h, *b_d; // Pointer to host & device arrays
float *c_h, *c_d; // Pointer to host & device arrays
float *res_h, *res_d; // Pointer to host & device arrays
const int N = 10; // Number of elements in arrays
size_t size = N * sizeof(float);
//size_t size_s = 4 * sizeof(float);
a_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &a_d, size); // Allocate array on device
b_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &b_d, size); // Allocate array on device
c_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &c_d, size); // Allocate array on device
res_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &res_d, size); // Allocate array on device
// Initialize host array and copy it to CUDA device
// for (int i=0; i<N; i++) a_h[i] = (float)i;
for (int i=0; i<N; i++) a_h[i] = (float)i;
for (int i=0; i<N; i++) b_h[i] = (float)i;
for (int i=0; i<N; i++) c_h[i] = (float)i;
for (int i=0; i<4; i++) res_h[i] = 0;
cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(b_d, b_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(c_d, c_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(res_d, res_h, size, cudaMemcpyHostToDevice);
// Do calculation on device:
int block_size = 8;
int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
square_array <<< n_blocks, block_size >>> (a_d, b_d, c_d, res_d);
// Retrieve result from device and store it in host array
cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(b_h, b_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(c_h, c_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(res_h, res_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
// Print results
for (int i=0; i<N; i++){
printf("%f A \n", a_h[i]);
}
for (int i=0; i<N; i++){
printf("%f B \n", b_h[i]);
}
for (int i=0; i<N; i++){
printf("%f C \n", c_h[i]);
}
for (int i=0; i<4; i++){
printf("%f res \n", res_h[i]);
}
// Cleanup
free(a_h); cudaFree(a_d);
free(b_h); cudaFree(b_d);
free(c_h); cudaFree(c_d);
free(res_h); cudaFree(res_d);
}
抱歉,我解决了 problem.It 是错误输入 control = 而不是 true ==
除了 if (a[idx]=b[idx] && c[idx]==0) {
中的 =
应该是 ==
正如你已经找到的(下面的 if
语句也是如此),至少有您的代码中的另外两个问题:
您没有检查线程索引是否超出数组的限制。因此,由于您使用的是 2 个块,每块 8 个线程,因此您有 16 个线程访问 10 个元素数组。为避免此问题,您需要将 N 作为内核参数传递并在某处添加 if ( idx < N )
。
你在 res
中并行积累,没有任何保护,导致各种竞争条件。这是一个非常典型的直方图问题,在文献(网络、书籍、CUDA 示例...)中有大量解释。一个快速解决方法(尽管可能不是最有效的方法)是使用原子操作,例如 atomicAdd
。在你的例子中,行 res[0]++;
会变成 atomicAdd( &res[0], 1 );
,而 res[1]++;
会变成(如你所猜)atomicAdd( &res[1], 1 );
。对 float 的支持意味着您在使用至少 2.0.
的计算能力时编译代码
HTH
我有一个包含 3 个数组的简单程序,它计算第三个数组有多少为 0,并且第一个和第二个具有相同的值。当它为真时,增加另一个数组索引。 问题是:
如果内核只有第一个
if() then
函数数组A永远为0如果我插入
if() then else
函数,数组 A 的值在索引 = 2 后设置为 0,并且不计算 A、B、C=0[=13 时的状态=]
这是代码
#include <stdio.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <stdlib.h>
#include <cuda_runtime_api.h>
// Kernel that executes on the CUDA device
__global__ void square_array(float *a, float *b, float *c, float *res)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (a[idx]=b[idx] && c[idx]==0) {
res[0]++;
}
else if (a[idx]=b[idx] && c[idx]==1){
res[1]++;
}
}
// main routine that executes on the host
int main(void)
{
float *a_h, *a_d; // Pointer to host & device arrays
float *b_h, *b_d; // Pointer to host & device arrays
float *c_h, *c_d; // Pointer to host & device arrays
float *res_h, *res_d; // Pointer to host & device arrays
const int N = 10; // Number of elements in arrays
size_t size = N * sizeof(float);
//size_t size_s = 4 * sizeof(float);
a_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &a_d, size); // Allocate array on device
b_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &b_d, size); // Allocate array on device
c_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &c_d, size); // Allocate array on device
res_h = (float *)malloc(size); // Allocate array on host
cudaMalloc((void **) &res_d, size); // Allocate array on device
// Initialize host array and copy it to CUDA device
// for (int i=0; i<N; i++) a_h[i] = (float)i;
for (int i=0; i<N; i++) a_h[i] = (float)i;
for (int i=0; i<N; i++) b_h[i] = (float)i;
for (int i=0; i<N; i++) c_h[i] = (float)i;
for (int i=0; i<4; i++) res_h[i] = 0;
cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(b_d, b_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(c_d, c_h, size, cudaMemcpyHostToDevice);
cudaMemcpy(res_d, res_h, size, cudaMemcpyHostToDevice);
// Do calculation on device:
int block_size = 8;
int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
square_array <<< n_blocks, block_size >>> (a_d, b_d, c_d, res_d);
// Retrieve result from device and store it in host array
cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(b_h, b_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(c_h, c_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
cudaMemcpy(res_h, res_d, sizeof(float)*N, cudaMemcpyDeviceToHost);
// Print results
for (int i=0; i<N; i++){
printf("%f A \n", a_h[i]);
}
for (int i=0; i<N; i++){
printf("%f B \n", b_h[i]);
}
for (int i=0; i<N; i++){
printf("%f C \n", c_h[i]);
}
for (int i=0; i<4; i++){
printf("%f res \n", res_h[i]);
}
// Cleanup
free(a_h); cudaFree(a_d);
free(b_h); cudaFree(b_d);
free(c_h); cudaFree(c_d);
free(res_h); cudaFree(res_d);
}
抱歉,我解决了 problem.It 是错误输入 control = 而不是 true ==
除了 if (a[idx]=b[idx] && c[idx]==0) {
中的 =
应该是 ==
正如你已经找到的(下面的 if
语句也是如此),至少有您的代码中的另外两个问题:
您没有检查线程索引是否超出数组的限制。因此,由于您使用的是 2 个块,每块 8 个线程,因此您有 16 个线程访问 10 个元素数组。为避免此问题,您需要将 N 作为内核参数传递并在某处添加
if ( idx < N )
。你在
res
中并行积累,没有任何保护,导致各种竞争条件。这是一个非常典型的直方图问题,在文献(网络、书籍、CUDA 示例...)中有大量解释。一个快速解决方法(尽管可能不是最有效的方法)是使用原子操作,例如atomicAdd
。在你的例子中,行res[0]++;
会变成atomicAdd( &res[0], 1 );
,而res[1]++;
会变成(如你所猜)atomicAdd( &res[1], 1 );
。对 float 的支持意味着您在使用至少 2.0. 的计算能力时编译代码
HTH