Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >多个并行裁减有时失败。

多个并行裁减有时失败。
EN

Stack Overflow用户
提问于 2015-04-27 13:41:50
回答 1查看 924关注 0票数 0

我有以下问题。我已经实现了几种不同的并行约简算法,如果我只减少每个内核一个值,那么所有这些算法都能正常工作。但是现在我需要减少几个(21),我只是不知道为什么它有时工作,有时不工作。

执行的步骤如下:

  • 计算每个线程的相关值(在本例中,我只是将它们设置为1,因为它显示的是相同的行为)
  • 将它们加载到共享内存中
  • 同步块内的线程
  • 减少共享内存中的值

这里是完整的代码,您可以只需cpy&pst并运行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <cuda_runtime.h>

// switch the compiler flag if you don't have the sdk's helper_cuda.h file
#if 1
#include "helper_cuda.h"
#else
#define checkCudaErrors(val) (val)
#define getLastCudaError(msg)
#endif

#ifdef __CDT_PARSER__
#define __global__
#define __device__
#define __shared__
#define __host__
#endif

// compute sum of val over num threads
__device__ float localSum(const float& val, volatile float* reductionSpace, const uint& localId)
{
    reductionSpace[localId] = val;  // load data into shared mem
    __syncthreads();

    // complete loop unroll
    if (localId < 128) reductionSpace[localId] += reductionSpace[localId + 128];
    __syncthreads();

    if (localId < 64) reductionSpace[localId] += reductionSpace[localId + 64];
    __syncthreads();

    // within one warp (=32 threads) instructions are SIMD synchronous
    // -> __syncthreads() not needed
    if (localId < 32)
    {
        reductionSpace[localId] += reductionSpace[localId + 32];
        reductionSpace[localId] += reductionSpace[localId + 16];
        reductionSpace[localId] += reductionSpace[localId + 8];
        reductionSpace[localId] += reductionSpace[localId + 4];
        reductionSpace[localId] += reductionSpace[localId + 2];
        reductionSpace[localId] += reductionSpace[localId + 1];
    }

    ## Edit: Here we need to sync in order to guarantee that the thread with ID 0 is also done... ##
    __syncthreads();

    return reductionSpace[0];
}

__global__ void d_kernel(float* od, int n)
{
    extern __shared__ float reductionSpace[];
    int g_idx = blockIdx.x * blockDim.x + threadIdx.x;
    const unsigned int linId = threadIdx.x;
    __shared__ float partialSums[21];

    float tmp[6] =
    { 0, 0, 0, 0, 0, 0 };

    // for simplification all computations are remove - this version still shows the same behaviour
    if (g_idx < n)
    {
        tmp[0] = 1.0f;
        tmp[1] = 1.0f;
        tmp[2] = 1.0f;
        tmp[3] = 1.0f;
        tmp[4] = 1.0f;
        tmp[5] = 1.0f;
    }

    float res = 0.0f;
    int c = 0;
    for (int i = 0; i < 6; ++i)
    {
        for (int j = i; j < 6; ++j, ++c)
        {
            res = tmp[i] * tmp[j];
            // compute the sum of the values res for blockDim.x threads. This uses
            // the shared memory reductionSpace for calculations
            partialSums[c] = localSum(res, reductionSpace, linId);

        }
    }
    __syncthreads();

    // write back the sum values for this block
    if (linId < 21)
    {
        atomicAdd(&od[linId], partialSums[linId]);
    }
}

