CUDA循环在数组添加中展开

时间:2014-06-22 14:19:38

标签: cuda

我想计算'out = alpha * px + beta * py','px'和'py'是数组。*

我有一个简单的内核:

__global__ 
void saxpyGPU2( float *out, const float *px, const float *py, size_t N, float alpha,float beta )
{
    size_t i = blockDim.x*blockIdx.x + threadIdx.x;
    while (i < N)
    {
        out[i] = alpha * px[i] + beta * py[i];
        i += blockDim.x*gridDim.x;
    } 
}

它有效,所以我想循环展开。

cuda-handbook中的代码是:

template<const int n> 
__device__ 
void saxpy_unrolled(float *out, const float *px, const float *py, size_t N, float alpha,float beta)
{
    float x[n], y[n];
    size_t i;
    for ( i = n*blockIdx.x*blockDim.x+threadIdx.x; i < N-n*blockDim.x*gridDim.x; i += n*blockDim.x*gridDim.x ) {
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            x[j] = px[index];
            y[j] = py[index];
        }
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            out[index] = alpha*x[j]+beta* y[j];
        }
    }
    // to avoid the (index<N) conditional in the inner loop, 
    // we left off some work at the end
    for ( int j = 0; j < n; j++ ) {
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            if ( index<N ) {
                x[j] = px[index];
                y[j] = py[index];
            }
        }
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            if ( index<N ) out[index] = alpha*x[j]+beta* y[j];
        }
    }
}

__global__ 
void saxpyGPU( float *out, const float *px, const float *py, size_t N, float alpha,float beta )
{
    saxpy_unrolled<4>( out, px, py, N, alpha ,beta);
}

当我&gt;我在第二个分支时不明白N-正* blockDim.x * gridDim.x。为什么要使用外循环

for ( int j = 0; j < n; j++ ) { for ( int j = 0; j < n; j++ )....}

我测试了这两个内核,第一个是好的,但是我从书中复制的第二个是不正确的。

我初始化了两个数组while(i<1024) a[i] = i; b[i] = 10*i;i++,我想计算c = alpha * a + beta * b使用上面的两个内核,但是循环展开的内核中的结果对于c中的所有元素都是4.3e8

这是我的测试代码:

int main(){
int arraySize = 1024;
float* a =new float[arraySize];
float* b =new float[arraySize];
float* c =new float[arraySize];
for (int i =0;i<arraySize;i++)
{
    a[i] = 1.0* i;
    b[i] = 10.0*i;
    c[i] = 0.0;
}
float* d_a;
float* d_b;
float* d_c;
cudaMalloc((void**)&d_a,sizeof(float)*arraySize);
cudaMemcpy(d_a,a,sizeof(float)*arraySize,cudaMemcpyHostToDevice);
cudaMalloc((void**)&d_b,sizeof(float)*arraySize);
cudaMemcpy(d_b,b,sizeof(float)*arraySize,cudaMemcpyHostToDevice);
cudaMalloc((void**)&d_c,sizeof(float)*arraySize);
for (int i=0;i<arraySize;i++)
{
    c[i] = a[i] + b[i];
}
dim3 block_size(256,1,1);
dim3 grid_size((arraySize -1)/block_size.x+1,1,1);
float alpha = 1.0;
float beta = 1.0;
bool flag = true;
if(flag)
{
    saxpyGPU<<<grid_size,block_size>>>(d_c,d_a,d_b,arraySize,alpha,beta);
    float* temp = new float[arraySize];
    cudaMemcpy(temp,d_c,arraySize*sizeof(float),cudaMemcpyDeviceToHost);
    for (int i = 0;i<arraySize;i++)
    {
        cout<<(temp[i] - c[i])<<",";
    }
}
else
{
    saxpyGPU2<<<grid_size,block_size>>>(d_c,d_a,d_b,arraySize,alpha,beta);
    cudaMemcpy(temp,d_c,arraySize*sizeof(float),cudaMemcpyDeviceToHost);
    for (int i = 0;i<arraySize;i++)
    {
        cout<<(temp[i] - c[i])<<",";
    }

这两个内核显示不同的结果

1 个答案:

答案 0 :(得分:2)

您发布的内核代码完全正确并产生预期结果。这可以使用以下代码演示:

#include <thrust/random.h>
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

template<const int n> 
__device__ 
void saxpy_unrolled(float *out, const float *px, const float *py, 
        size_t N, float alpha,float beta) {
    float x[n], y[n];
    size_t i;
    for ( i = n*blockIdx.x*blockDim.x+threadIdx.x; 
        i < N-n*blockDim.x*gridDim.x; 
        i += n*blockDim.x*gridDim.x ) {
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            x[j] = px[index];
            y[j] = py[index];
        }
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            out[index] = alpha*x[j]+beta* y[j];
        }
    }
    for ( int j = 0; j < n; j++ ) {
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            if ( index<N ) {
                x[j] = px[index];
                y[j] = py[index];
            }
        }
        for ( int j = 0; j < n; j++ ) {
            size_t index = i+j*blockDim.x;
            if ( index<N ) {
                out[index] = alpha*x[j] + beta*y[j];
            }
        }
    }
}

