0

私は現在、C++で独自のMersenne Twisterの実装を行っています。Visual StudioコンパイラがMersenne-Twisterの実装でループをアンロールしないのはなぜですか?

void twistIteration(uint32_t i) 
{ 
    uint32_t x = (mt[i] & MASK_UPPER) + (mt[(i + 1) % N] & MASK_LOWER); 

    uint32_t xA = x >> 1; 

    if (x & 1) 
    { 
     xA ^= A; 
    } 

    mt[i] = mt[(i + M) % N]^xA; 
} 

注N、MとMASK_UPPERはテンプレート引数なので、それらはコンパイル時に知られていること:このアルゴリズムは、次の関数を複数回呼び出す必要。

void twist() 
{ 
    for (uint32_t i = 0; i < N; i++) 
    { 
     twistIteration(i); 
    } 

    index = 0; 
} 

このアルゴリズムで128.000.000の乱数を生成すると、私のマシンで約0.95秒かかってしまいます。しかし、私は非常に少しひねりの機能を変更することで、アルゴリズムを高速化する方法を見つけた:表現(i + 1) % N(i + M) % Nがで計算することができるように

つまり
void twist() 
{ 
    for (uint32_t i = 0; i < N - 1; i++) 
    { 
     twistIteration(i); 
    } 

    twistIteration(N - 1); 

    index = 0; 
} 

、私は、ループの最後の繰り返しをアンロールコンパイル時。同じ量の乱数は今や巨大な改善である0.60秒しかかかりません。 私の質問です:なぜコンパイラは私のためにこれをしないのですか?私はデフォルトのVS2017リリースモードでコンパイルし、「高速コード最適化だがより大きなコード」をtrueに設定しました。 Visual Studioコンパイラのいくつかの奇妙な振る舞いですか?

+0

コンパイラがあなたのプログラムに最適なマシンコードを生成しない理由を尋ねているようです。 VC++ではこのような最適化を見ることができません。あなたのコードに対して_any_特定の最適化が実行されることは期待できません。 –

+0

あなたが使用している 'cl'の正確なコマンドラインは何ですか? 'gcc'や' clang'のような別のツールチェーンを使用する場合は、最適化を行いますか? – Dai

+0

私はコンパイラによって特定の最適化が行われるとは思っていませんが、特にコンパイル時にいくつかの式が分かっている場合は、基本的なループアンローリングが必要です。 – Brotcrunsher

答えて

1

このようなことを処理するコンパイラの最適化に依存するのは難しいことがあります。あなたの最大の賭けは、あなたが大きな違いを得ることができるかどうかを確認するために、異なるフラグを試すことです。

つまり、私はあなたが生成している要素の数を大幅に増やすことを試みます。この0.35秒は、他のさまざまな要因に依存する可能性のあるばらつきである可能性が非常に高いです。 1分(またはそれ以上)の時間がかかり、その差がまだ劇的であるかどうかを確認するためにストレステストを試してみてください。

0

thay設定でも大きなループを巻き戻すことに抵抗することがあります。

template<std::size_t...Is> 
inline auto index_over(std::index_sequence<Is...>){ 
    return [](auto&&f)->decltype(auto){ 
    return decltype(f)(f)(std::integral_constant<std::size_t,Is>{}...); 
    } 
} 
template<std::size_t N> 
inline auto index_upto(std::integral_constant<std::size_t,N> ={}){ 
    return index_over(std::make_index_sequence<N>{}); 
} 
template<class F> 
inline auto foreacher(F&&f){ 
    return [&](auto&&...args){ 
    using discard=int[]; 
    (void)discard{0,(void(
     f(decltype(args)(args)) 
    ),0)...}; 
    }; 
} 

auto index=index_upto<N>(); 
index(foreacher([&](auto I){ 
    twistIteration(I); 
)); 

(それはそのループを振りなおすために、スマートコンパイラを取る)非常識な程度にアンロール力ループです。

携帯電話の入力ミスを謝罪します。 Google site:stackoverflow.com yakkindex_upto tomfindの亜種は、おそらくタイプミスを減らすことができます。

関連する問題