1

実行時間測定機能を実装する必要があります。二つの可能性を考えました。

  • 最初 - 通常の time() 呼び出し。各実行ステップの開始時刻と各実行ステップの完了時刻を覚えておいてください。Unixtimeシェル コマンドはこのように動作します。

  • 2 つ目の方法はサンプリングです。すべての実行ステップは、実行が開始される前に何らかのフラグを設定し (たとえば、スタック フレームにオブジェクトを作成します)、完了時にそれを破棄します。タイマーは定期的にすべてのフラグをスキャンし、実行時間プロファイルを生成します。一部の実行ステップが他のステップよりも時間がかかる場合、そのステップはより多くの回数スキャンされます。多くのプロファイラーはこのように機能します。

サーバー アプリケーションにプロファイリング機能を追加する必要があります。2番目の方法は精度が低く、最初の方法はプロファイリングライブラリコードに依存関係を追加すると思います.

4

4 に答える 4

1

ブーストがオプションの場合は、タイマー ライブラリを使用できます。

于 2012-10-30T10:46:31.627 に答える
1

作成しているプロファイラーで何を探しているのかを本当に理解していることを確認してください。特定のコード部分の合計実行時間を収集しているときはいつでも、そのすべての子で費やされた時間が含まれており、難しい場合があります。最もトップレベルの関数は常に最も高価な関数としてバブルアップするため、システムのボトルネックを実際に見つけます-たとえば、main()。

私が提案するのは、すべての関数のプロローグとエピローグにフックすることです (アプリケーションが CLR アプリケーションの場合は、 を使用しICorProfilerInfo::SetEnterLeaveFunctionHooksてそれを行うことができます。また、すべてのメソッドの先頭でマクロを使用するか、またはあなたのすべての関数の最初とすべてのコード) を作成し、プロファイリングするスレッドごとにツリーの形式で時間を収集します。

このアルゴリズムは、次のようになります。

  • 監視しているスレッドごとに、スタックのようなデータ構造を作成します。
  • 実行を開始した関数について通知を受けるたびに、その関数を識別する何かをそのスタックにプッシュします。

    • その関数がスタック上の唯一の関数ではない場合、まだ返されていない前の関数が関数を呼び出したものであることがわかります。
    • お気に入りのデータ構造で、呼び出し先から呼び出された関係を追跡します。
  • メソッドが戻るときはいつでも、その識別子は常にそのスレッド スタックの一番上にあります。合計実行時間は (最後の (その) 識別子がスタックにプッシュされた時間 - 現在の時間) と等しくなります。スタックのその識別子をポップします。

このようにして、関数の実行時間の合計をどの子呼び出しが占めているかを確認できる、実行時間を消費するもののツリー状の内訳が得られます。

楽しむ!

于 2012-10-30T10:58:37.397 に答える
1

私のプロファイラーでは、あなたが言及した最初のアプローチの拡張バージョンを使用しました。

コンテキスト オブジェクトを提供するクラスがあります。実行フローが定義されたコンテキスト (関数やループなど) を離れるとすぐに解放される自動オブジェクトとして、作業コードで定義できます。コンストラクターは呼び出しGetTickCount(これは Windows プロジェクトであり、ターゲット プラットフォームに応じて類似の関数を選択できます) を呼び出してこの値を保存しますが、デストラクタはGetTickCount再度呼び出して、この瞬間と開始の差を計算します。各オブジェクトには一意のコンテキスト ID (同じコンテキスト内の静的オブジェクトとして自動生成可能) があるため、プロファイラーは同じ ID を持つすべてのタイミングを合計できます。つまり、同じコンテキストが複数回渡されたことを意味します。また、実行回数もカウントされます。

関数のプロファイリングに役立つプリプロセッサのマクロを次に示します。

#define _PROFILEFUNC_  static ProfilerLocator locator(__FUNC__); ProfilerObject obj(locator);

関数をプロファイリングしたいときは、関数の先頭にPROFILEFUNCを挿入するだけです。locatorこれにより、コンテキストを識別し、その名前を関数名として保存する静的オブジェクトが生成されます (別の名前を選択することもできます)。次に、automaticProfilerObjectがスタック上に作成され、独自の作成と削除を「トレース」し、これをプロファイラーに報告します。

于 2012-10-30T10:53:44.893 に答える
1

2 番目の方法は、本質的にスタック サンプリングです。なんらかの入口と出口のイベント キャプチャを使用して、自分で実行することもできます。または、実際にスタックを読み取るユーティリティがあればよりよいでしょう。後者には、メソッド レベルだけでなく、コード行の解決が得られるという利点があります。

多くの人がこれについて理解していないことがあります。それは、タイミング測定の精度は問題識別の精度よりもはるかに重要ではないということです。

I/O やその他のブロッキング中でもサンプルを取得することが重要です。これにより、不必要な I/O が見えなくなることはありません。他のプロセスとの競合によって時間が過大になるのではないかと心配している場合でも、気にしないでください。本当に重要なのは絶対的な時間の測定値ではなく、パーセンテージです。たとえば、コードの 1 行が実時間の 50% スタック上にある場合、それを取り除くと、他に何が起こっているかに関係なく、アプリの速度が 2 倍になります。

プロファイリングは、サンプルを取得するだけではありません。多くの場合、人々は自分が何をするかについてかなりカジュアルですが、そこにお金があります. まず、包含時間は、メソッドまたはコード行がスタック上にある時間の割合です。「自己」時間は忘れてください - それは包括的な時間に含まれています。呼び出しのカウントを忘れてください。包括的パーセントとの関係は、せいぜい非常に間接的です。要約する場合、コードの 1 行に焦点を当てた「バタフライ ビュー」を作成するのが最善の方法です。その左右には、スタック サンプルのすぐ上とすぐ下に表示されるコード行があります。コードの各行の横にはパーセント (そのコード行を含むスタック サンプルのパーセント) があります。(そして、再帰について心配する必要はありません。単純に問題ではありません。)

どんな種類の要約よりも優れているのは、スタック サンプル自体の小さなランダムな選択をユーザーに表示させることです。そうすれば、ユーザーは、各スナップショットが費やされた理由の全体像を把握できます。複数のサンプルに表示される回避可能なアクティビティは、大幅な高速化のチャンスであり、保証されています。人々はしばしば「まあ、それは本当のボトルネックではなく、まぐれかもしれない」と考えます。そうではありません。それを修正すると、おそらく少し、おそらく多くの利益が得られますが、平均して-重要です。人々はリスク回避によって支配されるべきではありません。

そのすべてについてもっと。

于 2012-10-30T13:30:51.100 に答える