2010-10-21 80 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