以下のこのコードはDelphi 13で検証しています。
はじめに
Delphiのコードの処理時間の測定する機会がありましたので,TStopwatchを使ってみました。
Vcl(つまりWindows環境)だと,GetTickCountをこれまで使っていたのですが,取得するのはシステムが開始してからの経過時間でCardinal(UInt32)が返されるため,コードの特定の部分を複数回実行してかかる時間の合計を出すには少しコードを描く必要がありました。
そこで,TStopwatchでどのくらい簡単に時間を計測できるか調べるため,簡単なストップウォッチのサンプルプログラムを書きたいと思います。
今回のサンプルプログラムはVclで書きましたが,TStopwatchはSystem.Diagnosticsで定義されていますので,VclとFMXのどちらでも利用可能です。
TStopwatchの初期化
まずは,TStopwatchについて調べます。
TStopwatchはレコード型で定義されているのですが,初期化が必要です。
2つの方法が提供されています。
- 初期化だけをしたい場合:
StopWatch := TStopWatch.Create;
- 初期化してすぐに計測をスタートする場合:
StopWatch := TStopWatch.StartNow;
StopWatch.Start;というよく似た名前のメソッドがあるのですが,Stopwatch.StartNow;は TStopWatchを初期化して返しますので注意が必要です。
計測の開始と終了
- 初期化された
Stopwatchの計測をスタートする。※計測値は初期化されません。
StopWatch.Start;
- 計測中の
Stopwatchの計測をストップする。※計測値は初期化されません。
StopWatch.Stop;
-
Stopwatchの計測値をリセットする。
StopWatch.Reset;
計測結果の取得方法
主に3つのプロパティで計測値を取得できます。
| プロパティ | 説明 |
|---|---|
Elapsed |
計測値を,System.TimeSpanユニットで定義されているTTimeSpanで返します。 |
ElapsedMilliseconds |
計測値のミリ秒を,Int64で返します。 |
ElapsedTicks |
計測値のカウント数を,Int64で返します。 |
これらのプロパティは計測中に計測値を読み出せるだけでなく,一旦Stopメソッドで計測を停止させてから,後で計測値を読み出すこともできます。
高解像度タイマを利用できているかの確認方法
IsHighResolutionプロパティで高精度タイマが使用されているかを確認できます。
サンプルコード
これを踏まえて,簡単なストップウォッチのサンプルを作ることにしました。
-
以下のようにVclフォーム
Form1に,Label1: TLabelとButton1: TButton,Button2: TButton,Button3: TButtonそしてTimer1: TTimerを配置します。(Label1のフォントサイズを少し大きくしています。)

-
インターフェースの
uses節にSystem.Diagnosticsを追加します。
uses
・・・(略)・・・,
System.Diagnostics;
-
Form1のPrivate宣言にFStpwatchを以下のように追加します。
private
{ Private 宣言 }
FStopwatch: TStopwatch;
- フォーム
Form1のOnCreateイベントを追加し,以下のように書きます。
Timer1のIntervalはLabel1のフレームレートを40fpsになるように25を設定しています。この値はの更新の頻度になりますので,適当に値を変更していただいて構いません。
高解像度タイマを使っているときにはラベルの文字を赤色にしています。
procedure TForm1.FormCreate(Sender: TObject);
begin
FStopWatch := TStopWatch.Create;
Timer1.Interval := 25; // 40fps
if FStopWatch.IsHighResolution then begin
Label1.Font.Color := clRed;
end;
end;
-
Button1: TButtonのOnClickイベントで計測をスタートします。
procedure TForm1.Button1Click(Sender: TObject);
begin
FStopwatch.Start;
end;
-
Button2: TButtonのOnClickイベントで計測をストップします。
procedure TForm1.Button2Click(Sender: TObject);
begin
FStopwatch.Stop;
end;
-
Button3: TButtonのOnClickイベントで計測値をリセットします。
procedure TForm1.Button3Click(Sender: TObject);
begin
FStopwatch.Reset;
end;
-
Timer1: TTimerのOnTimerイベントで計測値を表示します。
今回は,ElapsedMillisecondsプロパティを使いましたが,紹介した別のプロパティを使っていただいてもかまいません。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Caption := FStopwatch.ElapsedMilliseconds.ToString;
end;
全て記述すると以下のようになります。Unit1.pasで保存します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
System.Diagnostics;
type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private 宣言 }
FStopwatch: TStopwatch;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
FStopwatch.Start;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
FStopwatch.Stop;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
FStopwatch.Reset;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FStopwatch := TStopwatch.Create;
if FStopwatch.IsHighResolution then begin
Label1.Font.Color := clRed;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Caption := FStopwatch.ElapsedMilliseconds.ToString;
end;
end.
実行すると,StopWatchがどのような計測値を保持しているかが理解できると思います。
まとめ
TStopwatchを使うと簡単に繰り返し処理の中の特定の処理にかかる時間を測定できそうです。
処理を見通せる場所にTStopwatchを配置し,初期化してから計測を行い,任意のタイミングで計測結果が表示できます。
利用時には初期化が必要です。測定が一度きりで済むならStartNewで,計測を断続的に累積して行うならCreateでやるとよいのではないかと思います。
参考URL
- DockWiki - System.Classes.TThread.GetTickCount
- DockWiki - System.Diagnostics.TStopwatch
- DockWiki - System.TimeSpan.TTimeSpan
謝辞
dekoさんの Delphi Programming -経過時間を得るには?
を参考にさせていただきました。この場を借りてお礼申し上げます。
誤って理解していることがあればご指摘いただけるとありがたいです。