【问题标题】:How to optimize a cycle?如何优化一个循环?
【发布时间】:2011-04-28 13:42:29
【问题描述】:

我有以下瓶颈功能。

typedef unsigned char byte;
void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3)
{
     const byte b1 = 128-30;
     const byte b2 = 128+30;
     for (const byte * p1 = p1Start; p1 != p1End; ++p1, ++p2, ++p3) {
        *p3 = (*p1 < *p2 ) ? b1 : b2;
    }
}

我想用 SSE2 内部函数替换 C++ 代码。我试过_mm_cmpgt_epi8,但它使用了有符号比较。我需要无符号比较。

有什么技巧(SSE、SSE2、SSSE3)可以解决我的问题吗?

注意: 在这种情况下我不想使用多线程。

【问题讨论】:

  • 您知道您的目标处理器架构是什么吗?一次使用一个 64 位字块(位旋转以在寄存器中进行比较)可以在一定程度上减少内存总线争用。编译器的汇编代码应该有助于提供思路... ...而且 SSE 不是用于浮点运算,而不是整数运算吗?
  • SSE 有一些整数指令。
  • 为什么不让他们签名呢?在比较之前对每个元素进行简单的 XOR 0x80 即可完成这项工作。

标签: c++ optimization assembly intrinsics sse2


【解决方案1】:

是的,SSE 在这里不起作用。 您可以使用 OpenMP 在多核计算机上提高此代码性能:

void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3) { 常量字节 b1 = 128-30; 常量字节 b2 = 128+30; int n = p1End - p1Start; #pragma omp 并行 for (int i = 0; i

【讨论】:

  • @VJo - 是的,当然。在单核计算机上,此代码的执行与问题中的原始代码完全相同。
【解决方案2】:

使用 pcmpeqb 并成为你的力量。

【讨论】:

  • pcmpeqb 是对相等的检查。我需要更少的比较。
  • 啊是的。然后是 pcmpgtb。仍然使用电源。但明智的。
  • OP 需要无符号比较。
【解决方案3】:

你可以从你的数字中减去 127,然后使用 _mm_cmpgt_epi8

【讨论】:

  • 这似乎是正确的答案。但我认为你的 127 必须用 128 替换。或者用 128 异或。
  • 问题是我认为 MMX 中只有一个打包添加,这是一个完全不同的寄存器集。
【解决方案4】:

是的,这可以在 SIMD 中完成,但制作掩码需要几个步骤。

我认为,Ruslik 是对的。您想用 0x80 对每个组件进行异或,以翻转有符号和无符号比较的意义。 _mm_xor_si128 (PXOR) 让你明白——在将掩码加载到 SIMD 寄存器之前,你需要在某处将掩码创建为静态字符数组。然后 _mm_cmpgt_epi8 给你一个掩码,你可以使用按位与(例如_mm_and_si128)来执行掩码移动。

【讨论】:

    【解决方案5】:

    与其抵消您的有符号值以使其无符号,一种稍微更有效的方法是执行以下操作:

    • 使用_mm_min_epu8 获取p1、p2 的无符号最小值
    • 使用_mm_cmpeq_epi8比较这个最小值与p2是否相等
    • 对于 p1 = p2 的元素,结果掩码为 0xff
    • 您现在可以将此掩码与 _mm_or_si128_mm_andc_si128 一起使用来选择适当的 b1/b2 值

    请注意,这总共是 4 条指令,而使用偏移量 + 带符号的比较方法则为 5 条。

    【讨论】:

      【解决方案6】:

      很遗憾,上面的许多答案都不正确。让我们假设一个 3 位字:

      无符号:4 5 6 7 0 1 2 3 == 有符号:-4 -3 -2 -1 0 1 2 3(位:100 101 110 111 000 001 010 011)

      Paul R 的方法不正确。假设我们想知道 3 > 2.min(3,2) == 2,这表明是,所以该方法在这里有效。现在假设我们想知道如果 7 > 2。值 7 在有符号表示中为 -1,因此 min(-1,2) == -1,这错误地表明 7 不大于 2 无符号。

      Andrey 的方法也不正确。假设我们想知道是否 7 > 2,或者 a = 7,并且 b = 2。值 7 在有符号表示中为 -1,因此第一项 (a > b) 失败,并且该方法表明 7 不大于大于 2。

      但是,经过 Alexey 纠正的 BJobnh 的方法是正确的。只需从值中减去 2^(n-1),其中 n 是位数。在这种情况下,我们将减去 4 以获得新的对应值:

      旧签名:-4 -3 -2 -1 0 1 2 3 => 新签名:0 1 2 3 -4 -3 -2 -1 == 新未签名 0 1 2 3 4 5 6 7。

      换句话说,unsigned_greater_than(a,b) 等价于signed_greater_than(a - 2^(n-1), b - 2^(n-1))。

      【讨论】:

      • 如果您仔细查看我的回答,您会发现我正在使用 unsigned min 操作。
      猜你喜欢
      • 2011-12-08
      • 2011-05-30
      • 1970-01-01
      • 2019-03-21
      • 1970-01-01
      • 2011-06-15
      • 1970-01-01
      • 2022-11-03
      相关资源
      最近更新 更多