するあらゆる側面を含んでいます場合はメモリーが揃う?
-
19-09-2019 - |
質問
これまでの最適化コードSSE/SSE2の指とまでしていません。私の知る共通のSSEを最適化した機能のようになります:
void sse_func(const float* const ptr, int len){
if( ptr is aligned )
{
for( ... ){
// unroll loop by 4 or 2 elements
}
for( ....){
// handle the rest
// (non-optimized code)
}
} else {
for( ....){
// regular C code to handle non-aligned memory
}
}
}
しかし、どうやってくるかどうかを判断するメモリ ptr
ポイントにアライメントなど16バイト?と思いなどの通常のCコードのパスにあった非メモリとしているすべてのメモリ内の機能が揃います。のintrinsicsへの負荷データからunalignedメモリの信用格レジスタが恐ろしい遅いもより遅くな通常のCコードとします。
よろしくお願いし...
解決
EDIT:long
にキャストするには、int型と、今日、異なるサイズであること、ポインタの最も可能性が高い可能性に対して自分自身を保護するための安価な方法です。
以下のコメントで指摘したように、より良い解決策があるあなたは、ヘッダーを含めることを喜んでいる場合...
ポインタp
は、16バイト境界IFFの((unsigned long)p & 15) == 0
上に整列されている。
他のヒント
#define is_aligned(POINTER, BYTE_COUNT) \
(((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
のキャスト void *
(equivalenty, char *
が必要で、標準のみ保証可逆変換を uintptr_t
のための void *
.
だいたいタイプの安全使用を考慮するインライン機能:
static inline _Bool is_aligned(const void *restrict pointer, size_t byte_count)
{ return (uintptr_t)pointer % byte_count == 0; }
希望のコンパイラの最適化の場合 byte_count
でコンパイル時の定数です。
なぜ変換する必要があるため void *
?
言語は、C言語でも表現が異なるために異なるポインタの種類、例えばきの64ビット void *
タイプ(全体のアドレス空間)となり、32ビット foo *
タイプ(セグメント).
の変換 foo *
-> void *
を実際の計算例を追加を相殺するものとする。標準のもので、実装だけを変換する(任意の)整数へのポインタが思うことも多いとして実施され大きな負荷がかかります
このような実装では、 foo *
-> uintptr_t
-> foo *
うもの foo *
-> uintptr_t
-> void *
や void *
-> uintptr_t
-> foo *
ない.の配置を計算も確実に動作しないだけ配置をチェックの対比セグメントオフセットは、ばと考えている。
その結果:常に使用 void *
を実施-独立し活動しています。
他の回答が設定された低ビットとのAND演算を示唆し、ゼロと比較する。
しかし、より直接的な試験は、所望の位置合わせ値とMODを実行すること、およびゼロと比較だろう。
#define ALIGNMENT_VALUE 16u
if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0)
{
// ptr is aligned
}
タグのような関数テンプレート付き
#include <type_traits>
template< typename T >
bool is_aligned(T* p){
return !(reinterpret_cast<uintptr_t>(p) % std::alignment_of<T>::value);
}
は、
のようなものを呼び出すことによって、実行時にアライメントをチェックすることができますstruct foo_type{ int bar; }foo;
assert(is_aligned(&foo)); // passes
悪いアライメントが失敗することを確認するには、あなたが行うことができます。
// would almost certainly fail
assert(is_aligned((foo_type*)(1 + (uintptr_t)(&foo)));
これは私が使用しているものを基本的にあります。整数テンプレートにすることによって、私はそれはコンパイル時間を拡大していますので、私は私は何でも遅い剰余演算で終わるません確実ます。
私はいつもそうしたがって、コンパイル時のアサーションを私の入力をチェックするように。あなたのアライメント値が間違っている場合、うまくそれがコンパイルされません...
template <unsigned int alignment>
struct IsAligned
{
static_assert((alignment & (alignment - 1)) == 0, "Alignment must be a power of 2");
static inline bool Value(const void * ptr)
{
return (((uintptr_t)ptr) & (alignment - 1)) == 0;
}
};
で何が起こっているかを確認するには、あなたがこれを使用することができます:
// 1 of them is aligned...
int* ptr = new int[8];
for (int i = 0; i < 8; ++i)
std::cout << IsAligned<32>::Value(ptr + i) << std::endl;
// Should give '1'
int* ptr2 = (int*)_aligned_malloc(32, 32);
std::cout << IsAligned<32>::Value(ptr2) << std::endl;
することができ、あなただけの「と」最下位ビットのいずれかが設定されているかどうかを確認するには0x03の(4S上に並ぶ)とPTR、0x07の(8S上に並ぶ)または0x0Fの(16S上に整列)?
専門家にそのままにしておき、
bool is_aligned(const void* ptr, std::size_t alignment) noexcept;
例:
char D[1];
assert( boost::alignment::is_aligned(&D[0], alignof(double)) ); // might fail, sometimes
いかがます:
void *mem = malloc(1024+15);
void *ptr =( (*(char*)mem) - (*(char *)mem % 16) );