在查找数组的最大元素时比较 2 种不同架构上的 2 种不同场景

标签 c optimization cuda opencl gpgpu

假设我们有一个经典的场景,我们需要找到数组的最大元素(仅限整数),但不是它的位置。以下 2 个代码示例(放置在“for”循环内)中哪一个在 CPU 上运行速度更快,哪一个在 GPU 上运行速度更快,为什么?

if( array[i] > max)
  max = array[i];

max = 0.5 * ( a + b + abs(a-b));      //Where 'a' and 'b' refer to 'max' and 'array[i]'

此外,第二个代码块中真正困扰我的是“abs”函数调用。有没有办法只用算术表达式来计算一个数的绝对值?

最佳答案

我认为您确实想询问无分支与分支方式的m = max(m, array[i])。 C 编译器已根据优化设置将 if() 版本编译为无分支代码(使用 cmov)。它甚至可以自动矢量化为压缩比较或压缩最大函数。

您的 0.5 * abs() 版本显然很糟糕(比条件移动慢很多),因为它会转换为 double 并返回。而不是通过右移除以二。

查看 the Godbolt Compiler Explorer 上的 asm :

// auto-vectorizes to PMAXSD, or without SSE4.1, to pcmpgt / pand/por emulation of the same
int maxarray_if(int arr[], int n) {
  int result = arr[0];
  for (int i=0 ; i<n; ++i) {
    int tmp = arr[i];
    if (result < tmp)
      result = tmp;
  }
  return result;
}

gcc 5.3 -O3 -march=haswell -mno-avx 自动矢量化内循环:

.L13:
    add     eax, 1
    pmaxsd  xmm0, XMMWORD PTR [rdx]
    add     rdx, 16
    cmp     r8d, eax
    ja      .L13

对比。 FP 版本:

    ... whole bunch of integer crap
    cvtsi2sd        xmm0, eax
    mulsd   xmm0, xmm1
    cvttsd2si       eax, xmm0

所以 FP 版本显然完全是垃圾。

对于任何目标架构,您都会得到类似的结果。与 double 之间的转换不会消失。 gcc 即使使用 -ffast-math 也能保持它。

关于在查找数组的最大元素时比较 2 种不同架构上的 2 种不同场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37149330/

相关文章:

c - 易于使用 system() 的 fork-exec

c - C中的链表add()方法

c - 优化代码以在 c 中获得以下输出

c++ - x86汇编指令优化

python - 在 python 中运行的脚本中关闭 GPU

c++ - CUDA:在使用 cudaMallocPitch 分配的二维数组中查找数组索引

cuda - 通过brew和dmg安装cuda

C 如何将标量类型转换为非标量类型并向后转换?

c - 如何从 MPI_recv 消息中检索标签?

java - int vs long 的迭代速度