8

次のようなものを想定します。

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];
  }
}

次のように書くことで、アラインされていないアクセス マシン (x86 など) で高速化できます。

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;
  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
}

しかし、アラインメントを指定するコンパイラ定義のマクロ (上記の私の仮説のようなもの__ALIGNED4__) や、ターゲット アーキテクチャのアラインメントを決定するためにプリプロセッサを使用する巧妙な方法に関する良い情報を見つけることができません。をテストすることもできますが、アライメントされたメモリアクセスを必要とする他のアーキテクチャでJust Work TMdefined (__SVR4) && defined (__sun)を実行できるものを好むでしょう。

4

3 に答える 3

6

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命令を見てください。

于 2011-12-07T16:03:07.563 に答える
2

標準的なアプローチはconfigure、アライメントの問題をテストするプログラムを実行するスクリプトを用意することです。テストプログラムがクラッシュしない場合、configureスクリプトは、生成されたconfigヘッダーにマクロを定義し、より高速な実装を可能にします。より安全な実装がデフォルトです。

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
}
于 2011-12-07T16:04:35.357 に答える
1

(私はあなたが持っているのは奇妙だと思います.srcそしてmask、本当にこれらの通勤時間.私はに名前を変更mask_bytesしましたmemand.しかしとにかく...)

別のオプションは、C の型を利用するさまざまな関数を使用することです。たとえば、次のようになります。

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];
}

このようにして、プログラマーに決定させます。

于 2011-12-07T16:53:16.243 に答える