int main()
{
    int w = 320;
    int h = 240;
    int n = w * h;

    // ------------------------------------------------------------------------------------
    float *d_out;
    checkCudaErrors(cudaMalloc(&d_out, 21 * sizeof(float)));
    float* h_out = new float[21];

    int dimBlock = 256;
    int dimGrid = (n - 1) / dimBlock + 1;
    int sharedMemSize = dimBlock * sizeof(float);

    printf("w: %d\n", w);
    printf("h: %d\n", h);
    printf("dimBlock: %d\n", dimBlock);
    printf("dimGrid: %d\n", dimGrid);
    printf("sharedMemSize: %d\n", sharedMemSize);

    int failcounter = 0;
    float target = (float) n;
    int c = 0;
    // ------------------------------------------------------------------------------------

    // run the kernel for 200 times
    for (int run = 0; run < 200; ++run)
    {
        cudaMemset(d_out, 0, 21 * sizeof(float));
        d_kernel<<<dimGrid, dimBlock, sharedMemSize>>>(d_out, n);;
        getLastCudaError("d_kernel");

        checkCudaErrors(cudaMemcpy(h_out, d_out, 21 * sizeof(float), cudaMemcpyDeviceToHost));

        // check if the output has target value
        // since all threads get value 1 the kernel output corresponds to counting the elements which is w*h=n
        bool failed = false;
        for (int i = 0; i < 21; ++i)
        {
            if (abs(h_out[i] - target) > 0.01f)
            {
                ++failcounter;
                failed = true;
            }
        }

        // if failed, print the elements to show which one failed
        if (failed)
        {
            c = 0;
            for (int i = 0; i < 6; ++i)
            {
                for (int j = i; j < 6; ++j, ++c)
                {
                    printf("%10.7f ", h_out[c]);
                }
                printf("\n");
            }
        }
    }

    printf("failcounter: %d\n", failcounter);

    // ------------------------------------------------------------------------------------
    delete[] h_out;
    checkCudaErrors(cudaFree(d_out));
    // ------------------------------------------------------------------------------------

    return 0;
}

一些评论:

BlockSize总是256,因此localSum()中的展开循环检查正确的threadIds。正如前面提到的,在200次运行中,有时是完全正确的,有时只有2个值是错误的,有时大约有150个值是错误的。

而且它不需要有浮点精度,因为只有1x1被乘以并存储在d_kernel()中的变量res中。我可以清楚地看到,有时只是一些线程或块没有开始,但我不知道为什么。:/

从结果来看,很明显存在某种种族状况,但我根本看不出问题所在。

有人知道问题出在哪里吗?

编辑:

我现在测试了很多东西,我发现它必须用BlockSize来做一些事情。如果我将其简化为smth <=64并相应地更改localSum(),那么一切都按照预期的方式工作。

但这对我来说毫无意义?!在这里,我仍然只做一个普通的共享内存的并行还原,唯一的区别就是我每个线程做了21次。

编辑2:

现在我完全糊涂了。问题正在展开循环!!或更好的说法是同步了经纱。以下localSum()代码工作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// compute sum of val over num threads
__device__ float localSum(const float& val, volatile float* reductionSpace, const uint& localId)
{
    reductionSpace[localId] = val;  // load data into shared mem
    __syncthreads();

    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1)
    {
        if (localId < s)
        {
            reductionSpace[localId] += reductionSpace[localId + s];
        }

        __syncthreads();
    }

    return reductionSpace[0];
}

但是,如果我展开最后一个翘曲,并且在线程之间不同步,有时我会再次得到类似于2000次运行中的2或3个错误结果。因此,下面的代码会使不运行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// compute sum of val over num threads
__device__ float localSum(const float& val, volatile float* reductionSpace, const uint& localId)
{
    reductionSpace[localId] = val;  // load data into shared mem
    __syncthreads();

    for (unsigned int s = blockDim.x / 2; s > 32; s >>= 1)
    {
        if (localId < s)
        {
            reductionSpace[localId] += reductionSpace[localId + s];
        }

        __syncthreads();
    }

    if (localId < 32)
    {
        reductionSpace[localId] += reductionSpace[localId + 32];
        reductionSpace[localId] += reductionSpace[localId + 16];
        reductionSpace[localId] += reductionSpace[localId + 8];
        reductionSpace[localId] += reductionSpace[localId + 4];
        reductionSpace[localId] += reductionSpace[localId + 2];
        reductionSpace[localId] += reductionSpace[localId + 1];
    }

    return reductionSpace[0];
}

但是,既然CUDA同时执行一个翘曲(32个线程)而不需要__syncthreads(),这又有什么意义呢?!

我不需要有人把我的工作代码在这里,但我真的要求一个有丰富的经验和丰富的知识,在CUDA编程描述我这里的根本问题。或者至少给我个提示。

