programing

정렬된 메모리를 얻을 수 있는 최고의 크로스 플랫폼 방법

codeshow 2023. 10. 4. 23:03
반응형

정렬된 메모리를 얻을 수 있는 최고의 크로스 플랫폼 방법

여기 내가 Visual Studio와 GCC와 메모리를 정렬할 때 사용하는 코드가 있습니다.

inline void* aligned_malloc(size_t size, size_t align) {
    void *result;
    #ifdef _MSC_VER 
    result = _aligned_malloc(size, align);
    #else 
     if(posix_memalign(&result, align, size)) result = 0;
    #endif
    return result;
}

inline void aligned_free(void *ptr) {
    #ifdef _MSC_VER 
        _aligned_free(ptr);
    #else 
      free(ptr);
    #endif

}

이 코드는 일반적으로 괜찮습니까?나는 또한 사람들이 사용하는 것을 본 적이 있습니다._mm_malloc,_mm_free. 대부분의 경우에는 SSE/AVX를 사용해야 합니다.그 기능들을 일반적으로 사용할 수 있습니까?그러면 내 코드가 훨씬 간단해질 겁니다.

마지막으로, 메모리 정렬을 위한 나만의 기능을 쉽게 만들 수 있습니다(아래 참조).정렬된 메모리를 얻을 수 있는 다양한 공통 기능(많은 기능이 하나의 플랫폼에서만 작동함)은 왜 이렇게 많습니까?

이 코드는 16바이트 정렬을 합니다.

float* array = (float*)malloc(SIZE*sizeof(float)+15);

// find the aligned position
// and use this pointer to read or write data into array
float* alignedArray = (float*)(((unsigned long)array + 15) & (~0x0F));

// dellocate memory original "array", NOT alignedArray
free(array);
array = alignedArray = 0;

참조: http://www.songho.ca/misc/alignment/dataalign.html 및 표준 라이브러리를 사용해서만 정렬된 메모리를 할당하는 방법은 무엇입니까?

편집 : 신경쓰는 분이 계실까봐 아이겐(Eigen/src/Core/util/Memory.h)에서 aligned_malloc() 기능 아이디어를 얻었습니다.

편집: 방금 발견했습니다.posix_memalignMinGW에 대해 정의되지 않았습니다.하지만,_mm_malloc는 Visual Studio 2012, GCC, MinGW 및 Intel C++ 컴파일러에서 작동하므로 일반적으로 가장 편리한 솔루션인 것 같습니다.또한 자체적으로 사용해야 합니다._mm_free함수, 일부 구현에서 포인터를 전달할 수 있지만_mm_malloc정석대로free/delete.

특수 기능을 호출해서 프리를 해도 괜찮기만 하면 접근 방법은 괜찮습니다.난 당신의 것을 할겁니다.#ifdefs는 반대로 표준별 옵션에서 시작하여 플랫폼별 옵션으로 돌아갑니다.예를들면

  1. 한다면__STDC_VERSION__ >= 201112L사용하다aligned_alloc.
  2. 한다면_POSIX_VERSION >= 200112L사용하다posix_memalign.
  3. 한다면_MSC_VER정의되어 있습니다. Windows 항목을 사용합니다.
  4. ...
  5. 만약 다른 모든 것이 실패한다면, 그냥 사용하세요.malloc/freeSSE/AVX 코드를 비활성화합니다.

할당된 포인터를 에 전달하려면 문제가 더 어렵습니다.free; 이는 모든 표준 인터페이스에서 유효하지만 Windows에서는 유효하지 않으며 레거시의 경우에도 유효하지 않습니다.memalign일부 유닉스 계열 시스템이 가지고 있는 기능입니다.

당신이 제안하는 첫번째 기능은 확실히 잘 작동할 것입니다.

"홈브루" 기능도 작동하지만, 값이 이미 정렬되어 있으면 15바이트만 낭비한다는 단점이 있습니다.때로는 문제가 되지 않을 수도 있지만, OS가 낭비 없이 올바르게 할당된 메모리를 제공할 수 있는 것은 당연합니다. 또한 256바이트 또는 4096바이트로 정렬해야 하는 경우 "alignment-1"바이트를 추가함으로써 많은 메모리를 낭비할 위험이 있습니다.

다음은 user2093113의 샘플을 수정한 것으로, 직접 코드가 나를 위해 만들어지지 않았습니다(void* unknown size).또한 연산자 new/delete보다 우선하는 템플릿 클래스에 추가하여 할당 및 호출 배치를 새로 할 필요가 없습니다.

#include <memory>

template<std::size_t Alignment>
class Aligned
{
public:
    void* operator new(std::size_t size)
    {
        std::size_t space = size + (Alignment - 1);
        void *ptr = malloc(space + sizeof(void*));
        void *original_ptr = ptr;

        char *ptr_bytes = static_cast<char*>(ptr);
        ptr_bytes += sizeof(void*);
        ptr = static_cast<void*>(ptr_bytes);

        ptr = std::align(Alignment, size, ptr, space);

        ptr_bytes = static_cast<char*>(ptr);
        ptr_bytes -= sizeof(void*);
        std::memcpy(ptr_bytes, &original_ptr, sizeof(void*));

        return ptr;
    }

    void operator delete(void* ptr)
    {
        char *ptr_bytes = static_cast<char*>(ptr);
        ptr_bytes -= sizeof(void*);

        void *original_ptr;
        std::memcpy(&original_ptr, ptr_bytes, sizeof(void*));

        std::free(original_ptr);
    }
};

다음과 같이 사용합니다.

class Camera : public Aligned<16>
{
};

아직 이 코드의 교차 플랫폼성을 테스트하지 않았습니다.

만약 당신이 컴파일러를 지원한다면, C++11은 다음을 추가합니다.std::align런타임 포인터 정렬을 수행하는 함수입니다.다음과 같이 자신만의 malloc/free를 구현할 수 있습니다(테스트되지 않음).

template<std::size_t Align>
void *aligned_malloc(std::size_t size)
{
    std::size_t space = size + (Align - 1);
    void *ptr = malloc(space + sizeof(void*));
    void *original_ptr = ptr;

    char *ptr_bytes = static_cast<char*>(ptr);
    ptr_bytes += sizeof(void*);
    ptr = static_cast<void*>(ptr_bytes);

    ptr = std::align(Align, size, ptr, space);

    ptr_bytes = static_cast<void*>(ptr);
    ptr_bytes -= sizeof(void*);
    std::memcpy(ptr_bytes, original_ptr, sizeof(void*));

    return ptr;
}

void aligned_free(void* ptr)
{
    void *ptr_bytes = static_cast<void*>(ptr);
    ptr_bytes -= sizeof(void*);

    void *original_ptr;
    std::memcpy(&original_ptr, ptr_bytes, sizeof(void*));

    std::free(original_ptr);
}

그러면 원래 포인터 값을 비워둘 필요가 없습니다.이것이 100% 휴대용인지는 확실하지 않지만, 만약 그렇지 않다면 누군가 나를 고쳐주길 바랍니다!

여기 제 2센트입니다.

temp = new unsigned char*[num];
AlignedBuffers = new unsigned char*[num];
for (int i = 0; i<num; i++)
{
    temp[i] = new  unsigned char[bufferSize +15];
    AlignedBuffers[i] = reinterpret_cast<unsigned char*>((reinterpret_cast<size_t>
                        (temp[i% num]) + 15) & ~15);// 16 bit alignment in preperation for SSE
}

언급URL : https://stackoverflow.com/questions/16376942/best-cross-platform-method-to-get-aligned-memory

반응형