ボトルネックを見つけて、時間をできるだけ正確に測定する必要があります。
次のコード スニペットは、パフォーマンスを測定するための最良の方法ですか?
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);
ストップウォッチは、高精度タイマーの存在を自動的にチェックします。
多くの場合、タイムゾーンやDSTなどで行わなければならない作業のために、DateTime.Now
かなり遅いことがあることに注意してください。DateTime.UtcNow
通常、DateTime.UtcNow の分解能は 15 ミリ秒です。優れた要約については、精度に関するJohn Chapman のブログ投稿を参照してください。DateTime.Now
DateTime.UtcNow
興味深い雑学:ハードウェアが高頻度カウンターをサポートしていない場合、ストップウォッチはフォールバックします。Stopwatch がハードウェアを使用して高精度を実現しているかどうかは、静的フィールドStopwatch.IsHighResolutionで確認できます。
素早く汚いものが必要な場合は、精度を高めるために代わりにストップウォッチを使用することをお勧めします。
Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();
Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);
または、もう少し洗練されたものが必要な場合は、おそらくANTSなどのサードパーティのプロファイラーの使用を検討する必要があります。
この記事では、まず、3つの選択肢、、およびを比較する必要があると述べてStopwatch
いDateTime.Now
ますDateTime.UtcNow
。
また、場合によっては(パフォーマンスカウンターが存在しない場合)、StopwatchがDateTime.UtcNow+追加の処理を使用していることも示しています。そのため、その場合、DateTime.UtcNowが最良のオプションであることは明らかです(他の人がそれを使用し、いくつかの処理を行うため)
ただし、結局のところ、カウンターはほとんど常に存在します。高解像度パフォーマンスカウンターと、.NETストップウォッチに関連するその存在についての説明を参照してください。。
これがパフォーマンスグラフです。UtcNowが他の方法と比較してパフォーマンスコストがいかに低いかに注目してください。
X軸はサンプルデータサイズであり、Y軸は例の相対時間です。
優れている点の1つStopwatch
は、より高い分解能の時間測定を提供することです。もう1つは、よりOOな性質です。ただし、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);
}
System.Diagnostics.Stopwatch クラスを使用します。
Stopwatch sw = new Stopwatch();
sw.Start();
// Do some code.
sw.Stop();
// sw.ElapsedMilliseconds = the time your "do some code" took.
同上ストップウォッチ、それははるかに優れています。
パフォーマンス測定に関しては、「//実行プロセス」が非常に短いプロセスであるかどうかも確認する必要があります。
また、「// Some Execution Process」の最初の実行は、その後の実行よりも遅くなる可能性があることに注意してください。
通常、ループで 1000 回または 1000000 回実行してメソッドをテストすると、1 回実行するよりもはるかに正確なデータが得られます。
これらはすべて時間を測定する優れた方法ですが、ボトルネックを見つけるには非常に間接的な方法にすぎません。
スレッド内のボトルネックを見つける最も直接的な方法は、スレッドを実行することです。スレッドが待機している間は、一時停止またはブレーク キーでスレッドを停止します。これを数回行います。ボトルネックに X% の時間がかかる場合、X% は、各スナップショットのアクションでボトルネックを検出する確率です。
これは正しい方法です:
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 の代わりにストップウォッチを使用する を参照してください。
参考までに、.NET Timer クラスは診断用ではありません。次のように、事前に設定された間隔でイベントを生成します ( 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 のデザイナー ツール ボックスで見つけることができます。
Visual Studio Team Systemには、この問題に役立つ機能がいくつかあります。基本的に、単体テストを作成し、それらをさまざまなシナリオで組み合わせて、ストレスまたは負荷テストの一部としてソフトウェアに対して実行できます。これは、アプリケーションのパフォーマンスに最も影響を与えるコードの領域を特定するのに役立つ場合があります。
Microsoft の Patterns and Practices グループには、Visual Studio Team System Performance Testing Guidanceにいくつかのガイダンスがあります。
私のプログラム内で使用する方法は、ここに示すように StopWatch クラスを使用することです。
Stopwatch sw = new Stopwatch();
sw.Start();
// Critical lines of code
long elapsedMs = sw.Elapsed.TotalMilliseconds;
Vance Morrison のブログで、彼が書いた CodeTimer クラスStopWatch
についての投稿を見つけました。
私はこの種のパフォーマンス チェックをほとんど行ったことがないので (「これは遅いので、速くしてください」と考える傾向があります)、ほとんど常にこれを行ってきました。
グーグルは、パフォーマンスチェックのための多くのリソース/記事を明らかにします.
多くの人が pinvoke を使用してパフォーマンス情報を取得することに言及しています。私が研究している資料の多くは、perfmon の使用についてのみ言及しています。
ストップウォッチのトーク見た..いいね!私は何かを学びました:)
これは十分に専門的ではありません。
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 呼び出しを追加してマネージド ヒープを既知の状態に変更し、Sleep 呼び出しを追加して、コードのさまざまな間隔を ETW プロファイルで簡単に分離できるようにします。