EN

回答 1

Stack Overflow用户

发布于 2015-05-01 02:44:28

解决办法太简单了,我几乎羞于告诉它。我眼花缭乱,四处张望,却没有看到最明显的代码。在localSum()中的返回语句之前缺少一个简单的localSum()。Bc最后一次弯曲本身是同时执行的,但不能保证使用threadID 0的那个已经完成.这是个愚蠢的错误,我只是没看到。

抱歉给你添麻烦了..。:)

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

https://stackoverflow.com/questions/29906486

复制
相关文章
为什么我不建议你用 Select * ?
应用程序慢如牛,原因多多,可能是网络的原因、可能是系统架构的原因,还有可能是数据库的原因。
JavaFish
2019/10/17
1.7K0
为什么我不建议你写注释?
实际上,注释最多也就是一种必须的恶。若编程语言足够有表达力,或者我们擅长于用这些语言来表达意图,就不那么需要注释了,甚至也许根本不需要。 注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败,我用了失败一词,其实是说真的。注释总是一种失败,是因为我们无法找到不用注释就能表达这段代码含义的方法。 如果你发现你的代码需要写注释,那么你就应该想想是不是有办法翻盘,用代码来表达。并不是不让你真的不用注释,而是有些时候,用注释是因为我们怕其他的开发者在我们的代码的时候,看不懂我们的代码从而去加注释,那么我们为什么不写出其他开发者一目了然的代码呢?
用户7386338
2020/05/29
1.2K0
我为什么不建议使用框架默认的 DefaultMeterObservationHandler
最近,我们升级了 SpringBoot 3.x,并且,升级后,我们全面改造了原来的 Sleuth 以及 Micrometer 监控,最新的 io.micrometer.observation.Observation 抽象将链路追踪以及指标监控(opentracing 和 opentelemetry 两个标准)结合,这样,我们就可以在链路追踪中,同时记录指标监控数据了。
干货满满张哈希
2024/05/25
1460
我为什么不建议使用框架默认的 DefaultMeterObservationHandler
为什么我的自动化流程不执行
很多人经常会有这个问题,为什么我的自动化流程不执行。如果你设置好了自动化流程,但是自动化流程却没有执行,请按照如下的顺序检查你的流程配置:
阿那个沫
2022/11/08
1.5K0
为什么我的自动化流程不执行
为什么我不建议自研BI系统?
互联网的本质之一是信息共享,而共享的背后是各种原子粒度的数据流动。有以内容生产和内容消费匹配为目的的数据流动,比如搜索引擎;也有以人、货、场信息匹配为目的的数据流动,比如电商平台。
IT阅读排行榜
2023/02/13
7650
为什么我不建议自研BI系统?
为什么我不建议你用 if-else ?
程序员想必都经历过这样的场景:刚开始自己写的代码很简洁,逻辑清晰,函数精简,没有一个 if-else,可随着代码逻辑不断完善和业务的瞬息万变:比如需要对入参进行类型和值进行判断;这里要判断下对象是否为 null;不同类型执行不同的流程。
开发者技术前线
2020/11/23
2.1K0
为什么我不建议你用 if-else ?
活久见,为什么SHOW TABLE STATUS总是不更新
前几天,QQ群里在讨论一个关于MySQL表统计信息迟迟不更新的问题。 这个问题我复现了,下面是详细过程:
老叶茶馆
2020/06/24
2.1K0
DNS 系列(一):为什么更新了 DNS 记录不生效?
我们在上网时如果想要访问到另一台机器上的内容,通常只需要直接输入一串地址,就能够准确访问到自己想要访问的网站。但是实际上这只是方便我们记忆的字符形式网络标识,真正让我们的机器和另一台机器进行沟通的是 IP 地址。只不过 IP 地址无论是输入还是记忆都非常麻烦,因此才诞生了域名系统。那么域名是怎么连接到那个服务器的 IP 呢?这就和我们今天要说的域名系统 DNS 有关了。
用户9996356
2022/08/25
4.8K1
我为什么不建议你使用Python3.7.3?
之前使用Python的环境一直是Python3.7.3的,一直使用的很正常,没有什么毛病,直到最近做一个图片下载器的时候发现了问题。
云爬虫技术研究笔记
2019/11/05
2.1K0
我为什么不建议你使用Python3.7.3?
Python 为什么没有 main 函数?为什么我不推荐写 main 函数?
毫无疑问 Python 中没有所谓的 main 入口函数,但是网上经常看到一些文章提“Python 的 main 函数”、“建议写 main 函数”……
Python猫
2020/06/04
2.5K0
JAVA要死了吗?不!我来告诉你为什么!
我们看到“Java 死了吗?” 这个问题,年年都被抛出来,然而至今为止,从所有的第三方统计来看,Java 不仅活的很好,还在保持增长。虽然不断有新的语言面世,TIOBE 仍将 Java 评选为 2015 年度最热门语言,目前显示它相比 2014 年,用户增加了 5%,高于其他所有编程语言。
哲洛不闹
2018/09/14
7860
JAVA要死了吗?不!我来告诉你为什么!
为什么我不建议你通过 Python 去找工作?
这是读者“前进一点”在微信上问我的一个问题,我当时给他的回复是“Python 挺火的,学 Python 就好。”但当我在 B 站上看了羊哥的一期视频后,深感懊悔,觉得自己给出的建议是不负责任的。
黄啊码
2022/06/20
2.8K0
为什么我不建议你使用Java序列化
如今大部分的后端服务都是基于微服务架构实现的,服务按照业务划分被拆分,实现了服务的解耦,同时也带来了一些新的问题,比如不同业务之间的通信需要通过接口实现调用。两个服务之间要共享一个数据对象,就需要从对象转换成二进制流,通过网络传输,传送到对方服务,再转换成对象,供服务方法调用。这个编码和解码的过程我们称之为序列化和反序列化。
故里
2020/11/25
2K0
为什么我不建议你使用Java序列化
为什么我不建议你通过 Python 去找工作?
这是读者“前进一点”在微信上问我的一个问题,我当时给他的回复是“Python 挺火的,学 Python 就好。”但当我在 B 站上看了羊哥的一期视频后,深感懊悔,觉得自己给出的建议是不负责任的。
沉默王二
2020/05/26
2.7K0
为什么我不建议你用去 “ ! = null " 做判空?
最终,项目中会存在大量判空代码,多么丑陋繁冗!如何避免这种情况?我们是否滥用了判空呢?
用户9239674
2022/01/22
1K0
为什么我把 Run 出来的 Apk 发给老板,却装不上!
当我们在 Android Studio 中,直接 Run 一个项目时,AS 会自动打一个 Debug 的 Apk,并通过 ADB 命令,将 App 安装到我们连接的设备上。
CCCruch
2019/07/31
2.7K0
为什么我把 Run 出来的 Apk 发给老板,却装不上!
为什么我把 Run 出来的 Apk 发给老板,却装不上!
当我们在 Android Studio 中,直接 Run 一个项目时,AS 会自动打一个 Debug 的 Apk,并通过 ADB 命令,将 App 安装到我们连接的设备上。
Android技术干货分享
2019/08/01
2.7K0
996的程序员们,为什么我不建议你买保险?
所以在医院,我们经常能看到,很多病人明明有医治的方案,却因为没有钱,只能眼睁睁地看着他离去。
Java团长
2019/08/22
2.8K0
996的程序员们,为什么我不建议你买保险?
Pandas我这个填充nan值为什么填充不上呢?
前几天在Python钻石交流群【逆光】问了一个Python数据处理的问题,问题如下:请问一下,我这个填充nan值为什么填充不上呢
Python进阶者
2024/07/08
1220
Pandas我这个填充nan值为什么填充不上呢?
为什么我的数据不按顺序排序原来如此 | Java Debug 笔记
啵啵肠
2023/11/29
3270

相似问题

ntp什么时候更新时间?

10

如何阻止NTP更新系统时钟?

10

为什么CentOS没有NTP漂移文件?

10

在CentOS上将ntp更新为4.2.8p13

20

奇怪的NTP流量

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文