__global__ 
void saxpyGPU( float *out, const float *px, const float *py, 
        size_t N, float alpha,float beta ) {
    saxpy_unrolled<4>( out, px, py, N, alpha ,beta);
}

struct prg {
    float a, b;
    __host__ __device__
    prg(float _a=0.f, float _b=1.f) : a(_a), b(_b) {};

    __host__ __device__
    float operator()(const unsigned int n) const {
        thrust::default_random_engine rng;
        thrust::uniform_real_distribution<float> dist(a, b);
        rng.discard(n);
        return dist(rng);
    }
};

int main(void) {
    const int N = 100000;
    const float alpha = 0.12345f, beta = 0.9876f;

    prg gen(1.f, 2.f);
    thrust::device_vector<float> x(N), y(N), z(N);
    thrust::counting_iterator<unsigned int> iseqx(0);
    thrust::counting_iterator<unsigned int> iseqy(N);
    thrust::transform(iseqx, iseqx + N, x.begin(), gen);
    thrust::transform(iseqy, iseqy + N, y.begin(), gen);

    float *xp = thrust::raw_pointer_cast(&x[0]);
    float *yp = thrust::raw_pointer_cast(&y[0]);
    float *zp = thrust::raw_pointer_cast(&z[0]);
    dim3 blockdim(128);
    dim3 griddim(16);
    saxpyGPU<<<griddim, blockdim>>>(zp, xp, yp, N, alpha, beta);
    cudaDeviceSynchronize();

    std::vector<float> xh(N), yh(N), zh(N);
    thrust::copy(x.begin(), x.end(), xh.begin());
    thrust::copy(y.begin(), y.end(), yh.begin());
    thrust::copy(z.begin(), z.end(), zh.begin());

    float maxabserr = -1.f, maxrelerr = -1.f;
    for(int i=0; i<N; i++) {
        float saxpyval = alpha * xh[i] + beta * yh[i];
        float abserr = fabs(zh[i]-saxpyval);
        float relerr = abserr / fmaxf(fabs(zh[i]), fabs(saxpyval));
        maxabserr = fmaxf(abserr, maxabserr);
        maxrelerr = fmaxf(relerr, maxrelerr);
    }
    std::cout.precision(10);
    std::cout << "Maximum absolute error = " << maxabserr << std::endl;
    std::cout << "Maximum relative error = " << maxrelerr << std::endl;

    return 0;
}

给了我以下内容:

$ nvcc -arch=sm_30 -o unrolled_saxpy unrolled_saxpy.cu
$ ./unrolled_saxpy 
Maximum absolute error = 2.384185791e-07
Maximum relative error = 1.1920676e-07

如果您(仍然)不理解为什么内核按原样编写,请按照我在上一个问题中向您展示的内容并手动展开saxpy函数。从n = 1开始并确认它在功能上与展开的等效物相同,然后尝试n = 2,n = 4等,以查看循环展开的动作是什么。