首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >减少数据自动化系统

减少数据自动化系统
EN

Stack Overflow用户
提问于 2013-12-02 08:57:49
回答 2查看 2.3K关注 0票数 2

我才刚开始学习CUDA编程,我对裁减有一些困惑。

我知道与共享内存相比,全局内存具有很大的访问延迟,但我是否可以使用全局内存来(至少)模拟类似共享内存的行为?

例如,我想对长度恰好为BLOCK_SIZE * THREAD_SIZE的大型数组的元素进行求和(网格和块的大小都是2的幂),我尝试使用以下代码:

代码语言:javascript
复制
    __global__ void parallelSum(unsigned int* array) {

    unsigned int totalThreadsNum = gridDim.x * blockDim.x;
    unsigned int idx = blockDim.x * blockIdx.x + threadIdx.x;

    int i = totalThreadsNum / 2;
    while (i != 0) {
            if (idx < i) {
                array[idx] += array[idx + i];
        }
        __syncthreads();
        i /= 2;
    }
}

我比较了这段代码的结果和主机上连续生成的结果,奇怪的是:有时结果是相同的,但有时它们显然是不同的。这里有使用全局内存的原因吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-12-02 10:44:32

你最好的选择是从数据自动化系统样本中的约简实例开始。扫描实例还有助于学习吞吐量体系结构上的并行计算原理。

也就是说,如果您实际上只想在代码中使用减缩操作符,那么您应该查看推力 (来自主机、跨平台的调用)和幼崽 (CUDA专用的)。

看看你的具体问题:

  • 您没有理由不能使用全局内存来减少,工具箱中的示例代码经过不同级别的优化,但在每种情况下,数据都是从全局内存开始的。
  • 您的代码效率低下(有关工作效率的更多细节,请参见工具箱中的示例)。
  • 您的代码试图在没有适当同步的情况下在不同块中的线程之间进行通信;__syncthreads()只同步特定块内的线程,而不是跨不同块同步线程(至少在一般情况下,这是不可能的,因为您倾向于过订阅GPU,这意味着不是所有块都会在给定的时间运行)。

最后一点是最重要的。如果块X中的线程希望读取块Y编写的数据,那么您需要在两个内核启动过程中打破这一点,这就是为什么典型的并行还原采用多阶段方法:在块内减少批处理,然后在批间减少。

票数 4
EN

Stack Overflow用户

发布于 2015-08-08 21:37:10

汤姆已经回答了这个问题。在他的回答中,他建议使用推力幼崽来减少数据自动化系统。

在这里,我提供了一个充分发挥作用的例子,说明如何使用这两个库来执行缩减。

代码语言:javascript
复制
#define CUB_STDERR

#include <stdio.h>

#include <thrust/device_ptr.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>

#include <cub/device/device_reduce.cuh>

#include "TimingGPU.cuh"
#include "Utilities.cuh"

using namespace cub;

/********/
/* MAIN */
/********/
int main() {

    const int N = 8388608;

    gpuErrchk(cudaFree(0));

    float *h_data       = (float *)malloc(N * sizeof(float));
    float h_result = 0.f;

    for (int i=0; i<N; i++) {
        h_data[i] = 3.f;
        h_result = h_result + h_data[i];
    }

    TimingGPU timerGPU;

    float *d_data;          gpuErrchk(cudaMalloc((void**)&d_data, N * sizeof(float)));
    gpuErrchk(cudaMemcpy(d_data, h_data, N * sizeof(float), cudaMemcpyHostToDevice));

    /**********/
    /* THRUST */
    /**********/
    timerGPU.StartCounter();
    thrust::device_ptr<float> wrapped_ptr = thrust::device_pointer_cast(d_data);
    float h_result1 = thrust::reduce(wrapped_ptr, wrapped_ptr + N);
    printf("Timing for Thrust = %f\n", timerGPU.GetCounter());

    /*******/
    /* CUB */
    /*******/
    timerGPU.StartCounter();
    float           *h_result2 = (float *)malloc(sizeof(float));
    float           *d_result2; gpuErrchk(cudaMalloc((void**)&d_result2, sizeof(float)));
    void            *d_temp_storage = NULL;
    size_t          temp_storage_bytes = 0;

    DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, d_data, d_result2, N);
    gpuErrchk(cudaMalloc((void**)&d_temp_storage, temp_storage_bytes));
    DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, d_data, d_result2, N);

    gpuErrchk(cudaMemcpy(h_result2, d_result2, sizeof(float), cudaMemcpyDeviceToHost));

    printf("Timing for CUB = %f\n", timerGPU.GetCounter());

    printf("Results:\n");
    printf("Exact: %f\n", h_result);
    printf("Thrust: %f\n", h_result1);
    printf("CUB: %f\n", h_result2[0]);

}

请注意,由于不同的基本理念,CUB可以比推力更快一些,因为CUB会留下性能关键的细节,例如算法的准确选择和并发性的不受约束的程度以及用户手中的并发性。通过这种方式,可以对这些参数进行调优,以便最大限度地提高特定体系结构和应用程序的性能。

在行动中的幼崽-使用CUB模板库的一些简单示例上给出了计算阵列欧氏范数的比较。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20324277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档