使用通过引用传递的参数优化OpenCL函数中的指针访问(通过指针)

时间:2017-10-24 23:07:11

标签: c++ c pointers opencl compiler-optimization

我现在尝试优化我的OpenCL代码。我使用一些指针来返回值。是否更有效地创建存储在寄存器中的临时变量(我猜至少)或者我可以直接访问指针并在整个函数中使用它们,因为它不会对性能产生任何影响,因为编译器会对此进行优化呢?

让我向您展示一个简单的盒子光线交叉的例子:

tmin和tmax存储在临时变量中:

bool intersect(const Ray* ray, float3 boxmin, float3 boxmax, float* tmin, float* tmax)
{
  float3 invR = 1.0f / ray->dir;

  float t1 = (boxmin.x - ray->origin.x) * invR.x;
  float t2 = (boxmax.x - ray->origin.x) * invR.x;
  float t3 = (boxmin.y - ray->origin.y) * invR.y;
  float t4 = (boxmax.y - ray->origin.y) * invR.y;
  float t5 = (boxmin.z - ray->origin.z) * invR.z;
  float t6 = (boxmax.z - ray->origin.z) * invR.z;

  float tmin_ = fmax(fmax(fmin(t1, t2), fmin(t3, t4)), fmin(t5, t6));
  float tmax_ = fmin(fmin(fmax(t1, t2), fmax(t3, t4)), fmax(t5, t6));

  if (tmax_ < 0)
    return false;
  if (tmin_ > tmax_)
    return false;

  *tmax = tmax_;
  *tmin = tmin_;
  return true;
}

直接访问:

bool intersect(const Ray* ray, float3 boxmin, float3 boxmax, float* tmin, float* tmax)
{
  float3 invR = 1.0f / ray->dir;

  float t1 = (boxmin.x - ray->origin.x) * invR.x;
  float t2 = (boxmax.x - ray->origin.x) * invR.x;
  float t3 = (boxmin.y - ray->origin.y) * invR.y;
  float t4 = (boxmax.y - ray->origin.y) * invR.y;
  float t5 = (boxmin.z - ray->origin.z) * invR.z;
  float t6 = (boxmax.z - ray->origin.z) * invR.z;

  *tmin = fmax(fmax(fmin(t1, t2), fmin(t3, t4)), fmin(t5, t6));
  *tmax = fmin(fmin(fmax(t1, t2), fmax(t3, t4)), fmax(t5, t6));

  if (*tmax < 0)
    return false;
  if (*tmin > *tmax)
    return false;
  return true;
}

嗯,这不是最好的例子,因为只有三个解除引用的指针,其中性能可能没有差别,但它只是在那里证明我的意思。 有没有足够深入知识的人,知道大多数OpenCL编译器在这种情况下做了什么? 了解C / C ++编译器在这种情况下会做什么也很有趣。

2 个答案:

答案 0 :(得分:1)

取决于您传递的指针的内存位置(tmaxtmin)。

  • Private:编译器可能会优化它们。
  • Local:编译器不能对它们进行优化,除非编译器清楚指针总是由组中的单个工作项指向。 (即使它可能仍然没有这样做)。在案例2中,在某些情况下可能会出现一些降级。
  • 全局:编译器永远不会优化它们,因为它无法知道全局内存是由另一个工作组甚至是CPU端更改的。在第二种情况下会有一个惩罚和额外的内存访问。

性能的最佳解决方案是第一个。您可以在私有空间中执行大部分检查,并且只在需要时访问指向内存的指针。不要担心使用额外的变量,GPU有足够的寄存器:

  float tmin_ = fmax(fmax(fmin(t1, t2), fmin(t3, t4)), fmin(t5, t6));
  float tmax_ = fmin(fmin(fmax(t1, t2), fmax(t3, t4)), fmax(t5, t6));

  if (tmax_ < 0)
    return false;
  if (tmin_ > tmax_)
    return false;

  *tmax = tmax_;
  *tmin = tmin_;

答案 1 :(得分:0)

这两个选项与任何体面的编译器之间的性能不会有任何差别。大多数OpenCL实现基于llvm,它绝对会优化诸如此类的临时性。

尽管如此,基本上唯一容易辨别的方法是计算两种选择。这始终是优化的证明,但是使用基于CPU的编译器,人们通常也可以查看汇编输出。使用OpenCL更难做到。

注意使用可以使用向量操作使这段代码更简洁。是否有助于表现是另一回事。

你也可以返回一个我认为完全避免使用指针的结构。