ボトルネックを見つけ、時間をできるだけ正確に測定する必要があります。
次のコードスニペットは、パフォーマンスを測定するための最良の方法ですか?
DateTime startTime = DateTime.Now;
// Some execution process
DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
ボトルネックを見つけ、時間をできるだけ正確に測定する必要があります。
次のコードスニペットは、パフォーマンスを測定するための最良の方法ですか?
DateTime startTime = DateTime.Now;
// Some execution process
DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
回答:
いいえ、ちがいます。ストップウォッチを使用する(内System.Diagnostics
)
Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);
ストップウォッチは、高精度タイマーの存在を自動的にチェックします。
言及する価値があるのDateTime.Now
はDateTime.UtcNow
、タイムゾーンやDSTなどで行わなければならない作業が原因である場合よりも、かなり遅い場合があることです。
DateTime.UtcNowの解像度は通常15ミリ秒です。優れた要約については、精度に関するJohn Chapmanのブログ投稿を参照してくださいDateTime.Now
。
興味深い雑学:DateTime.UtcNow
ハードウェアが高周波カウンターをサポートしていない場合、ストップウォッチはフォールバックします。静的フィールドStopwatch.IsHighResolutionを調べることにより、ストップウォッチがハードウェアを使用して高精度を達成しているかどうかを確認できます。
PerformWork()
非常に短い場合は繰り返し呼び出して、呼び出しのバッチの平均を計算できる場合があるという推奨も追加する必要があります。また、Stopwatch
タイミング測定を濁らせるストロボ効果を回避するために、開始/停止するのではなく、呼び出し全体の時間を計ってください。
この記事では、まず、すべてのあなたは3つの選択肢を比較する必要があると述べているStopwatch
、DateTime.Now
とDateTime.UtcNow
。
また、場合によっては(パフォーマンスカウンターが存在しない場合)、ストップウォッチがDateTime.UtcNow +いくつかの追加処理を使用していることも示しています。そのため、その場合はDateTime.UtcNowが最良のオプションであることは明らかです(他のユーザーがそれを使用するため+一部の処理)
しかし、結局のところ、カウンターはほとんど常に存在します-.NETストップウォッチに関連する高解像度パフォーマンスカウンターとその存在についての説明を参照してください。。
こちらがパフォーマンスグラフです。パフォーマンスコストがUtcNowが他の方法と比べてどれほど低いかに注意してください。
X軸はサンプルデータサイズであり、Y軸は例の相対時間です。
1つStopwatch
優れている点は、より高い分解能の時間測定を提供することです。もう1つは、オブジェクト指向の性質です。ただし、OOラッパーを作成するのはUtcNow
難しくありません。
ベンチマークコードをユーティリティクラス/メソッドにプッシュすると便利です。StopWatch
クラスは、である必要はありませんDisposed
か、Stopped
エラーに。したがって、いくつかのアクションのタイミングを決める最も簡単なコードは
public partial class With
{
public static long Benchmark(Action action)
{
var stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
}
呼び出しコードの例
public void Execute(Action action)
{
var time = With.Benchmark(action);
log.DebugFormat(“Did action in {0} ms.”, time);
}
拡張メソッドのバージョンはこちら
public static class Extensions
{
public static long Benchmark(this Action action)
{
return With.Benchmark(action);
}
}
そして、サンプルの呼び出しコード
public void Execute(Action action)
{
var time = action.Benchmark()
log.DebugFormat(“Did action in {0} ms.”, time);
}
Elapsed.TotalMilliseconds
より高い精度のために戻ります。あまりにもこの質問を参照してくださいstackoverflow.com/questions/8894425/...
これらはすべて時間を測定する優れた方法ですが、それはボトルネックを見つける非常に間接的な方法にすぎません。
スレッド内のボトルネックを見つける最も直接的な方法は、スレッドを実行することです。待機している処理を実行している間は、一時停止またはブレークキーを使用して停止します。これを数回繰り返します。ボトルネックにX%の時間がかかる場合、X%は各スナップショットのアクションでそれをキャッチする確率です。
参考までに、.NETタイマークラスは診断用ではなく、次のように、事前に設定された間隔でイベントを生成します(MSDNから)。
System.Timers.Timer aTimer;
public static void Main()
{
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
したがって、これは実際に何かがかかった時間を知るのに役立ちません。一定の時間が経過しただけです。
タイマーはSystem.Windows.Formsのコントロールとしても公開されています... VS05 / VS08のデザイナーツールボックスで確認できます
これは正しい方法です:
using System;
using System.Diagnostics;
class Program
{
public static void Main()
{
Stopwatch stopWatch = Stopwatch.StartNew();
// some other code
stopWatch.Stop();
// this not correct to get full timer resolution
Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);
// Correct way to get accurate high precision timing
Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
}
}
詳細については、正確なパフォーマンスカウンターを取得するためにDataTimeの代わりにストップウォッチを使用するを参照してください。
Visual Studio Team Systemには、この問題に役立ついくつかの機能があります。基本的に、単体テストを作成し、さまざまなシナリオでそれらを混合して、ストレステストまたは負荷テストの一部としてソフトウェアに対して実行できます。これは、アプリケーションのパフォーマンスに最も影響を与えるコードの領域を特定するのに役立ちます。
MicrosoftのPatterns and Practicesグループには、Visual Studio Team System Performance Testing Guidanceにいくつかのガイダンスがあります。
Vance Morrisonのブログで、彼が書いたCodeTimerクラスについての投稿を見つけたところです。これにより、使用がStopWatch
簡単になり、面倒なことをいくつか行うことができます。
これは十分に専門的ではありません:
Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);
より信頼性の高いバージョンは次のとおりです。
PerformWork();
int repeat = 1000;
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
PerformWork();
}
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);
実際のコードでは、GC.Collect呼び出しを追加してマネージヒープを既知の状態に変更し、ETWプロファイルでコードの異なる間隔を簡単に分離できるようにSleep呼び出しを追加します。
私はこの種のパフォーマンスチェックをほとんど行わなかったので(「これは遅い、速くする」と思う傾向がある)ので、私はほとんどいつもこれを行ってきました。
グーグルはパフォーマンスチェックのための多くのリソース/記事を明らかにしています。
pinvokeを使用してパフォーマンス情報を取得することについて多くの人が言及しています。私が研究している資料の多くは、実際にはperfmonの使用についてのみ言及しています。
StopWatchの話を見てください。私は何かを学びました:)
プログラム内で使用する方法は、次に示すようにStopWatchクラスを使用することです。
Stopwatch sw = new Stopwatch();
sw.Start();
// Critical lines of code
long elapsedMs = sw.Elapsed.TotalMilliseconds;