wetchのブログ

他人に見られることを想定していない書き散らかし独習ノート.物理学とかVBAとか.

VBAの実行時間を測るためのクラス

VBAの話も久し振り.

コードが遅い気がしたので実行時間を測ろうとしたのだけど,折角だからそれなりのツールとして作ることにした.

完成イメージとしては,学生のときに使ってたMatlabの感じでレポートを出せるようにしようと思った.
jp.mathworks.com
こういうのを一般にプロファイラというらしい.

参考.
tonari-it.com

使い方としてはこんな感じ.

Sub HowToUseTimer()
    Dim timer As TimerClass
    Set timer = New TimerClass
    
    For i = 0 To 10
        '時間のかかる処理を実行

        timer.Record
    Next
End Sub

こうするとEnd Subの(正確にはtimerオブジェクトが破棄される)タイミングでこのようなレポートを出す.

実行時間測定
Step    Self Time       Total Time
0   0.000       0.000
1   0.102       0.102
2   0.102       0.203
3   0.117       0.320
4   0.102       0.422
5   0.094       0.516
6   0.102       0.617
7   0.109       0.727
8   0.102       0.828
9   0.117       0.945
10  0.094       1.039
11  0.117       1.156

Step 0はtimerをnewしたタイミングで,その後のstep1~11はForの中でtimer.Recordをしたタイミングでの差分時間と合計時間を出している.
(タブ位置が狂ってるけど,メッセージボックスに表示させたらこれでうまくできるんだ...)


クラスモジュールTimerClassの中はと言うと,

Private time_() As Double

Private Sub Class_Initialize()
    ReDim time_(0)
    time_(0) = getSecond
End Sub

Public Sub Record()
    Dim n As Long
    n = UBound(time_)
    ReDim Preserve time_(n + 1)
    time_(n + 1) = getSecond
End Sub

Private Function getSecond() As Double
    getSecond = CDbl(Timer)
End Function

Private Sub class_terminate()
    Dim n As Long
    n = UBound(time_)
    
    Dim selfTime() As Double, totalTime() As Double
    ReDim selfTime(n)
    ReDim totalTime(n)
    
    selfTime(0) = 0
    totalTime(0) = 0
    
    Dim i As Long
    For i = 1 To n
        selfTime(i) = time_(i) - time_(i - 1)
        totalTime(i) = time_(i) - time_(0)
    Next
    
    Dim report As String
    report = "実行時間測定" & vbNewLine _
            & "Step" & vbTab & "Self Time" & vbTab & vbTab & "Total Time"
    
    For i = 0 To n
        report = report & vbNewLine _
                & i & vbTab & Format(selfTime(i), "0.000") & vbTab & vbTab & Format(totalTime(i), "0.000")
    Next i
    
    MsgBox prompt:=report, Buttons:=vbInformation + vbOKOnly
End Sub

インスタンスをnewしたタイミングで時刻を内部変数time_(0)に保存している.
そのあとReportを呼んだタイミングでも時刻を調べてtime_の配列数を1個増やして保存.
インスタンスを使わなくなったらデストラクタが呼ばれてレポートを作成.


大したものじゃないけど,まあ何かの役に立つだろ.