【问题标题】:How to allocate 16byte memory aligned data如何分配 16byte 内存对齐数据
【发布时间】:2012-06-18 13:59:59
【问题描述】:

我正在尝试在一段代码上实现 SSE 矢量化,我需要我的一维数组与 16 字节内存对齐。但是,我尝试了几种方法来分配 16 字节内存对齐的数据,但它最终是 4 字节内存对齐的。

我必须使用英特尔 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 字节对齐的,仅仅因为 printf 一次只输出 4 个字节?正因为您使用的是 memalign 例程,所以您将其放入浮点类型。当您使用 printf 打印时,它知道如何处理它的原始类型(浮点数)。
  • 为什么不能在 Linux 上使用“_mm_malloc”?

标签: c memory sse icc


【解决方案1】:

您分配的内存是 16 字节对齐的。见:
&amp;A[0] = 0x11fe010
但是在float的数组中,每个元素都是4字节,所以第二个是4字节对齐的。

您可以使用带有aligned 属性的结构数组,每个结构都包含一个浮点数:

struct x {
    float y;
} __attribute__((aligned(16)));
struct x *A = memalign(...);

【讨论】:

  • 我认为__attribute__ 是 GCC 的内置函数,不适用于 ICC。
  • @Benoit,确实是 GCC 特定的,但我认为 ICC 确实支持它。 See here
  • @Benoit:如果需要在 16 上对齐结构,只需在末尾添加 12 个字节的填充...
  • @VladLazarenko,工作,但不是很好和便携。如果在某些编译器中更改了float,您将再次出现对齐错误。
  • @ugoren:因此,您可以添加静态断言、禁用结构填充等。__attribute__((aligned(16))) 不适用于 gcc,也不能移植。
【解决方案2】:

memalign函数返回的地址是0x11fe010,是0x10的倍数。因此,该功能正在做正确的事情。这也意味着您的数组 在 16 字节边界上正确对齐。您稍后要做的是打印数组中每个 float 类型的下一个元素的地址。由于在您的情况下float 大小正好是 4 个字节,因此每个下一个地址都将等于前一个地址 +4。例如,0x11fe010 + 0x4 = 0x11FE014。当然,地址0x11FE014 不是0x10 的倍数。如果您要在 16 字节边界上对齐所有浮点数,那么您将不得不浪费每个元素 16 / 4 - 1 字节。仔细检查您正在使用的内在函数的要求。

【讨论】:

    【解决方案3】:

    AFAIK,memalignposix_memalign 都在做他们的工作。

    &A[0] = 0x11fe010
    

    这与 16 字节对齐。

    &A[1] = 0x11fe014
    

    当您执行&amp;A[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 ) );
    

    【讨论】:

      【解决方案4】:

      我在Wikipedia找到了这个代码:

      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)
      

      【讨论】:

        【解决方案5】:

        我个人认为您的代码是正确的,并且适用于英特尔 SSE 代码。当您将数据加载到 XMM 寄存器时,我相信处理器只能从主内存中加载 4 个连续的浮点数据,其中第一个以 16 字节对齐。

        总之,我相信你所做的正是你想要的。

        【讨论】:

          【解决方案6】:

          你也可以在 VS 中使用它。

          __declspec(align(16)) struct x {
              long long a;
              long long b;
              char c;
          };
          

          而不是这个

          struct x {
              float y;
          } __attribute__((aligned(16)));
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-12-29
            • 2011-11-28
            • 1970-01-01
            • 2014-02-28
            • 1970-01-01
            • 2011-12-30
            • 2012-07-08
            • 2011-04-29
            相关资源
            最近更新 更多