87

問題

シミュレーションタスク用の中規模のプログラムがあり、最適化する必要があります。GprofValgrindを使用したプロファイリングを含め、プログラミングスキルの限界までソースを最適化するためにすでに最善を尽くしています。

最終的に終了したら、おそらく数か月間、いくつかのシステムでプログラムを実行したいと思います。したがって、私たちは最適化を限界まで押し上げることに本当に興味があります。

すべてのシステムは、比較的新しいハードウェア(Intel i5またはi7)でDebian/Linuxを実行します。

質問

-O3 / -Ofastを超える、最新バージョンのg ++​​を使用して可能な最適化オプションは何ですか?

また、長期的に見れば、コストのかかるマイナーな最適化にも関心があります。

私たちが今使っているもの

現在、次のg++最適化オプションを使用しています。

  • -Ofast:最高の「標準」最適化レベル。含まれて-ffast-mathいるものは計算に問題を引き起こさなかったので、標準に準拠していないにもかかわらず、それを採用することにしました。
  • -march=native:すべてのCPU固有の命令の使用を有効にします。
  • -flto異なるコンパイル単位間でのリンク時間の最適化を可能にします。
4

8 に答える 8

101

回答のほとんどは、さまざまなコンパイラや外部ライブラリなど、多くの書き換えや統合作業をもたらす可能性が高い代替ソリューションを示唆しています。OPの要求に応じて、コンパイラフラグをアクティブにするか、コードに最小限の変更を加えることで、質問の内容に固執し、GCCだけで何ができるかに焦点を当てます。これは「これをしなければならない」という答えではありませんが、私にとってうまく機能し、特定のコンテキストに関連する場合は試してみることができるGCCの微調整のコレクションです。


元の質問に関する警告

詳細に入る前に、質問に関するいくつかの警告があります。通常、一緒に来る人のために、質問を読んで、「OPはO3を超えて最適化されているので、彼と同じフラグを使用する必要があります!」と言います。

  • -march=native特定のCPUアーキテクチャに固有の命令を使用できるようにします。これは、必ずしも別のアーキテクチャで使用できるとは限りません。別のCPUを搭載したシステムで実行すると、プログラムがまったく機能しない場合や、プログラムが大幅に遅くなる場合があります(これにより、プログラムも有効になりますmtune=native)。したがって、プログラムを使用する場合は、このことに注意してください。詳細はこちら
  • -Ofast、あなたが述べたように、いくつかの非標準準拠の最適化を可能にするので、それも注意して使用する必要があります。詳細はこちら

試してみる他のGCCフラグ

さまざまなフラグの詳細をここに示します。

  • -Ofastを有効にします-ffast-math。これにより、、、、、、およびが有効に-fno-math-errnoなります。、などのフラグを選択的に追加することで、浮動小数点計算の最適化をさらに進めることができます。これらは含まれておらず、計算のパフォーマンスをさらに向上させることができますが、実際にメリットがあり、計算に支障がないかどうかを確認する必要があります。-funsafe-math-optimizations-ffinite-math-only-fno-rounding-math-fno-signaling-nans-fcx-limited-range-fno-signed-zeros-fno-trapping-math-Ofast
  • GCCは、「-O」オプションでは有効にされない他の多数の最適化フラグも備えています。これらは「壊れたコードを生成する可能性のある実験オプション」としてリストされているため、注意して使用する必要があります。また、正確性とベンチマークの両方をテストして、その効果を確認する必要があります。それにもかかわらず、私は頻繁に使用します-frename-registers。このオプションは、私にとって望ましくない結果をもたらすことはなく、顕著なパフォーマンスの向上をもたらす傾向があります(つまり、ベンチマーク時に測定できます)。ただし、これはプロセッサに大きく依存するタイプのフラグです。-funroll-loopsまた、良い結果が得られることもありますが(また-frename-registers、それを意味します)、実際のコードによって異なります。

PGO

GCCには、プロファイルに基づく最適化機能があります。それに関する正確なGCCドキュメントは多くありませんが、それでも実行するのは非常に簡単です。

  • まず、でプログラムをコンパイルします-fprofile-generate
  • プログラムを実行させます(コードがプロファイル情報を.gcdaファイルに生成するため、実行時間は大幅に遅くなります)。
  • を使用してプログラムを再コンパイルし-fprofile-useます。アプリケーションがマルチスレッドの場合は、-fprofile-correctionフラグも追加します。

