programing

posix_memalign/memalign의 기능

goodsources 2022. 7. 26. 23:44
반응형

posix_memalign/memalign의 기능

어떤 기능이 있는지 이해하려고 합니다.memalign()그리고.posix_memalign()사용 가능한 문서를 읽는 것은 도움이 되지 않았습니다.

어떻게 작동하는지, 어떤 용도로 사용하는지 누가 좀 알려주시겠어요?또는 사용 예를 제시해 주십시오.

Linux 메모리의 구조를 이해하려고 합니다만, 독자적인 심플한 메모리 풀(저 플래그멘테이션 힙)을 쓸 필요가 있습니다.

반면에.malloc는, 얼라인먼트를 가질 수 있는 메모리 청크를 제공합니다(유일한 요건은 실장이 서포트하는 가장 큰 프리미티브 타입으로 얼라인먼트를 할 필요가 있습니다).posix_memalign는 요청된 정렬이 보장되는 메모리 청크를 제공합니다.

그 결과, 예를 들어 posix_memalign(&p, 32, 128)는 128바이트의 메모리 청크로 시작 주소가 32의 배수임을 보증합니다.

이것은, 특정의 얼라인먼트에 준거한 메모리가 필요한 다양한 저레벨 조작(SSE 명령(DMA) 사용 등)에 도움이 됩니다.

Oli의 답변과 더불어 더 중요한 문제를 지적하고 싶습니다.

최근의 x86 아키텍처에서는 메모리에서 캐시로 가져올 수 있는 최소 데이터 양인 캐시 라인은 64바이트입니다.구조 크기가 56바이트라고 가정하면 대규모 배열이 있습니다.하나의 요소를 조회할 때 CPU는 2개의 메모리 요청을 발행해야 합니다(캐시라인 중간에 있는 경우에도 2개의 요청을 발행할 수 있습니다).이는 메모리를 기다려야 하고 캐시를 더 많이 사용하기 때문에 성능에 좋지 않습니다. 따라서 결과적으로 캐시 누락 비율이 높아집니다.이 경우 posix_memalign을 사용하는 것만으로는 충분하지 않지만 64바이트 경계에 맞게 구조를 패딩하거나 압축해야 합니다.

40 바이트의 구조를 가지는 것은 불운에 지나지 않습니다.

malloc는 항상 모든 원시 유형에 필요한 최대 정렬로 설정된 메모리를 반환합니다.이렇게 하면malloc필요한 모든 유형의 메모리를 저장할 수 있습니다.설명에 대한 나의 이해posix_memalign는, 얼라인먼트로 지정한 주소의 배수가 되는 메모리 위치를 반환하는 것입니다.

커스텀 메모리 풀을 쓸 때 이것이 얼마나 도움이 될지는 잘 모르겠습니다만, 실장 방법의 예를 제시해 보았습니다.다른 점은 이 예와 같습니다.malloc_aligned로워야 합니다.free_aligned,에서는posix_memalign 하면 .free.

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

void *malloc_aligned(size_t alignment, size_t bytes)
{
    // we need to allocate enough storage for the requested bytes, some 
    // book-keeping (to store the location returned by malloc) and some extra
    // padding to allow us to find an aligned byte.  im not entirely sure if 
    // 2 * alignment is enough here, its just a guess.
    const size_t total_size = bytes + (2 * alignment) + sizeof(size_t);

    // use malloc to allocate the memory.
    char *data = malloc(sizeof(char) * total_size);

    if (data)
    {
        // store the original start of the malloc'd data.
        const void * const data_start = data;

        // dedicate enough space to the book-keeping.
        data += sizeof(size_t);

        // find a memory location with correct alignment.  the alignment minus 
        // the remainder of this mod operation is how many bytes forward we need 
        // to move to find an aligned byte.
        const size_t offset = alignment - (((size_t)data) % alignment);

        // set data to the aligned memory.
        data += offset;

        // write the book-keeping.
        size_t *book_keeping = (size_t*)(data - sizeof(size_t));
        *book_keeping = (size_t)data_start;
    }

    return data;
}

void free_aligned(void *raw_data)
{
    if (raw_data)
    {
        char *data = raw_data;

        // we have to assume this memory was allocated with malloc_aligned.  
        // this means the sizeof(size_t) bytes before data are the book-keeping 
        // which points to the location we need to pass to free.
        data -= sizeof(size_t);

        // set data to the location stored in book-keeping.
        data = (char*)(*((size_t*)data));

        // free the memory.
        free(data);
    }
}

int main()
{
    char *ptr = malloc_aligned(7, 100);

    printf("is 5 byte aligned = %s\n", (((size_t)ptr) % 5) ? "no" : "yes");
    printf("is 7 byte aligned = %s\n", (((size_t)ptr) % 7) ? "no" : "yes");

    free_aligned(ptr);

    return 0;
}

GNU C에서 posix_memalign을 사용하는 경우 두 번째 파라미터는 2의 거듭제곱일 뿐만 아니라 size of(void*)의 배수여야 합니다.이 요건은 memalign 기능의 요건과는 다릅니다.memalign 기능은 2의 전력만을 필요로 합니다.

int
__posix_memalign (void **memptr, size_t alignment, size_t size)
{
  void *mem;

  /* Test whether the SIZE argument is valid.  It must be a power of
     two multiple of sizeof (void *).  */
  if (alignment % sizeof (void *) != 0
      || !powerof2 (alignment / sizeof (void *))
      || alignment == 0)
    return EINVAL;


  void *address = RETURN_ADDRESS (0);
  mem = _mid_memalign (alignment, size, address);

  if (mem != NULL)
    {
      *memptr = mem;
      return 0;
    }

  return ENOMEM;
}
weak_alias (__posix_memalign, posix_memalign) 

posix_memalign 구현의 첫 번째 if 조건을 보면 정렬이 size of(void*)의 배수인지 여부를 확인합니다.

어떻게 동작하는지는 구현에 따라 다릅니다.이 함수의 목적은 n바이트 정렬된 메모리 블록을 제공하는 것입니다(블록의 시작 주소는 n의 배수입니다).

memalign은 사용되지 않기 때문에(참조: man 페이지), 여기서는 malloc()와 posix_memalign()의 차이만 설명합니다.malloc()는 8바이트 정렬(RHEL 32비트의 경우 등)이지만, posix_memalign()의 경우 정렬은 사용자가 정의할 수 있습니다.이 사용법을 알기 위해서는 mprotect()를 사용하여 메모리 속성을 설정하는 것이 좋습니다.mprotect()를 사용하려면 메모리 포인터가 PAGE 정렬되어 있어야 합니다.따라서 posix_memalign()을 호출하고 페이지 크기를 정렬하면 반환된 포인터는 쉽게 mprotect()로 전송하여 읽기/쓰기 실행 가능 속성을 설정할 수 있습니다.(예를 들어 데이터를 메모리 포인터에 복사한 후 데이터를 읽기 전용 속성으로 설정하여 수정하지 않도록 할 수 있습니다)."contrac()"의 반환된 포인터는 여기서 사용할 수 없습니다.

언급URL : https://stackoverflow.com/questions/6563120/what-does-posix-memalign-memalign-do

반응형