当前位置 : 主页 > 网络安全 > 测试自动化 >

性能问题:单CPU内核与单CUDA内核

来源:互联网 收集:自由互联 发布时间:2021-06-22
我想比较单个Intel CPU核心的速度和单个nVidia GPU核心的速度(即:单个CUDA代码,单个线程).我确实实现了以下天真的2d图像卷积算法: void convolution_cpu(uint8_t* res, uint8_t* img, uint32_t img_width,
我想比较单个Intel CPU核心的速度和单个nVidia GPU核心的速度(即:单个CUDA代码,单个线程).我确实实现了以下天真的2d图像卷积算法:

void convolution_cpu(uint8_t* res, uint8_t* img, uint32_t img_width, uint32_t img_height, uint8_t* krl, uint32_t krl_width, uint32_t krl_height)
{
    int32_t center_x = krl_width  / 2;
    int32_t center_y = krl_height / 2;
    int32_t sum;
    int32_t fkx,fky;
    int32_t xx,yy;

    float krl_sum = 0;
    for(uint32_t i = 0; i < krl_width*krl_height; ++i)
        krl_sum += krl[i];
    float nc = 1.0f/krl_sum;

    for(int32_t y = 0; y < (int32_t)img_height; ++y)
    {
        for(int32_t x = 0; x < (int32_t)img_width; ++x)
        {
            sum = 0;

            for(int32_t ky = 0; ky < (int32_t)krl_height; ++ky)
            {
                fky = krl_height - 1 - ky;

                for(int32_t kx = 0; kx < (int32_t)krl_width; ++kx)
                {
                    fkx = krl_width - 1 - kx;

                    yy = y + (ky - center_y);
                    xx = x + (kx - center_x);

                    if( yy >= 0 && yy < (int32_t)img_height && xx >= 0 && xx < (int32_t)img_width )
                    {
                        sum += img[yy*img_width+xx]*krl[fky*krl_width+fkx];
                    }
                }
            }
            res[y*img_width+x] = sum * nc;
        }
    }
}

CPU和GPU的算法相同.我还制作了另一个GPU版本,与上面几乎相同.唯一的区别是我在使用它们之前将img和krl数组传输到共享内存.

我使用了2个尺寸为52×52的图像,我得到了以下表现:

> CPU:10ms
> GPU:1338ms
> GPU(涂抹):1165ms

CPU是Intel Xeon X5650 2.67GHz,GPU是nVidia Tesla C2070.

为什么我会有这样的性能差异?看起来单个CUDA核心对于这个特定代码来说要慢100倍!有人可以向我解释原因吗?我能想到的原因是

> CPU的频率更高
> CPU进行分支预测.
> CPU有更好的缓存机制吗?

您认为导致这种巨大性能差异的主要问题是什么?

请记住,我想比较单个CPU线程和单个GPU线程之间的速度.我不是要评估GPU的计算性能.我知道这不是在GPU上进行卷积的正确方法.

我想解释一下,可能会对你有用.

CPU acts as host and GPU acts as device.

为了在GPU上运行线程,CPU将所有数据(将在其上执行计算的计算DATA)复制到GPU.该复制时间总是大于计算时间.因为计算是在ALU-算术和逻辑单元中执行的.这只是一些说明.但复制需要更多时间.

因此,当你在CPU中只运行一个线程时,CPU将所有数据放在自己的内存中,具有缓存和分支预测,预取,微操作重新排序,L1速度提高10倍,L2速度提高10倍,能够分配6倍以上的指令每个周期,核心频率提高4.6倍.

但是当你想在GPU上运行线程时,它首先在GPU内存上复制数据.这一次需要更多时间.其次,GPU核心在一个时钟周期内运行线程网格.但为此我们需要对数据进行分区,以便每个线程都可以访问一个数组项.在您的示例中,它是img和krl数组.

还有一个可用于nvidia GPU的分析器.如果存在代码,请删除代码(例如打印输出或打印),并尝试分析您的exe.它将以毫秒为单位显示复制时间和计算时间.

循环并行化:当您使用image_width和image_height运行两个循环来计算图像时,需要执行更多的时钟周期,因为它会通过计数器执行指令级别.但是当你在GPU上移植它们时,你可以使用threadid.x和threadid.y以及16或32个线程的网格,它们只在GPU的一个核心中以一个时钟周期运行.这意味着它在一个时钟周期内计算16或32个数组项,因为它有更多的ALU.(如果没有依赖关系,数据分区很好)

在你的卷积算法中你已经在CPU中保持了循环,但是在GPU中如果你运行相同的循环而不会受益,因为GPU 1线程将再次充当CPU 1线程.还有内存缓存,内存复制,数据分区等的开销.

我希望这会让你明白……

网友评论