GCCを使用したPGOは、驚くべき結果をもたらし、パフォーマンスを大幅に向上させることができます(最近取り組んでいたプロジェクトの1つで、速度が15〜20%向上しました)。明らかに、ここでの問題は、アプリケーションの実行を十分に表すデータがあることです。これは、常に利用可能であるとは限らず、簡単に取得できるとは限りません。

GCCの並列モード

GCCは、GCC4.2コンパイラがリリースされた頃に最初にリリースされたパラレルモードを備えています。

基本的に、C++標準ライブラリの多くのアルゴリズムの並列実装を提供します。それらをグローバルに有効にするには、コンパイラに-fopenmp-D_GLIBCXX_PARALLELフラグを追加するだけです。必要に応じて各アルゴリズムを選択的に有効にすることもできますが、これにはいくつかのマイナーなコード変更が必要になります。

この並列モードに関するすべての情報は、ここにあります。

大規模なデータ構造でこれらのアルゴリズムを頻繁に使用し、多くのハードウェアスレッドコンテキストを利用できる場合、これらの並列実装によりパフォーマンスが大幅に向上します。これまでの並列実装のみを使用しましたsortが、大まかなアイデアを出すために、アプリケーションの1つでソートの時間を14秒から4秒に短縮することができました(テスト環境:カスタムコンパレータ機能を備えた1億個のオブジェクトのベクトルおよび8コアマシン)。

追加のトリック

前のポイントのセクションとは異なり、この部分ではコードに小さな変更を加える必要があります。これらはGCC固有でもあるため(一部はClangでも機能します)、コンパイル時マクロを使用して、コードを他のコンパイラーで移植可能に保つ必要があります。このセクションには、より高度な手法がいくつか含まれているため、アセンブリレベルで何が起こっているのかを理解していない場合は、使用しないでください。また、プロセッサとコンパイラは最近かなり賢いので、ここで説明する関数から目立った利点を得るのは難しいかもしれないことに注意してください。

  • ここにリストされているGCCビルトイン。などの構造は、分岐予測情報__builtin_expectをコンパイラに提供することにより、コンパイラがより適切な最適化を行うのに役立ちます。データにアクセスする前にデータをキャッシュに取り込み、キャッシュミスを減らすのに役立つなどの他の構成。__builtin_prefetch
  • ここにリストされている関数属性。hot特に、とcold属性を調べる必要があります。前者は、関数がプログラムのホットスポットであることをコンパイラーに示し、関数をより積極的に最適化し、局所性を高めるためにテキストセクションの特別なサブセクションに配置します。後者は、関数のサイズを最適化し、テキストセクションの別の特別なサブセクションに配置します。

この回答が一部の開発者にとって役立つことを願っています。編集や提案を検討させていただきます。

于 2016-07-21T18:33:58.950 に答える
18

比較的新しいハードウェア(Intel i5またはi7)

インテル®コンパイラーと高性能ライブラリーのコピーに投資してみませんか?最適化でGCCを大幅に上回り、通常は10%から30%以上、さらには大量の処理プログラムの場合はさらにパフォーマンスが向上します。また、インテルは、コードに統合する余裕がある場合は、高性能の数値計算(並列)アプリケーション用の拡張機能とライブラリーも多数提供しています。何ヶ月もの実行時間を節約することになれば、大きな見返りが得られるかもしれません。

プログラミングスキルの限界までソースを最適化するために、すでに最善を尽くしています。

私の経験では、プロファイラーの助けを借りて通常行う種類のマイクロおよびナノ最適化は、マクロ最適化(コードの構造の合理化)と比較して時間投資の見返りが少ない傾向があり、最も重要なのは見過ごされがちなメモリアクセスの最適化(たとえば、参照の局所性、順序どおりのトラバーサル、間接参照の最小化、キャッシュミスの排除など)。後者は通常、メモリの使用方法(トラバース)をより適切に反映するようにメモリ構造を設計することを含みます。コンテナタイプを切り替えて、そこからパフォーマンスを大幅に向上させるのと同じくらい簡単な場合もあります。多くの場合、プロファイラーを使用すると、命令ごとの最適化の詳細に迷い、メモリレイアウトの問題は表示されず、通常、全体像を確認するのを忘れると見落とされます。それ'

