2012-06-18 2 views
11

16 바이트 메모리를 정렬하려면 1D 배열이 필요한 코드 조각에 SSE 벡터화를 구현하려고합니다. 그러나, 나는 16byte 메모리 정렬 된 데이터를 할당하는 몇 가지 방법을 시도했지만 4byte 메모리가 정렬되게된다.16 바이트 메모리 정렬 된 데이터를 할당하는 방법

Intel icc 컴파일러를 사용해야합니다.

&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을을 사용하고 있습니다 :

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

이 내가 얻을 출력은 다음과 같습니다 이것은 내가 함께 테스트입니다 샘플 코드입니다. 리눅스에서 작업 할 때 _mm_malloc을 사용할 수없고 _aligned_malloc을 사용할 수 없습니다. _aligned_attribute를 사용하려고 할 때 메모리 손상 오류가 발생합니다 (gcc 만 사용할 때 적합합니다).

누구든지 Linux 플랫폼에서 icc 용으로 16 바이트 메모리 정렬 데이터를 정확하게 생성하는 데 도움을 줄 수 있습니까?

+0

printf가 한 번에 4 바이트 만 출력하기 때문에 4 바이트 정렬이라는 것을 어떻게 알 수 있습니까? 그냥 memalign 루틴을 사용하기 때문에, 당신은 그것을 플로트 타입으로 넣을 것입니다. printf를 사용하여 인쇄 할 때 원시 타입 (float)을 처리하는 방법을 알고 있습니다. – trumpetlicks

+1

Linux에서 "_mm_malloc"을 사용할 수없는 이유는 무엇입니까? –

답변

14

할당하는 메모리는 16 바이트로 정렬됩니다. 참조 :
&A[0] = 0x11fe010
float의 배열에서 각 요소는 4 바이트이므로 두 번째 바이트는 4 바이트로 정렬됩니다.

당신은 구조체의 배열을 사용할 수 있습니다

aligned 속성으로, 하나의 플로트를 포함하는 각 :

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

'__attribute__'는 GCC의 내장 함수이며 ICC에서는 사용할 수 없습니다. – Benoit

+0

@Benoit, 실제로 GCC와 관련이 있지만 ICC가 지원한다고 생각합니다. [See here] (http://software.intel.com/sites/products/collateral/hpc/compilers/intel_linux_compiler_compatibility_with_gnu_compilers.pdf) – ugoren

+0

@Benoit : 16에 구조체를 정렬해야하는 경우에는 12 바이트의 패딩을 추가하면됩니다. 끝 ... –

0

나는 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

memalign에 의해 반환 된 주소를 함수는 0x11fe010이며, 이는 0x10의 배수입니다. 그래서 함수는 올바른 일을합니다. 이는 또한 배열 이 16 바이트 경계에서 올바르게 정렬되었음을 의미합니다. 나중에 수행하는 작업은 어레이에있는 float 유형의 모든 요소의 주소를 인쇄하는 것입니다. 귀하의 경우에 float 크기가 정확히 4 바이트이므로 모든 다음 주소는 이전 주소 +4와 같습니다. 예 : 0x11fe010 + 0x4 = 0x11FE014. 물론 0x11FE014 주소는 0x10의 배수가 아닙니다. 모든 플로트를 16 바이트 경계에 맞추려면 요소 당 16/4 - 1 바이트를 낭비해야합니다. 사용중인 내장 함수에 대한 요구 사항을 다시 확인하십시오.

1

AFAIK, memalignposix_memalign 모두 해당 작업을 수행하고 있습니다.

&A[0] = 0x11fe010 

이것은 16 바이트로 정렬됩니다.

&A[1] = 0x11fe014 

당신이 &A[1]

당신은 float 포인터를 하나 개의 위치를 ​​추가 할 compiller을 말하고있다.

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

당신이 당신의 벡터 내부 모든 요소는 16 바이트로 정렬하도록하려는 경우에는 16 바이트 넓은 구조의 배열을 선언 고려해야합니다 :에 그것은 불가피하게 이어질 것입니다.

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

그럼 당신은 변수를합니다 (예 : 20) ELEMENT_COUNT에 대한 메모리를 할당해야합니다

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

나는 개인적으로 코드가 정확하고 인텔 SSE 코드에 적합하다 생각합니다. XMM 레지스터에 데이터를로드 할 때, 프로세서는 주 메모리에서 4 개의 연속 플로트 데이터를로드 할 수 있으며 첫 번째는 16 바이트로 정렬됩니다.

간단히 말해서, 내가 한 일은 당신이 원하는 것입니다.