これは、VisualStudioと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を使用します。これらの機能を一般的に使用できますか?それは私のコードをずっと簡単にするでしょう。
最後に、メモリを整列させる独自の関数を簡単に作成できます(以下を参照)。では、なぜ、アラインされたメモリを取得するための非常に多くの異なる共通関数があるのでしょうか(その多くは1つのプラットフォームでのみ機能します)。
このコードは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(Eigen/src/Core/util/Memory.h)からaligned_malloc()関数のアイデアを得ました
編集:私はposix_memalign
がMinGWに対して未定義であることを発見しました。ただし、_mm_malloc
はVisualStudio 2012、GCC、MinGW、およびIntel C++コンパイラで機能するため、一般的に最も便利なソリューションのようです。また、独自の_mm_free
関数を使用する必要がありますが、一部の実装では、_mm_malloc
から標準のfree
/delete
にポインターを渡すことができます。
あなたが提案する最初の関数は確かにうまくいくでしょう。
「自作」関数も機能しますが、値がすでに整列されている場合、15バイトを無駄にしているという欠点があります。時々問題にならないかもしれませんが、OSは無駄なく正しく割り当てられたメモリを提供できる可能性があります(256バイトまたは4096バイトに整列する必要がある場合は、「alignment-1」を追加することで大量のメモリを浪費するリスクがありますバイト)。
解放を行うために特別な関数を呼び出さなければならないことに問題がない限り、アプローチは問題ありません。ただし、#ifdef
sは逆の方法で行います。標準で指定されたオプションから始めて、プラットフォーム固有のオプションにフォールバックします。例えば
__STDC_VERSION__ >= 201112L
の場合はaligned_alloc
を使用します。_POSIX_VERSION >= 200112L
の場合はposix_memalign
を使用します。_MSC_VER
が定義されている場合は、Windowsのものを使用してください。malloc
/free
を使用して、SSE/AVXコードを無効にします。割り当てられたポインタをfree
に渡すことができるようにしたい場合、問題はより困難になります。これはすべての標準インターフェースで有効ですが、Windowsでは有効ではなく、一部のUNIXライクなシステムにある従来のmemalign
関数では必ずしも有効ではありません。
これはuser2093113のサンプルの修正であり、直接コードは私のためにビルドされませんでした(void *不明なサイズ)。また、演算子new/deleteをオーバーライドするテンプレートクラスに配置したので、割り当てを行ったり、placementnewを呼び出す必要はありません。
#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
}