NDW

アプリ開発やトラブルシューティング等のノウハウ、キャンプや登山の紹介や体験談など。

.NET Core 1. システムエンジニアリング 実装技術

.NET Core(C#): Stopwatchで経過時間測定(ミリ秒, マイクロ秒, ナノ秒)

投稿日:

はじめに

  • 次の環境を使用して動作確認しています。
    ハードウェア CPU: AMD Ryzen 5 3400G, MEM: 16GB, SSD: 130GB
    OS Windows 10(64ビット)
    IDE Microsoft Visual Studio Community 2019(16.8.5) + C#(8.0)
  • 型が分かりやすいよう変数宣言ではvarを使用していません。実装時はvarを使用することをおすすめします。
  • 完全なソースコードはこちらで公開しています。

経過時間測定のサンプル

Stopwatchを使用した経過時間測定のサンプルを紹介します。

// 経過時間の計測
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Thread.Sleep(3000);
stopWatch.Stop();

// Elapsed(TimeSpan)からの経過時間取得
TimeSpan elapsed = stopWatch.Elapsed;
double eMili = elapsed.TotalMilliseconds;
double eMicr = eMili * 1000;
double eNano = eMili * 1000 * 1000;
Console.WriteLine($"===== from Stopwatch.Elapsed");
Console.WriteLine($"elapsed={elapsed}");    // 00:00:03.0060116
Console.WriteLine($"1) mili  sec={eMili}"); // 3006.0116
Console.WriteLine($"2) micro sec={eMicr}"); // 3006011.5999999996
Console.WriteLine($"3) nano  sec={eNano}"); // 3006011599.9999995

// ElapsedTicks(long)からの経過時間取得
bool hrEnabled = Stopwatch.IsHighResolution;
long freq = Stopwatch.Frequency;
long ticks = stopWatch.ElapsedTicks;
double tMili = (double)ticks * 1000 / freq;
double tMicr = (double)ticks * 1000 * 1000 / freq;
double tNano = (double)ticks * 1000 * 1000 * 1000 / freq;
Console.WriteLine($"===== from Stopwatch.ElapsedTicks");
Console.WriteLine($"high-resolution performance counter={hrEnabled}"); // true
Console.WriteLine($"Frequency={freq:#,0}[Ticks/sec])"); // 10,000,000
Console.WriteLine($"elapsedTicks={ticks}"); // 30060116
Console.WriteLine($"1) mili  sec={tMili}"); // 3006.0116
Console.WriteLine($"2) micro sec={tMicr}"); // 3006011.6
Console.WriteLine($"3) nano  sec={tNano}"); // 3006011600
  • StopwatchクラスのStart(), Stop()メソッドで計測の開始・終了、Elapsedプロパティから経過時間(TimeSpan型)の取得が行えます。
    再計測する場合は、Reset()/Start()またはRestart()を使用できます。
  • ElapsedTicksプロパティ(long型)を使用して経過時間を取得することもできますが、前述のElapsedから取得した方が簡単です。
    両者は多少の誤差がありますが、ほぼ同じ時間を取得できます。
    (上記では誤差が分かる例を記載していますが、私の環境ではほとんどの実行で一致します。)

ElapsedTicksを使った経過時間の算出方法

  • コンピュータでは、監視や時間計測、音楽の再生等のように正確な時刻に基づいた処理が必要になります。これを実現するために、一定時間間隔で処理を実行できる仕組み(「タイマー実行」「タイマー割り込み」と呼ばれる)を持っています。
  • このタイマー実行の頻度が高いほど細かい単位で時間計測が可能になり、ナノ秒等の精密な時間計測が可能となります。
  • タイマー実行の頻度はハードウェアやOS等の実行環境によって変わります。実行環境が「高解像度パフォーマンスカウンタ(high-resolution performance counter)」に対応している場合は、タイマー実行の頻度が向上します。
  • 高解像度パフォーマンスカウンタを使用しているかはStopwatchのIsHighResolutionプロパティ、タイマー実行の頻度はFrequencyプロパティで取得できます。
    (これらのプロパティは実行環境に依存するので静的プロパティで提供されていると思われます。)
  • 経過時間内でのタイマー実行回数がStopwatch.ElapsedTicksプロパティ([Ticks])です。単位時間でのタイマー実行回数はStopwatch.Frequencyプロパティ([Ticks/秒])です。
    これらを使用して、次のように経過時間[秒]を算出できます。
    経過時間[秒] = ElapsedTicks[Ticks] ÷ Frequency[Ticks/秒]
  • なお、高解像度パフォーマンスカウンタの実装は、チップセットに搭載された高精度イベント タイマー(HPET: High Precision Event Timer)と呼ばれるハードウェアタイマーのことらしいです。
    2005年頃から搭載し始めているため、最近のPCではどれでも搭載していると思われます。
  • DateTime型にもTicksプロパティがありますが、前述のElapsedTicksとは考え方が異なります。DateTimeのTicksは、1Ticks=100ナノ秒(固定)ですが、ElapsedTicksは実行環境で異なる値になります。(ElapsedTicksのRemarksより。)







-.NET Core, 1. システムエンジニアリング, 実装技術

関連記事

Azure AD B2Cの拡張属性とカスタム属性の違い

Azure AD B2Cのユーザアカウントを操作する際、拡張属性(ExtensionProperty)とカスタム属性(Custom Attribute)というキーワードがあり紛らわしい…と …

VULTRでRHEL8をインストール(1/2)

VULTRのVPSにRHEL8.3をインストールする手順を説明します。 概要 VULTRのVPSにRed Hat Enterprise Linux(RHEL)をインストールする手順を説明します。 実案 …

JavaEE7のJSF, Facelets, JSPの関係

JavaEEを使ったアプリ開発の際に、いつも気になるが後回しにしていたこと… HTML5への対応方法の調査等、今後の理解促進のために、調べてみた。 FaceletsとJSFとの関係は? J …

.NET Core(C#): Moqを使ったモック作成方法

はじめに 次の環境を使用して動作確認しています。 OS Windows 10(64ビット) IDE Microsoft Visual Studio Community 2019(16.8.5) + C …

ゾーン10進数の変換方法とC#のサンプル

なお、パック10進数はこちらで紹介しています。 ゾーン10進数 ゾーン10進数の変換方法 10進数の各桁を「ゾーン部(上位4ビット)+数値部(下位4ビット)」のバイトに変換して生成します。 生成したバ …