C ++コードの高速で便利なクロスプラットフォームプロファイラ

みなさんこんにちは。 数か月前、 victorzsと一緒に、 c ++コードのシンプルで便利なプロファイラーを作成することにしました(コードセクション、関数の実行時間プロファイルすることを意味します)。





CryEngine SDKからサンプルをプロファイリングするスクリーンショット



既存のソリューションは、いくつかの理由で私たちに適合しませんでした。 次を実行できる品質プロファイラが必要でした。





慎重な研究の結果、上記のすべてを実行できるプロファイラーが誕生しました。



コードの動作時間を知り、同時に客観的な証拠を得たい場合は、プロファイラーの使用方法を示すカットをお願いします。



コード統合



  1. ここから最新リリースをダウンロードして解凍します: https : //github.com/yse/easy_profiler/releases
  2. CMake



    を使用してビルドする場合、

    • リリースからディレクトリ<easy_profiler_release_dir>/cmake/easy_profiler



      を指す変数CMAKE_PREFIX_PATH



      定義します。
    • find_package(easy_profiler REQUIRED)



      およびtarget_link_libraries(... easy_profiler)





    そうでなければ:

    • ヘッダーファイルを検索するためのディレクトリをコンパイラに書き込みます: <easy_profiler_release_dir>/include



    • リンカーをライブラリ検索ディレクトリに設定します: <easy_profiler_release_dir>/bin





  3. コンパイラに定義を追加しますBUILD_WITH_EASY_PROFILER



  4. 測定するコード内の場所にブロックを追加します。 例:



     #include <easy/profiler.h> void foo() { EASY_FUNCTION(profiler::colors::Magenta);//    ,     EASY_BLOCK("Calculating sum");//      int sum = 0; for (int i = 0; i < 10; ++i) { EASY_BLOCK("Addition", profiler::colors::Red);//         sum += i; } EASY_END_BLOCK; //   (      "Calculating sum" EASY_BLOCK("Calculating multiplication", profiler::colors::Blue500); int mul = 1; for (int i = 1; i < 11; ++i) mul *= i; //              .   ,      "Calculating multiplication"  "foo" }
          
          





  5. easy_profilerライブラリー( * .dllまたは* .so )をアセンブルされたアプリケーションの隣に置くことを忘れないでください。 または、 PATH



    システム変数にディレクトリ<easy_profiler_release_dir>/bin



    します(LinuxではLD_LIBRARY_PATH



    十分です)


統計収集モードで追加されたブロックは、できるだけ短い時間で済みます(これについては、技術的な実装に関するさらなる記事で説明しています)。 Core i7-5930K 3.5GHzプロセッサ、16 Gb RAM、 12スレッドのアプリケーションのWin7 Pro搭載したマシンでは、1ブロックの平均「コスト」は約10〜15ナノ秒です。 同様の結果がFedora 22で達成されました。 これは、測定値のグラフです(x軸に沿って-ブロック数、yに沿って-ブロックごとのナノ秒):







さらに、依存関係が線形であることは明らかです。ブロック数は時間応答に影響しません。



プロファイリング



結果の取得と分析は、簡単な名前profiler_guibinディレクトリ内)のプログラムで行われます。 プロファイラーは2つの方法で初期化できます。



  1. profiler_guiアプリケーションによるソケット接続。 これを行うには、 プロファイルされたアプリケーションのソケットでリッスンを初期化する必要があります。 これは単純に行われます:



     profiler::startListen();
          
          





    この関数は、制御コマンドのポート28077



    profiler::startListen(portNumber)



    パラメーターを使用してポートを変更できます)でリッスンするスレッドを開始します。 関数を呼び出すことでリスニングを停止できます(ただし、これはまったく必要ありません)。



     profiler::stopListen();
          
          





    ブロックの収集は、 profiler_guiをプロファイルされたアプリケーションに接続し、ツールバーの[ キャプチャ ]ボタンをクリックした後に開始されます。 プロファイリングが停止した後( 「停止」をクリック)、収集された情報はプロファイルされたアプリケーションからprofiler_guiにソケット経由で転送され、すぐにeasy_profiler.cacheファイルのディスクに保存されます。 すべての情報を別のファイルに保存することもできます( easy_profiler.cacheファイルを移動するだけです)。



  2. 結果をファイルに保存します。 これを行うには、最初にプロファイラーを初期化してから、適切なタイミングでファイルを保存する必要があります。 これは次のように行われます。



     int main() { EASY_PROFILER_ENABLE; /* do work*/ profiler::dumpBlocksToFile("test_profile.prof"); }
          
          





    その後、保存されたファイルをprofiler_guiプログラムで開くことができます