于 2013-01-24T02:16:40.630 に答える
8

ええと、最後に試すことができます:ACOVEAプロジェクト:進化的アルゴリズムによるコンパイラ最適化の分析-説明から明らかなように、遺伝的アルゴリズムを試して、プロジェクトに最適なコンパイラオプションを選択します(コンパイルを何度も実行して、タイミング、アルゴリズムにフィードバックを与える:)-しかし、結果は印象的かもしれません!:)

于 2013-01-24T01:43:55.530 に答える
7

余裕があれば、VTuneを試してみてください。単純サンプリングよりもはるかに多くの情報を提供します(私が知る限り、gprofによって提供されます)。コードアナリストを試してみてください。Latterはまともな無料のソフトウェアですが、Intel CPUでは正しく(またはまったく)動作しない可能性があります。

このようなツールを搭載しているため、キャッシュ使用率(および基本的にメモリレイアウト)などのさまざまな測定値を確認できます。これを最大限に活用すると、効率が大幅に向上します。

アルゴリズムと構造が最適であることが確実な場合は、i5とi7で複数のコアを使用する必要があります。言い換えれば、さまざまな並列プログラミングアルゴリズム/パターンを試して、速度を上げることができるかどうかを確認してください。

真に並列なデータ(類似/同じ操作を実行する配列のような構造)がある場合は、OpenCLおよびSIMD命令(セットアップが簡単)を試してみてください。

于 2013-01-24T10:17:28.363 に答える
4

現在選択されている回答に関するいくつかのメモ(コメントとしてこれを投稿するのに十分な評判ポイントがまだありません):

答えは言う:

-fassociative-math、、、、および。-freciprocal-math_ これらは含まれておらず、計算のパフォーマンスをさらに向上させることができます-fno-signed-zeros-fno-trapping-math-Ofast

おそらくこれは回答が投稿されたときに当てはまりましたが、GCCのドキュメントには、これらはすべて、によって有効化され-funsafe-math-optimizations、によって有効化され-ffast-math、によって有効化されると記載されてい-Ofastます。これは、コマンドgcc -c -Q -Ofast --help=optimizerで確認できます。このコマンドは、によって有効になっている最適化を示し-Ofast、これらすべてが有効になっていることを確認します。

答えはまた言う:

「-O」オプションで有効にされないその他の最適化フラグ...-frename-registers

繰り返しますが、上記のコマンドは、少なくとも私のGCC 5.4.0では、-frename-registersデフォルトで。を使用して有効になっていることを示しています-Ofast

于 2017-07-29T10:48:25.347 に答える
1

これ以上の詳細なしに答えることは困難です:

  • どんな種類の数の計算?
  • どのライブラリを使用していますか?
  • どの程度の並列化?

コードの中で最も時間がかかる部分を書き留めてもらえますか?(通常はタイトループ)

CPUにバインドされている場合、IOにバインドされている場合とは答えが異なります。

繰り返しになりますが、詳細をお知らせください。

于 2013-01-24T03:25:06.087 に答える
1

重労働を構成する操作の種類を調べて、最適化されたライブラリを探すことをお勧めします。一般的な問題(主に数学)のために、高速でアセンブリに最適化されたSIMDベクトル化ライブラリが非常にたくさんあります。車輪の再発明はしばしば魅力的ですが、既存の解決策があなたのニーズをカバーできるのであれば、通常は努力する価値はありません。あなたはそれがどのようなシミュレーションであるかを述べていないので、私はいくつかの例を提供することしかできません。

http://www.yeppp.info/

http://eigen.tuxfamily.org/index.php?title=Main_Page

https://github.com/xianyi/OpenBLAS

于 2015-12-16T22:01:45.000 に答える
-3

gccintelを使用して/implement-fno-gcse(gfortranで適切に機能)および-fno-guess-branch-prbability(gfortranのデフォルト)

于 2015-07-11T10:07:42.330 に答える