2012-06-18 12 views
11

Estoy tratando de implementar la vectorización de SSE en un fragmento de código para el que necesito que mi matriz 1D esté alineada con 16 bytes de memoria. Sin embargo, he intentado varias maneras de asignar datos alineados en 16 bytes de memoria, pero termina siendo de 4 bytes de memoria alineada.Cómo asignar datos de memoria de 16 bytes

Tengo que trabajar con el compilador Intel icc. Este es un ejemplo de código que estoy probando con:

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

Ésta es la salida me sale:

&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 

Se 4byte alineado cada vez, he utilizado tanto memalign, memalign POSIX. Como estoy trabajando en Linux, no puedo usar _mm_malloc ni puedo usar _aligned_malloc. Aparece un error de corrupción de memoria cuando intento usar _aligned_attribute (que es adecuado solo para gcc).

¿Alguien me puede ayudar en la generación precisa de datos alineados de memoria de 16bytes para icc en la plataforma de Linux.

+0

¿Cómo sabes que está alineado en 4 bytes, simplemente porque printf solo está produciendo 4 bytes a la vez? Solo porque está usando la rutina de memalign, la está poniendo en un tipo de flotador. Cuando imprime utilizando printf, sabe cómo procesar a través de su tipo primitivo (float). – trumpetlicks

+1

¿Por qué no puedes usar "_mm_malloc" en Linux? –

Respuesta

14

La memoria que asigna está alineada en 16 bytes. Ver:
&A[0] = 0x11fe010
Pero en una matriz de float, cada elemento tiene 4 bytes, por lo que el segundo está alineado con 4 bytes.

Se puede utilizar una gran variedad de estructuras, cada uno con un solo flotador, con el atributo aligned:

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

Creo que '__attribute__' es un built-in de GCC, no disponible para ICC. – Benoit

+0

@Benoit, específicamente GCC, pero creo que ICC sí lo admite. [Consulte aquí] (http://software.intel.com/sites/products/collateral/hpc/compilers/intel_linux_compiler_compatibility_with_gnu_compilers.pdf) – ugoren

+0

@Benoit: si necesita alinear una estructura en 16, solo agregue 12 bytes de relleno en al final ... –

0

me encontré con este código en 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) 
7

La dirección devuelta por memalign función es 0x11fe010, que es un múltiplo de 0x10. Entonces la función está haciendo lo correcto. Esto también significa que su matriz es correctamente alineada en un límite de 16 bytes. Lo que está haciendo más tarde es imprimir una dirección de cada elemento siguiente del tipo float en su matriz. Dado que el tamaño de float es exactamente 4 bytes en su caso, cada dirección siguiente será igual a la anterior +4. Por ejemplo, 0x11fe010 + 0x4 = 0x11FE014. Por supuesto, la dirección 0x11FE014 no es un múltiplo de 0x10. Si tuviera que alinear todos los flotadores en el límite de 16 bytes, entonces tendrá que perder 16/4 - 1 bytes por elemento. Verifique dos veces los requisitos de las características intrínsecas que está utilizando.

1

AFAIK, tanto memalign como posix_memalign están haciendo su trabajo.

&A[0] = 0x11fe010 

Esto está alineado con 16 byte.

&A[1] = 0x11fe014 

Al hacer &A[1] le está diciendo al compiller para agregar una posición a un puntero float. Que inevitablemente conducirá a:

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

Si la intención de tener cada elemento dentro de su vector alineado a 16 bytes, se debe considerar que se declara una matriz de estructuras que son de 16 bytes de ancho.

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

A continuación, debe asignar memoria para ELEMENT_COUNT (20, en su ejemplo) variables:

struct float_16byte *A = (struct float_16byte *)memalign(16, ELEMENT_COUNT * sizeof(struct float_16byte)); 
0

personalmente creo que su código es correcto y es conveniente para el código de Intel SSE. Cuando carga datos en un registro XMM, creo que el procesador solo puede cargar 4 datos de flotación contiguos desde la memoria principal con el primero alineado por 16 bytes.

En resumen, creo que lo que ha hecho es exactamente lo que quiere.

Cuestiones relacionadas