2010-10-21 31 views
6

我有以下瓶颈功能。如何优化周期?

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++代码。我试过​​,但它使用了有符号比较。我需要无符号比较。

是否有任何技巧(SSE,SSE2,SSSE3)来解决我的问题?

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

+0

你知道你的目标是哪个处理器架构吗?一次处理一个64位字块(在寄存器中进行比较)可以在一定程度上减少内存总线争用。编译器的汇编代码应该有助于提供想法... ...并不是SSE专门用于浮点,而不是整数操作? – 2010-10-21 11:58:44

+0

SSE有一些整数指令。 – Crashworks 2010-10-21 11:59:15

+1

为什么不让他们签名?一个简单的异或0x80与比较前的每个元素都可以完成这项工作。 – ruslik 2010-10-21 12:01:27

回答

9

相反抵消你的符号值,使他们无符号的,稍微更有效的方法是做到以下几点:

  • 使用_mm_min_epu8拿到P1的无符号分钟,P2
  • 比较这分钟用于使用_mm_cmpeq_epi8
  • 与P2平等所得掩模现在为0x00的元件,其中,P1 < p2和0xff的其中的元件,其中,P1> P2 =
  • 现在可以使用这个掩模_mm_or_si128_mm_andc_si128选择适当的B1/B2值

注意,这是4个指令中总,与使用偏移+签署比较法相比5。

1

是的,上证所不会在这里工作。 您可以通过使用OpenMP提高多核计算机上的代码性能:

 
void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3) 
{ 
    const byte b1 = 128-30; 
    const byte b2 = 128+30; 

    int n = p1End - p1Start; 
    #pragma omp parallel for 
    for (int i = 0; i < n; ++p1, ++i) 
    { 
     p3[i] = (p1[i] < p2[i]) ? b1 : b2; 
    } 
} 
+3

这不适用于单核或单CPU – 2010-10-21 12:05:32

+0

@ VJo - 当然可以。在单核心计算机上,此代码完全像问题中的原始代码一样执行。 – 2010-10-21 12:09:16

+1

@VJo它会工作,但不会给予任何提振 – Andrey 2010-10-21 12:56:17

-3

使用PCMPEQB并成为Power和你在一起。

+1

'pcmpeqb'是一个平等的检查。我需要较少的比较。 – 2010-10-21 12:11:21

+0

啊是的。然后pcmpgtb。仍然使用电源。但明智。 – 2010-10-21 12:16:52

+2

OP需要无符号比较。 – 2010-10-21 12:47:21

2

你可以从你的号码减去127,然后用_mm_cmpgt_epi8

+2

这似乎是正确的答案。但我认为你的127必须用128代替。或者用128代换xor。 – 2010-10-21 12:22:22

+0

问题是我认为在MMX中只有一个压缩添加,它完全是一个不同的寄存器集合。 – Crashworks 2010-10-21 12:23:17

+0

是的,你是对的。 128,而不是127 – 2010-10-21 12:42:50

2

是的,这可以在SIMD完成,但它会采取一些措施,使蒙版。

Ruslik说得没错,我想。你想用0x80对每个组件进行异或处理,以翻转有符号和无符号比较的意义。 _mm_xor_si128(PXOR)可以解决这个问题 - 在将其加载到SIMD寄存器之前,您需要将掩码创建为静态字符数组。然后_mm_cmpgt_epi8为您提供一个掩码,您可以使用按位与(例如_mm_and_si128)来执行屏蔽移动。

-1

不幸的是,上面的许多答案都是不正确的。我们假设一个3位字:

unsigned:4 5 6 7 0 1 2 3 == signed:-4 -3 -2 -1 0 1 2 3(bits: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。

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

旧有符号:-4 -3 -2 -1 0 1 2 3 =>新有符号:0 1 2 3 -4 -3 -2 -1 == new unsigned 0 1 2 3 4 5 6 7.

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

+0

如果你仔细看看我的答案,你会看到我使用* unsigned * min操作。 – 2015-11-20 11:14:17