两个几乎相同的OpenCL内核之间的性能差距

时间:2017-05-04 23:39:10

标签: performance opencl gpu flops

我有两个几乎相同的OpenCL内核,我想在GFLOPS中计算它们的性能。内核#1是:

__kernel void Test41(__global float *data, __global float *rands, int index, int rand_max){

    float16 temp;
    int gid = get_global_id(0);

    temp = data[gid];
    temp = (float) rands[1] * temp;
    temp = (float) rands[2] * temp;
    temp = (float) rands[3] * temp;
    temp = (float) rands[4] * temp;
    .
    .
    .
    temp = (float) rands[497] * temp;
    temp = (float) rands[498] * temp;
    temp = (float) rands[499] * temp;
    data[gid] = temp.s0;

}

第二个核心是:

__kernel void Test42(__global float *data, __global float *rands, int index, int rand_max){

    float16 temp[500];
    int gid = get_global_id(0);

    temp[0] = data[gid];
    temp[1] = (float) rands[1] * temp[0];
    temp[2] = (float) rands[2] * temp[1];
    temp[3] = (float) rands[3] * temp[2];
    temp[4] = (float) rands[4] * temp[3];
    .
    .
    .
    temp[497] = (float) rands[497] * temp[496];
    temp[498] = (float) rands[498] * temp[497];
    temp[499] = (float) rands[499] * temp[498];
    data[gid] = temp[index].s0;

}

正如您在代码中看到的那样,我使用的流大小为16.每个内核都有500行操作,其中每个操作只执行一次浮点操作。我还总共部署了大约1048576个内核,因此我将有大约1048576个工作项并行执行。

为了计算我做的翻牌:

flops = #numWorkItems(1048576) * (500) * StreamSize(16) / timeTaken;

不幸的是,对于第一个内核,我得到了1.4个TFLOP,但是对于第二个内核,我获得了38个GFLOP。我无法解释这个巨大的差距。使用temp而不是单个temp的向量似乎是一个巨大的交易。似乎真正的应用程序大多像第二个内核。第一个内核对于实际应用来说太简单了。

任何人都可以帮助我理解这里到底发生了什么以及第二个内核性能如何达到第一个?一般来说,如果我要对我的设备进行基准测试,我是否应该看到性能接近理论值?

P.S。我知道我需要将rands复制到__本地内存中,但现在让我们跳过它。

2 个答案:

答案 0 :(得分:0)

正如@pmdj在评论中建议的那样,第二个内核的主要问题是注册压力:您正在使用大量硬件寄存器,这减少了同时执行的工作组的数量。 通常,大型私有数组在OpenCL / CUDA中不是一个好主意。 在这种情况下,编译器可以做很少的事情来优化性能。 您可以为阵列使用本地内存,但是您需要添加适当的同步来访问它。

答案 1 :(得分:-1)

有两个可能的问题:

  • 您将float16临时缓冲区声明为__private {这是OpenCL中的默认值},并且很可能会在global内存空间中分配具有相当高的访问延迟。如果它适合您的设备本地内存,您可以尝试将其声明为__local float16
  • 添加temp缓冲区为编译器带来了一些问题...原始代码可以在某些GPU架构(例如英特尔)上轻松实现矢量化,并且您通过添加store + load添加了人工依赖关系

我实际上就编译器提交了一份问题报告。编译器应该很容易找出依赖关系,进行优化甚至摆脱temp缓冲区。

相关问题