二维阵列中的Cuda归约

二维阵列中的Cuda归约,cuda,parallel-processing,reduction,Cuda,Parallel Processing,Reduction,我想计算Cuda中整个图像的平均值。为了测试2D数组的缩减是如何工作的,我在下面编写了这个内核。最终输出o应该是所有图像值的总和。输入g是一个2D数组,每个像素的值为1。但是这个程序的结果是0的和。我觉得有点奇怪 我在本教程中模拟了一维数组的缩减,我编写了这个二维表单。我是Cuda的新手。欢迎对潜在缺陷和改进提出建议 只需添加一条评论。我知道计算一维数组中的平均值是有意义的。但我想利用更多的资源,测试更复杂的还原行为。这可能不对。但这只是一个测试。希望有人能给我更多的建议,减少常见做法 #inc

我想计算Cuda中整个图像的平均值。为了测试2D数组的缩减是如何工作的,我在下面编写了这个内核。最终输出o应该是所有图像值的总和。输入g是一个2D数组,每个像素的值为1。但是这个程序的结果是0的和。我觉得有点奇怪

我在本教程中模拟了一维数组的缩减,我编写了这个二维表单。我是Cuda的新手。欢迎对潜在缺陷和改进提出建议

只需添加一条评论。我知道计算一维数组中的平均值是有意义的。但我想利用更多的资源,测试更复杂的还原行为。这可能不对。但这只是一个测试。希望有人能给我更多的建议,减少常见做法

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

cudaEvent_t start, stop;
float elapsedTime;

__global__ void 
reduce(float *g, float *o, const int dimx, const int dimy)
{
extern __shared__ float sdata[];

unsigned int tid_x = threadIdx.x;
unsigned int tid_y = threadIdx.y;

unsigned int i = blockDim.x * blockIdx.x + threadIdx.x;
unsigned int j = blockDim.y * blockIdx.y + threadIdx.y; 

if (i >= dimx || j >= dimy)
    return;

sdata[tid_x*blockDim.y + tid_y] = g[i*dimy + j];

__syncthreads();

for(unsigned int s_y = blockDim.y/2; s_y > 0; s_y >>= 1)
{
    if (tid_y < s_y)
    {
        sdata[tid_x * dimy + tid_y] += sdata[tid_x * dimy + tid_y + s_y];
    }
    __syncthreads();
}

for(unsigned int s_x = blockDim.x/2; s_x > 0; s_x >>= 1 )
{

    if(tid_x < s_x)
    {
        sdata[tid_x * dimy] += sdata[(tid_x + s_x) * dimy];
    }
    __syncthreads();
}

float sum;

if( tid_x == 0 && tid_y == 0)
{ 
    sum = sdata[0];
    atomicAdd (o, sum);   // The result should be the sum of all pixel values. But the program produce 0
}

//if(tid_x==0 && tid__y == 0 ) 
    //o[blockIdx.x] = sdata[0];
}

int
main()
{   
int dimx = 320;
int dimy = 160;
int num_bytes = dimx*dimy*sizeof(float);

float *d_a, *h_a, // device and host pointers
            *d_o=0, *h_o=0;

h_a = (float*)malloc(num_bytes);
h_o = (float*)malloc(sizeof(float));

srand(time(NULL));


for (int i=0; i < dimx; i++)
{   
    for (int j=0; j < dimy; j++)
    {
        h_a[i*dimy + j] = 1;
    }
}

cudaMalloc( (void**)&d_a, num_bytes );
cudaMalloc( (void**)&d_o, sizeof(int) );

cudaMemcpy( d_a, h_a, num_bytes, cudaMemcpyHostToDevice);
cudaMemcpy( d_o, h_o, sizeof(int), cudaMemcpyHostToDevice); 

dim3 grid, block;
block.x = 4;
block.y = 4;
grid.x = dimx / block.x;
grid.y = dimy / block.y;

cudaEventCreate(&start);
cudaEventRecord(start, 0);

int sizeofSharedMemory = dimx*dimy*sizeof(float);

reduce<<<grid, block, sizeofSharedMemory>>> (d_a, d_o, block.x, block.y);

cudaEventCreate(&stop);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);

cudaEventElapsedTime(&elapsedTime, start, stop);
std::cout << "This kernel runs: " << elapsedTime << "ms" << std::endl; 

std::cout << block.x << " " << block.y << std::endl;
std::cout << grid.x << " " << grid.y << std::endl;
std::cout << dimx <<  " " << dimy << " " << dimx*dimy << std::endl;

cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost );
cudaMemcpy( h_o, d_o, sizeof(int), cudaMemcpyDeviceToHost );

std::cout << "The sum is:" << *h_o << std::endl;

free(h_a);
free(h_o);
cudaFree(d_a);
cudaFree(d_o);

}
#包括
#包括
#包括
#包括
cudaEvent\u t启动、停止;
浮动时间;
__全局无效
减少(浮点*g,浮点*o,常量整数dimx,常量整数dimy)
{
外部共享浮点数据[];
无符号整数tid_x=threadIdx.x;
无符号整数tid_y=threadIdx.y;
无符号整数i=blockDim.x*blockIdx.x+threadIdx.x;
无符号整数j=blockDim.y*blockIdx.y+threadIdx.y;
如果(i>=dimx | | j>=dimy)
返回;
sdata[tid_x*blockDim.y+tid_y]=g[i*dimy+j];
__同步线程();
对于(无符号整数s_y=blockDim.y/2;s_y>0;s_y>>=1)
{
如果(tid_y0;s_x>>=1)
{
if(tid_x
int dimx = 320;
int dimy = 160;
...
int sizeofSharedMemory = dimx*dimy*sizeof(float); // = 204800

reduce<<<grid, block, sizeofSharedMemory>>> (d_a, d_o, block.x, block.y);
                          ^
                          |
                         204800 is illegal here
在将总和从设备复制到主机之前,您正在打印总和。 与这些步骤的顺序相反:

cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost );
cudaMemcpy( h_o, d_o, sizeof(int), cudaMemcpyDeviceToHost );

std::cout << "The sum is:" << *h_o << std::endl;
cudaMemcpy(h_a,d_a,num_字节,cudaMemcpyDeviceToHost);
cudaMemcpy(h_o,d_o,sizeof(int),cudaMemcpyDeviceToHost);

std::cout一个
2D
MxN
元素的数组可以被视为
1D
MN
元素的数组。那么,为什么你不利用已经开发的
CUDA
还原代码来实现
1D
数组呢?你可以看看
CUDA SDK还原
的例子。关于你的代码,你能发布一个完整版本,以便有人可以编译和执行它,并给你更多的见解?谢谢你的反馈。我把整个程序放在它上面。因为它是一个测试程序,让我学习最好的cuda,我尝试写我自己的。一个非常快的评论。你没有初始化
h_o
,所以
d_o
,但这不是唯一的问题在这段代码中。谢谢。我在这里将它初始化为*h_o=0,*d_o。在这里不正确吗?事实上,我用相同的主函数尝试了1D数组缩减,并且成功了。在从设备复制其值之前,您正在打印
*h_0
cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost );
cudaMemcpy( h_o, d_o, sizeof(int), cudaMemcpyDeviceToHost );

std::cout << "The sum is:" << *h_o << std::endl;