Windowsのコンテキスト切り替えに関する情報を取得するには、管理者権限でプロファイルされたアプリケーションを実行する必要があります。 Linuxの場合、状況はもう少し複雑ですscripts/context_switch_logger.stp



内のスーパーユーザー権限でパラメーターを指定してscripts/context_switch_logger.stp



を実行する必要があります。 このスクリプトはsystemtapによって解釈されます 。 Fedoraでは、次のコマンドを実行する必要があります。



 #stap -o /tmp/cs_profiling_info.log scripts/context_switch_logger.stp name APPLICATION_NAME
      
      





APPLICATION_NAME



はプロファイル対象のアプリケーションの名前であり、 /tmp/cs_profiling_info.log



はコンテキスト切り替えに関する情報が書き込まれるファイルです。 コンテキスト切り替え情報はカーネル空間でのみ取得できるため、スーパーユーザー特権が必要です。



結果分析



結果アナライザの機能を実証するために、CryEngineの簡単な例を紹介します。 CryEngine自体にはいくつかのプロファイラーがあり、それらを整理するためのマクロがあり、プロファイラーを簡単に埋め込むことができます。



コンパイル後、テストケースを実行し、 profiler_guiプログラムを実行し、アプリケーションに接続します(アイコン: 、その横に、プロファイルされたアプリケーションが実行されているIPアドレスまたはホスト名を入力できます。 接続に成功すると(アイコンが少し緑色に変わります: )プロファイリングセッションを開始できます。 ボタンをクリックした後 プロファイルされたアプリケーションで統計収集が開始されます。 プロファイリングセッションを完了するには、表示されるウィンドウを閉じます。



スクリーンショットは、結果のプログラムの一般的なビューを示しています







ウィンドウの上部には、実行中のフローと保存されたブロックが表示され、その期間は水平スケールで推定できます。 各ブロック内に、その階層が垂直に表示されます。



中央部分には、ストリームまたは選択されたブロックのタイムダイアグラムが表示されます。 ここでは、ブロックの実行時間は垂直方向、水平方向、つまりプログラムの実行時間、つまり ブロックの継続時間のバーストを監視し、必要に応じて、問題をより詳細に評価できます。



下部には、選択したサイトの詳細な統計情報を含むブロック実行ツリーがあります。 ここでは、期間で並べ替え、最も長いブロックを検索し、ブロックの呼び出し回数を推定できます。 サイトの選択は、画面の上部でマウスの右ボタンを押しながら必要な部分を選択することにより実行されます。



ブロックの簡単な統計は、画面の上部に表示できます。 ブロックの上にマウスを移動すると、ポップアップウィンドウに簡単な概要が表示されます。









この要約では、このタイプのすべてのブロックの合計期間の合計と、この量がフレーム(このブロックの最上位の親)の割合、ストリームとその親の合計時間に関する情報。 多くの場合、これは包括的な情報です。



もう1つの非常に便利な機能は、動的なオン/オフブロックです。 これを行うには、ダイアログ(アイコン )および表示されるウィンドウで、目的のブロックを有効または無効にします。 次のプロファイリングセッションでは、これらの設定が考慮されます。





C3DEngine::GetWaterLevel



関数の情報の収集を無効にしますC3DEngine::GetWaterLevel







したがって、プロファイラーの利点:



-作業速度

-最小メモリオーバーヘッド

-クロスプラットフォーム

-便利で機能的なグラフィック表示



使用の唯一の制限は、 C ++ 11標準をサポートするコンパイラーによってプロファイルされたアプリケーションを構築する必要があることです。



このプロファイラーは、ゲームエンジン( AIと3Dの両方)の開発者、既製のエンジンを使用する人、およびアプリケーションのパフォーマンスを重視するすべての人の両方に役立ちます。 このプロファイラーは、航空および戦術シミュレーターの視覚化システムの開発の一環として使用します。



ライセンスはApache 2.0またはGPL v.3( libinとguiの両方)です。 これらのライセンスのいずれかを使用します。



ご清聴ありがとうございました! フィードバック(質問、希望、 バグ 、githubのスター、プルリクエスト)を楽しみにしています。 開発プロセス中に、いくつかの非標準タスクが解決されました。これについては、別の記事を書きたいと思います。






All Articles