CUDA 并行加速基础之 Reduce 和 Scan 的实现

GPU加速求和算法
本文介绍了如何利用GPU的并行性来加速求和运算,详细解释了Reduce和Scan两种并行算法的原理,并提供了CUDA实现代码。

前言

我们知道硬件拥有其独特的并行性,为了发挥这一特色。我们要将平时串行执行的程序用并行性算法重新改写才能充分发挥 GPU 的优势。

实例:做求和:1+2+3+4+···

为了做这样一个累加和的加速,有两种简单的实现方法,分别是 Redece 进行归约(二分),或者是用 Scan 通过控制步长进行扫描求和。

Reduce

在这里插入图片描述
如上图所示为了并行执行累加,我们要构造出一些线程,每个线程并行工作,从而达到加速的目的。在这里插入图片描述
Reduce 的原理如上图所示。我们构建1024个线程块,每个线程块中含有1024个线程,每个block中的线程(每次迭代只有上次迭代一半的线程数)并行的去计算求和。

求和规则是:每次迭代中左半边的线程分别加上右半边的线程分配得到的数,即只有一半的线程在工作,如此循环往复,最终0号线程得到的结果就是该线程块所有数的和。最后再运行最后一个线程块,将之前得到的线程块和当作输入数据,进行最后一次并行计算,从而得到最终和。

实现代码如下,通过两种访存方式进行实现:

#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>

__global__ void global_reduce_kernel(float * d_out, float * d_in)
{
   
   
    int myId = threadIdx.x + blockDim.x * blockIdx.x;
    int tid  = threadIdx.x;

    // do reduction in global mem
    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1)
    {
   
   
        if (tid < s)
        {
   
   
            d_in[myId] += d_in[myId + s];
        }
        __syncthreads();        // make sure all adds at one stage are done!
    }

    // only thread 0 writes result for this block back to global mem
    if (tid == 0)
    {
   
   
        d_out[blockIdx.x] = d_in[myId];
    }
}

__global__ void shmem_reduce_kernel(float * d_out, const float * d_in)
{
   
   
    // sdata is allocated in the kernel call: 3rd arg to <<<b, t, shmem>>>
    extern __shared__ float sdata[];

    int myId = threadIdx.x + blockDim.x * blockIdx.x;
    int tid  = threadIdx.x;

    // load shared mem from global mem
    sdata[tid] = d_in[myId];
    __syncthreads();            // make sure entire block is loaded!

    // do reduction in shared mem
    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1)
    {
   
   
        if (tid < s)
        {
   
   
            sdata[tid] += sdata[tid + s];
        }
        __syncthreads();        // make sure all adds at one stage are done!
    }

    // only thread 0 writes result for this block back to global mem
    if (tid == 0)
    {
   
   
        d_out[blockIdx.x] = sdata[0];
    }
}

void reduce(float * d_out, float * d_intermediate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangbowj123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值