2011-12-07 43 views
7

假設是這樣的:是否有標準的宏來檢測需要對齊內存訪問的體系結構?

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len) 
{ 
    unsigned int i; 
    unsigned int wordlen = len >> 2; 
    for(i=0; i<wordlen; i++) 
    { 
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; // this raises SIGBUS on SPARC and other archs that require aligned access. 
    } 
    for(i=wordlen<<2; i<len; i++){ 
    dest[i] = src[i] & mask[i]; 
    } 
} 

但是它需要建立在幾個架構,所以我:

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len) 
{ 
    unsigned int i; 
    for(i=0; i<len; i++) 
    { 
    dest[i] = src[i] & mask[i]; 
    } 
} 

我可以寫的東西,比如去更快不結盟接入設備(如86)上想要做這樣的事情:

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len) 
{ 
    unsigned int i; 
    unsigned int wordlen = len >> 2; 

#if defined(__ALIGNED2__) || defined(__ALIGNED4__) || defined(__ALIGNED8__) 
    // go slow 
    for(i=0; i<len; i++) 
    { 
    dest[i] = src[i] & mask[i]; 
    } 
#else 
    // go fast 
    for(i=0; i<wordlen; i++) 
    { 
    // the following line will raise SIGBUS on SPARC and other archs that require aligned access. 
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; 
    } 
    for(i=wordlen<<2; i<len; i++){ 
    dest[i] = src[i] & mask[i]; 
    } 
#endif 
} 

但我找不到任何關於編譯器定義的宏的好信息(如我的假設上面的)指定了對齊或使用預處理器來確定目標架構對齊的任何聰明方式。我只能測試defined (__SVR4) && defined (__sun),但我更喜歡的東西只是工作 TM其他架構需要對齊內存訪問。

+1

CPU使額外的週期得到未對齊的數據並將其移入正確的位置。通常情況下,這會明顯慢於對齊獲取。您應該總是嘗試讀取對齊的... – DipSwitch

+0

就像我一直在使用無法進行交叉對齊副本的系統一樣工作,以至於我剛剛假設存在正常和「快速」副本。 –

+0

不幸的是,這是在一個庫中,我無法控制這個庫的用戶如何對齊他們發送給我的緩衝區。 – nolandda

回答

5

儘管x86靜靜地修復了未對齊的訪問,但這對性能來說並不是最佳選擇。通常最好是假定一定的對齊方式並自行執行修正:

unsigned int const alignment = 8; /* or 16, or sizeof(long) */ 

void memcpy(char *dst, char const *src, unsigned int size) { 
    if((((intptr_t)dst) % alignment) != (((intptr_t)src) % alignment)) { 
     /* no common alignment, copy as bytes or shift around */ 
    } else { 
     if(((intptr_t)dst) % alignment) { 
      /* copy bytes at the beginning */ 
     } 
     /* copy words in the middle */ 
     if(((intptr_t)dst + size) % alignment) { 
      /* copy bytes at the end */ 
     } 
    } 
} 

另請參閱SIMD指令。

+0

基於OP在'for'循環之外定義'i',我擔心他沒有C99或'intptr_t'。 –

+0

即使沒有C99,我見過的每個類似unix的系統在'inttypes.h'中有'intptr_t'多少年了......我認爲這不是問題。 –

+0

和西蒙+1,即使在「允許」未對齊訪問的拱形上也能最佳地解決問題。但將「對齊」變爲一個變量而不是一個常量可能是一個壞主意。 –

2

標準方法是使用運行程序的configure腳本來測試對齊問題。如果測試程序沒有崩潰,配置腳本將在生成的配置頭文件中定義一個宏,以實現更快的實現。更安全的實施是默認的。

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len) 
{ 
    unsigned int i; 
    unsigned int wordlen = len >> 2; 

#if defined(UNALIGNED) 
    // go fast 
    for(i=0; i<wordlen; i++) 
    { 
    // the following line will raise SIGBUS on SPARC and other archs that require aligned access. 
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; 
    } 
    for(i=wordlen<<2; i<len; i++){ 
    dest[i] = src[i] & mask[i]; 
    } 
#else 
    // go slow 
    for(i=0; i<len; i++) 
    { 
    dest[i] = src[i] & mask[i]; 
    } 
#endif 
} 
1

(我覺得很奇怪,你有srcmask時候,確實這些上下班。我改名mask_bytesmemand。但不管怎麼說...)

另一種選擇是使用利用的不同功能例如:

void memand_bytes(char *dest, char *src1, char *src2, size_t len) 
{ 
    unsigned int i; 
    for (i = 0; i < len; i++) 
     dest[i] = src1[i] & src2[i]; 
} 

void memand_ints(int *dest, int *src1, int *src2, size_t len) 
{ 
    unsigned int i; 
    for (i = 0; i < len; i++) 
     dest[i] = src1[i] & src2[i]; 
} 

這樣你讓程序員決定。

相關問題