12

1D 配列を 16 バイトのメモリに揃える必要があるコードに SSE ベクトル化を実装しようとしています。ただし、16 バイトのメモリ アライン データを割り当てる方法をいくつか試しましたが、最終的に 4 バイトのメモリ アラインになります。

Intel icc コンパイラを使用する必要があります。これは私がテストしているサンプルコードです:

  #include <stdio.h>
  #include <stdlib.h>

  void error(char *str)
  {
   printf("Error:%s\n",str);
   exit(-1);
  }

  int main()
  {
   int i;
   //float *A=NULL;
   float *A = (float*) memalign(16,20*sizeof(float));

   //align
   // if (posix_memalign((void **)&A, 16, 20*sizeof(void*)) != 0)
   //   error("Cannot align");

    for(i = 0; i < 20; i++)
       printf("&A[%d] = %p\n",i,&A[i]);

        free(A);

         return 0;
   }

これは私が得る出力です:

 &A[0] = 0x11fe010
 &A[1] = 0x11fe014
 &A[2] = 0x11fe018
 &A[3] = 0x11fe01c
 &A[4] = 0x11fe020
 &A[5] = 0x11fe024
 &A[6] = 0x11fe028
 &A[7] = 0x11fe02c
 &A[8] = 0x11fe030
 &A[9] = 0x11fe034
 &A[10] = 0x11fe038
 &A[11] = 0x11fe03c
 &A[12] = 0x11fe040
 &A[13] = 0x11fe044
 &A[14] = 0x11fe048
 &A[15] = 0x11fe04c
 &A[16] = 0x11fe050
 &A[17] = 0x11fe054
 &A[18] = 0x11fe058
 &A[19] = 0x11fe05c

これは毎回 4 バイトにアラインされています。私は memalign と posix memalign の両方を使用しました。私は Linux で作業しているので、_mm_malloc も _aligned_malloc も使用できません。_aligned_attribute を使用しようとすると、メモリ破損エラーが発生します (gcc だけに適していると思います)。

Linuxプラットフォームでicc用の16バイトのメモリ整列データを正確に生成するのを手伝ってくれる人はいますか?

4

6 に答える 6

15

割り当てるメモリは 16 バイトでアラインされます。参照:
&A[0] = 0x11fe010
ただし、 の配列ではfloat、各要素は 4 バイトであるため、2 番目の要素は 4 バイトでアラインされます。

aligned次の属性を使用して、それぞれが 1 つの float を含む構造体の配列を使用できます。

struct x {
    float y;
} __attribute__((aligned(16)));
struct x *A = memalign(...);
于 2012-06-18T14:09:30.437 に答える
7

memalign関数によって返されるアドレスはです。0x11fe010これは の倍数です0x10。したがって、関数は正しいことをしています。これは、配列16 バイト境界に正しく配置されていることも意味します。後で行うことはfloat、配列内の型の次のすべての要素のアドレスを出力することです。このfloat場合、サイズは正確に 4 バイトであるため、次のアドレスはすべて前のアドレス +4 に等しくなります。たとえば、0x11fe010 + 0x4 = 0x11FE014. もちろん、アドレス0x11FE014は の倍数ではありません0x10。すべての float を 16 バイト境界に揃える場合、16 / 4 - 1要素ごとにバイトを浪費する必要があります。使用している組み込み関数の要件を再確認してください。

于 2012-06-18T14:11:02.157 に答える
1

memalign私の知る限り、との両方posix_memalignが仕事をしています。

&A[0] = 0x11fe010

これは 16 バイトにアラインされます。

&A[1] = 0x11fe014

これを行う&A[1]と、ポインターに 1 つの位置を追加するようにコンパイラーに指示しfloatます。それはやむを得ず次のことにつながります。

&A[0] + sizeof( float ) = 0x11fe010 + 4 = 0x11fe014

ベクター内のすべての要素を 16 バイトに揃える場合は、16 バイト幅の構造体の配列を宣言することを検討する必要があります。

struct float_16byte
{
    float data;
    float padding[ 3 ];
}
    A[ ELEMENT_COUNT ];

ELEMENT_COUNT次に、 (この例では 20 個の) 変数にメモリを割り当てる必要があります。

struct float_16byte *A = ( struct float_16byte * )memalign( 16, ELEMENT_COUNT * sizeof( struct float_16byte ) );
于 2012-06-18T14:22:01.293 に答える
0

ウィキペディアでこのコードを見つけました:

Example: get a 12bit aligned 4KBytes buffer with malloc()

// unaligned pointer to large area
void *up=malloc((1<<13)-1);
// well aligned pointer to 4KBytes
void *ap=aligntonext(up,12);

where aligntonext() is meant as: 
move p to the right until next well aligned address if
not correct already. A possible implementation is

// PSEUDOCODE assumes uint32_t p,bits; for readability
// --- not typesafe, not side-effect safe
#define alignto(p,bits) (p>>bits<<bits)
#define aligntonext(p,bits) alignto((p+(1<<bits)-1),bits)
于 2012-06-18T14:11:00.043 に答える
0

あなたのコードは正しく、Intel SSE コードに適していると個人的に信じています。データを XMM レジスタにロードする場合、プロセッサはメイン メモリから 4 つの連続する float データしかロードできないと思います。最初のデータは 16 バイトでアラインされています。

要するに、あなたがしたことはまさにあなたが望んでいることだと思います。

于 2013-10-28T01:30:25.723 に答える