0

使用 CUDA CI 有一个统计内核,当我在内核中的任何位置在 VS2012 中添加断点并将 stddev 行包含在前面的变量定义中时:

double mean, stddev, sumOfValues, sumOfValuesSquared;
unsigned int n;

// acquire greater than 0 values for: sumOfValues, sumOfValuesSquared, and n

stddev = (float)(sqrt((double)(n) * sumOfValuesSquared - (sumOfValues*sumOfValues)) / (double)(n));

断点永远不会到达,内核也不会执行。当我删除那一行时,内核就会执行。我认为它与sqrt有关,但事实并非如此。我还有一行:

mean = sumOfValues / n;

当我使用该行时,它也不会执行内核。关于 CUDA 中的类型转换,我缺少什么(这是寄存器问题,还是单精度与双精度)?

-- 更新 (10/2/2013 14:25 CST) --

我将线程数从 1 调整到 1024。第一次运行,它进入我的断点,第二次线程数高,内核不执行。请看下面的代码:

#include "stdafx.h"

#include <stdio.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>

typedef struct
{
    unsigned int value;
} ValueStruct;

__global__ void FailsToExecute(ValueStruct *vs)
{
    unsigned int numerator = vs->value;
    unsigned int denominator= 3;
    bool eject = false;

    if(denominator > 0)
    {
         if(1.0f * numerator / denominator > 17.98f)
             eject = true;
         else
             eject = false;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    ValueStruct *vsHost;
    ValueStruct *vsDevice;

    cudaMallocHost((void **)&vsHost, sizeof(ValueStruct));
    cudaMalloc((void **)&vsDevice, sizeof(ValueStruct));

    vsHost->value = 54;

    cudaMemcpy(vsDevice, vsHost, sizeof(ValueStruct), cudaMemcpyKind::cudaMemcpyHostToDevice);

    dim3 blocks(5);
    dim3 threads(1024);

    FailsToExecute<<<blocks, threads>>>(vsDevice);

    return 0;
}

我如何计算/处理寄存器边界,我对它们了解不多?

4

2 回答 2

0

需要的资源多于可用资源(例如寄存器、共享内存)的内核将不会启动。这可以通过适当的错误检查来检测,例如如下所示:

https://devtalk.nvidia.com/default/topic/545591/how-to-debug-kernel-throwing-an-exception-/?offset=16

由于每个 GPU 架构的分配粒度效应不同,因此对特定内核与特定启动配置的组合所需资源的准确计算可能并非易事。出于这个原因,我建议使用包含粒度细节的 CUDA 占用计算器。您可以在此处找到占用电子表格:

http://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls

于 2013-10-02T20:02:46.687 回答
0

nvcc 编译器是否有可能将内核优化为一无所有?查看内核函数,我可以看到如何安全地将其优化为零指令,因为它实际上没有做任何事情。

__global__ void FailsToExecute(ValueStruct *vs)
{
    unsigned int numerator = vs->value;
    unsigned int denominator= 3;
    bool eject = false;

    if(denominator > 0)
    {
         if(1.0f * numerator / denominator > 17.98f)
             eject = true;
         else
             eject = false;
    }
}

设置eject无关紧要,因为eject不再使用。所以我们可以划掉这两个任务。if() 条件中的表达式没有修改任何内容,并且由于它对 if 语句的任何一个分支都没有任何作用,因此看起来 if() 可以删除。同样继续回到内核的顶部,似乎它可以全部优化为空,并且仍然让内核产生相同的结果。

也许如果您添加某种输出,例如一个布尔数组,并将结果保存eject到该数组中,那么您会看到内核正在执行。

于 2013-10-02T21:17:50.410 回答