2017-01-23 180 views
1

我有一段代碼,在〜每秒120萬個運行執行一些任務後運行時,體積最大的是來自兩個數據uint32_t的片設置與bitshifted數據的uint8_t陣列。摘錄代碼如下:優化位位移入陣列

static inline uint32_t RotateRight(uint32_t val, int n) 
{ 
    return (val >> n) + (val << (32 - n)); 

} 

static inline uint32_t CSUInt32BE(const uint8_t *b) 
{ 
    return ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3]; 
} 

static uint32_t ReverseBits(uint32_t val) // Usually just static, tried inline/static inline 
{ 
    // uint32_t res = 0; 
    // for (int i = 0; i<32; i++) 
    // { 
    //  res <<= 1; 
    //  res |= val & 1; 
    //  val >>= 1; 
    // } 
    // Original code above, benched ~220k l/s 

    //val = ((val & 0x55555555) << 1) | ((val >> 1) & 0x55555555); 
    //val = ((val & 0x33333333) << 2) | ((val >> 2) & 0x33333333); 
    //val = ((val & 0x0F0F0F0F) << 4) | ((val >> 4) & 0x0F0F0F0F); 
    //val = ((val & 0x00FF00FF) << 8) | ((val >> 8) & 0x00FF00FF); 
    //val = (val << 16) | (val >> 16); 
    // Option 0, benched ~770k on MBP 

    uint32_t c = 0; 
    c = (BitReverseTable256[val & 0xff] << 24) | 
     (BitReverseTable256[(val >> 8) & 0xff] << 16) | 
     (BitReverseTable256[(val >> 16) & 0xff] << 8) | 
     (BitReverseTable256[val >> 24]); // was (val >> 24) & 0xff 
             // Option 1, benched ~970k l/s on MBP, Current, minor tweak to 24 

             //unsigned char * p = (unsigned char *)&val; 
             //unsigned char * q = (unsigned char *)&c; 
             //q[3] = BitReverseTable256[p[0]]; 
             //q[2] = BitReverseTable256[p[1]]; 
             //q[1] = BitReverseTable256[p[2]]; 
             //q[0] = BitReverseTable256[p[3]]; 
             // Option 2 at ~970k l/s on MBP from http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c 


    return c; // Current 
       // return val; // option 0 
       // return res; // original 


       //uint32_t m; 
       //val = (val >> 16) | (val << 16);       // swap halfwords 
       //m = 0x00ff00ff; val = ((val >> 8) & m) | ((val << 8) & ~m); // swap bytes 
       //m = m^(m << 4); val = ((val >> 4) & m) | ((val << 4) & ~m); // swap nibbles 
       //m = m^(m << 2); val = ((val >> 2) & m) | ((val << 2) & ~m); 
       //m = m^(m << 1); val = ((val >> 1) & m) | ((val << 1) & ~m); 
       //return val; 
       // Benches at 850k l/s on MBP 

       //uint32_t t; 
       //val = (val << 15) | (val >> 17); 
       //t = (val^(val >> 10)) & 0x003f801f; 
       //val = (t + (t << 10))^val; 
       //t = (val^(val >> 4)) & 0x0e038421; 
       //val = (t + (t << 4))^val; 
       //t = (val^(val >> 2)) & 0x22488842; 
       //val = (t + (t << 2))^val; 
       //return val; 
       // Benches at 820k l/s on MBP 
} 
static void StuffItDESCrypt(uint8_t data[8], StuffItDESKeySchedule *ks, BOOL enc) 
{ 
uint32_t left = ReverseBits(CSUInt32BE(&data[0])); 
uint32_t right = ReverseBits(CSUInt32BE(&data[4])); 

right = RotateRight(right, 29); 
left = RotateRight(left, 29); 

//Encryption function runs here 

left = RotateRight(left, 3); 
right = RotateRight(right, 3); 

uint32_t left1 = ReverseBits(left); 
uint32_t right1 = ReverseBits(right); 

data[0] = right1 >> 24; 
data[1] = (right1 >> 16) & 0xff; 
data[2] = (right1 >> 8) & 0xff; 
data[3] = right1 & 0xff; 
data[4] = left1 >> 24; 
data[5] = (left1 >> 16) & 0xff; 
data[6] = (left1 >> 8) & 0xff; 
data[7] = left1 & 0xff; 

這是完成這一任務的最優化的方式?我有一個uint64_t中的版本,以及:

uint64_t both = ((uint64_t)ReverseBits(left) << 32) | (uint64_t)ReverseBits(right); 

data[0] = (both >> 24 & 0xff); 
data[1] = (both >> 16) & 0xff; 
data[2] = (both >> 8) & 0xff; 
data[3] = both & 0xff; 
data[4] = (both >> 56); 
data[5] = (both >> 48) & 0xff; 
data[6] = (both >> 40) & 0xff; 
data[7] = (both >> 32) & 0xff; 

我測試過,如果我完全跳過這個任務會發生什麼(在ReverseBits功能仍然完成),代碼運行在每秒〜650萬組的運行。另外,如果我只做一個,就會發生這種速度命中,即使沒有觸及其他7個任務,也會達到120萬。

我討厭認爲這一操作需要一個巨大的80%的速度,由於打這個工作,不能作出任何更快。

這是Windows的Visual Studio 2015年(雖然我儘量保持源作爲移植到MacOS和Linux作爲可能的)。

編輯:完整的基本代碼是Github。我不是代碼的原始作者,但是我已經分叉它並使用修改後的速度版本來維護密碼恢復解決方案。您可以通過各種解決方案和平臺速度看到我在ReverseBits中取得的成功。

這些文件已超過20年之久,並且已成功恢復文件,儘管速度很慢,多年以來一直保持不變。見blog post

+0

我們無法回答提出的問題。 「最優化」至少在某種程度上取決於您所提供的代碼片段的上下文以及您使用的C實現。然而,如果你提出[mcve],那麼我們至少可以提出一些嘗試的建議。 –

+0

發佈您的所有定義。剩下什麼? ReverseBits正在做什麼?等等 –

+0

什麼數據類型是'data []'?它是字節還是無符號字符? –

回答

3

您當然做了比您需要做的更多的工作。請注意函數ReverseBits()如何將正確順序的反向字的字節放在一起,以及發生的下一個事件(您將歸因於放慢的部分)如何重新排序這些相同的字節。

您可以編寫並使用ReverseBits()的修改版本,將反轉表示的字節直接放入數組的正確位置,而不是將它們打包成整數,只是爲了再次打開它們。這應該至少快一點,因爲你會嚴格刪除操作。

+0

予製備的改性ReverseBits這樣 '靜態內嵌無效ReverseBits_direct(uint8_t * B,uint64_t中VAL) { \t B [0] =(BitReverseTable256 [VAL&0xff的]); \t b [1] =(BitReverseTable256 [(val >> 8&0xff)]); \t b [2] =(BitReverseTable256 [(val >> 16&0xff)]); \t b [3] =(BitReverseTable256 [(val >> 24&0xff)]); \t b [4] =(BitReverseTable256 [(val >> 32&0xff)]); \t b [5] =(BitReverseTable256 [(val >> 40&0xff)]); \t b [6] =(BitReverseTable256 [(val >> 48&0xff)]); \t b [7] =(BitReverseTable256 [(val >> 56)]); }' 我想說速度已經增加到1.3Mil(而且代碼肯定更清晰) –

+0

@GregEsposito,我不能說我驚訝於增強功能相對較小。說實話,我發現你的相對錶現可疑;如果在陣列中記錄更新的數據的成本與您(認爲您已經測試過)的成本相當,那麼可能會有更微妙的影響,例如緩存使用的有效性。事實上,你可能會發現,你觀察到的加速很大程度上來自於不必將修改後的數據寫回主內存,因此感知到的改進機會是虛幻的。 –

+0

是的,通過評論整個功能,它是每個600萬,但只有一個設置它的1.2-1.3百萬(以1米,10米,100米,10億次的線/秒計數)。我完全可以相信,只是觸及數據而不是運行數據,這種衝擊就來了。我現在的目標是將數據類型轉移到uint64並採用其他方式優化代碼庫。考慮到我在雙Xeon X5365處理器上,有些技術我無法利用,但有很多內核可以投入使用。 –

0

我立即想到的是「觀點」的int32_t,如果他們的int8_t

uint8_t data2[8]; 
*((uint32_t*)&data2[0]) = right1; 
*((uint32_t*)&data2[4]) = left1; 

但是一個數組,你的right1最顯著位存儲在data[0],而這種做法讓至少顯著位轉到data[0]。無論如何,因爲我不知道什麼ReverseBits做什麼,並且您是否也可以根據不同的順序調整您的代碼,也許這有助於...

+0

如果這產生了正確的結果,那麼這將是值得一試。不幸的是,它不會在小端平臺上這樣做,比如所有那些MSVC運行的平臺上,因爲字節以big-endian順序記錄在「data」中。 –