Stopwatchクラスは、名前の通りストップウォッチのように時間経過を計測するクラス。 OSおよびハードウェアが対応している場合は、自動的に高分解能パフォーマンスカウンタを使用して計測を行うため、一般的にDateTime.TicksEnvironment.TickCountなどを使った場合よりも高い精度で計測を行うことが出来る。 高分解能パフォーマンスカウンタに対応していない場合は、システムタイマを使用して計測を行う。

高分解能パフォーマンスカウンタとシステムタイマのどちらが使用されるかどうかは、IsHighResolutionプロパティで参照できる。 また、分解能はFrequencyプロパティで参照できる。

Stopwatchクラスは、Start()メソッドで時間経過の計測を開始し、Stop()メソッドで計測を終了する。 Stopwatchクラスは、Start()およびStop()する度に時間経過を累積して計上する。 そのため、計上した時間をクリアして計測しなおしたい場合はReset()メソッドを呼ぶ必要がある。

高分解能パフォーマンスカウンタが使用される場合は、内部的にQueryPerformanceFrequency()およびQueryPerformanceCounter() (いずれもWin32 API)が呼ばれる。 この時、GetTimestamp()はQueryPerformanceCounter()の結果に基づいた値となる。 システムタイマが使用される場合は、GetTimestamp()はDateTime.Tickと同値となる。

§1 主なコンストラクタ

Stopwatch()
インスタンスを生成する。

§2 主なメソッド

void Start()
計測を開始する。
void Stop()
計測を停止する。
void Reset()
計上した経過時間をリセットする。
void Restart()
計上した経過時間をリセットし、計測を再度開始する。 Reset() + Start()と同等。 (.NET Framework 4以降)
static Stopwatch StartNew()
Stopwatchのインスタンスを作成するのと同時に、計測を開始する。
static long GetTimestamp()
現在のタイマ刻み数(タイマの持つ分解能で計測出来る時間間隔を計測した回数)を取得する。

§3 主なプロパティ

Frequency (static long)
タイマの持つ分解能で計測できる1秒あたりの計測回数を表す。
IsHighResolution (static long)
タイマが高分解能パフォーマンスカウンタを使用している場合はtrue、システムタイマを使用している場合はfalse。
Elapsed (TimeSpan)
計測を開始してから終了するまでの時間経過の累積値をTimeSpan型で表す。
ElapsedMilliseconds (long)
計測を開始してから終了するまでの時間経過の累積値をミリ秒単位で表す。
ElapsedTicks (long)
計測を開始してから終了するまでの時間経過の累積値をタイマ刻み数単位で表す。

§4 主な呼び出し順序

  1. new Stopwatch()
  2. Start()
  3. Stop()
  4. Reset()

もしくは

  1. StartNew()
  2. Stop()
  3. Reset()

§5 使用例

1秒スリープする前後のタイムスタンプと実際の経過時間を計測する。

using System;
using System.Diagnostics;
using System.Threading;

class Sample {
  static void Main()
  {
    // Stopwatchの能力を表示
    Console.WriteLine("Stopwatch.Frequency: {0}MHz", Stopwatch.Frequency / 1000000);
    Console.WriteLine("Stopwatch.IsHighResolution: {0}", Stopwatch.IsHighResolution);

    Stopwatch watch = new Stopwatch();

    // 3回試行
    for (int count = 0; count < 3; count++) {
      Console.WriteLine("Test#{0}", count);

      Console.WriteLine("Timestamp(before): {0}", Stopwatch.GetTimestamp());

      watch.Start();

      // 1秒スリープする
      Thread.Sleep(1000);

      watch.Stop();

      Console.WriteLine("Timestamp(after): {0}", Stopwatch.GetTimestamp());

      Console.WriteLine("Elapsed milliseconds: {0}", watch.ElapsedMilliseconds);
      Console.WriteLine("Elapsed ticks: {0}", watch.ElapsedTicks);

      watch.Reset();
    }
  }
}
Windows XP上で実行した例
Stopwatch.Frequency: 3MHz
Stopwatch.IsHighResolution: True
Test#0
Timestamp(before): 4468021555
Timestamp(after): 4471571779
Elapsed milliseconds: 991
Elapsed ticks: 3549773
Test#1
Timestamp(before): 4471574066
Timestamp(after): 4475149159
Elapsed milliseconds: 998
Elapsed ticks: 3574602
Test#2
Timestamp(before): 4475151335
Timestamp(after): 4478730883
Elapsed milliseconds: 999
Elapsed ticks: 3579056
Ubuntu 9.10(Mono 2.7)上で実行した例
Stopwatch.Frequency: 10MHz
Stopwatch.IsHighResolution: True
Test#0
Timestamp(before): 2359336605891
Timestamp(after): 2359346610670
Elapsed milliseconds: 1000
Elapsed ticks: 10003551
Test#1
Timestamp(before): 2359346614248
Timestamp(after): 2359356615817
Elapsed milliseconds: 1000
Elapsed ticks: 10001479
Test#2
Timestamp(before): 2359356616492
Timestamp(after): 2359366617684
Elapsed milliseconds: 1000
Elapsed ticks: 10001077

同じ処理で繰り返し計測するような場合はRestartメソッドを使用するとより簡単に記述できる。

using System;
using System.Diagnostics;
using System.Threading;

class Sample {
  static void Main()
  {
    Stopwatch watch = new Stopwatch();

    // 3回試行
    for (int count = 0; count < 3; count++) {
      // カウンタをリセットすると同時にカウントを再開
      watch.Restart();

      // 1秒スリープする
      Thread.Sleep(1000);

      Console.WriteLine("Test#{0} Elapsed: {1}", count, watch.Elapsed);
    }
  }
}