1

反復回数またはその他の属性に基づいてループを展開するようにコンパイラーにどのように指示しますか?または、Visual Studio 2005でループ展開の最適化をどのようにオンにしますか?

編集:例:

//Code Snippet 1
    vector<int> b;
    for(int i=0;i<3;++i) b.push_back(i);

とは対照的に

//Code Snippet 2
    vector<int> b;
    b.push_back(0);
    b.push_back(1);
    b.push_back(2);

push_back()は一例ですが、これを長時間かかる可能性のあるものに置き換えることができます。

しかし、私はどこかでコード1を使用でき、ループがいくつかの基準を満たしている場合、コンパイラーはそれをコード2に展開できることを読みました。だから私の質問は:どうやってそれをするのですか?どちらがより効率的であるかについてはSOに関する議論がすでにありますが、それについてのコメントはとにかくありがたいです。

4

5 に答える 5

7

通常は、コンパイラにその仕事を任せます。コンパイル時にループの数がわかっていて、コンパイラの最適化がオンになっている場合、コンパイラはコードサイズとブランチの削減のバランスを取り、展開可能なループを展開します。

それが本当にあなたが望むものではない場合は、Duff's Deviceを使って自分でそれを行う可能性もあります:(ウィキペディアから)

send(to, from, count)
register short *to, *from;
register count;
{
    register n=(count+7)/8;
    switch(count%8){
    case 0: do{ *to = *from++;
    case 7:     *to = *from++;
    case 6:     *to = *from++;
    case 5:     *to = *from++;
    case 4:     *to = *from++;
    case 3:     *to = *from++;
    case 2:     *to = *from++;
    case 1:     *to = *from++;
        }while(--n>0);
    }
}

これにより、実行時に決定された反復回数で展開できます。

それでもコンパイル時に必要な展開が行われ、組み込みの最適化が必要なものではない場合(よりきめ細かい制御が必要な場合)、C++テンプレートを作成して必要な処理を実行できます。これは非常に簡単なテンプレートアプリケーションであり、すべてコンパイル時に実行されるため、コンパイラが追加で実行する可能性のある関数のインライン化やその他の最適化を失うことはありません。

于 2009-09-02T16:11:01.897 に答える
6

それは一般的にかなり単純です:「あなたは最適化を有効にします」。

コードを最適化するようにコンパイラーに指示した場合、ループ展開は、コンパイラーが適用しようとする多くの最適化の1つです。

ただし、展開しても必ずしも高速なコードが生成されるとは限らないことに注意してください。(データキャッシュと命令キャッシュの両方で)キャッシュミスを引き起こす可能性があります。また、最新のCPUに見られる高度な分岐予測では、ループを構成する分岐のコストはほとんどの場合無視できます。

時々、コンパイラーは、展開するとより遅いコードが生成されると判断し、それを実行しない場合があります。

于 2009-09-02T17:09:08.787 に答える
5

ループの展開によって、ループで実行されるコードが魔法のように高速化されることはありません。ループ変数の比較に使用されるCPUサイクルを数回節約するだけです。したがって、ループ本体自体がほとんど何もしない非常にタイトなループでのみ意味があります。

あなたの例に関して:push_back()償却された一定の時間がかかりますが、これには時折の割り当て-コピー-割り当て解除のサイクルと実際のオブジェクトのコピーが含まれます。ループ内の比較がそれと比較して重要な役割を果たすことは非常に疑わしいです。そして、それを他のものと交換するのに時間がかかる場合、同じことが当てはまります。

もちろん、これは特定のCPUでは間違っている可能性があり、他のCPUでは正しくない可能性があります。キャッシュ、命令パイプライン、分岐予測スキームを備えた最新のCPUアーキテクチャの特異性により、コードの最適化においてコンパイラを凌駕することは非常に困難になっています。展開して「重い」ボディのループを最適化しようとすることは、これで多くを達成するのに十分な知識がないことを示唆しているようです。(私はあなたが気分を害しないようにこれを言うように一生懸命に努力しています。私はこのゲームで私がより緩いことを認める最初の人です。)

パフォーマンスに問題がある場合は、10件中9件のIMEで、ばかげたエラー(複雑なオブジェクトのコピーなど)を排除し、アルゴリズムとデータ構造を最適化することを検討する必要があります。

(それでも問題が10分の1のカテゴリに分類されると思われる場合は、Intelのコンパイラを試してください。前回見たときに無料でテストバージョンをダウンロードでき、VSに接続されていてセットアップが非常に簡単でした。 、そして私がテストしたアプリケーションで約0.5%の速度向上をもたらしました。)

于 2009-09-02T17:29:42.160 に答える
5

あなたが言うことに注意してください:

push_back()は一例ですが、これを長時間かかる可能性のあるものに置き換えることができます。

実際、push_back()(またはそれを置き換えるもの)に長い時間がかかる場合、それはループの展開が労力の無駄になる状況です。通常、ループは特に遅くはありません。ループの展開が理にかなっているのは、ループ内で行われる作業が非常に小さい場合です。その場合、ループ構造がその一連の実行の処理を支配し始める可能性があります。

他にも多くの答えが得られると確信しているので、実際にボトルネックであることがわからない限り、この種のことについて心配する必要はありません。99%の確率で、そうではありません。

于 2009-09-02T17:37:07.497 に答える
3

プロジェクトを右クリックし、プロパティを選択してナビゲートします: alt text http://img200.imageshack.us/img200/8685/propsm.jpg

WRTループの展開。MSVisualStudioでは、速度ではなくサイズを最適化すると、キャッシュのヒット/ミスにより、実際にはより高速なコードが生成されることが一般的に認められていることに注意してください。

于 2009-09-02T17:59:33.770 に答える