Search code examples
performanceexcelvbaloopslag

Count the program-steps


I have a "large" vba-program with many loops, now I want to count each step respective command of my program makes when I start it, so maybe I can find loops which are not really performant. I want to have a number of executed steps.

Does anybody know how that works? Or in Excel 2010 does there already exist some functions for that?

Thanks. I know my English is not very good.

Edit 06.14.13:
Now I write it so in my module

Sub DoStuff()
Dim sw As New Stopwatch
sw.Start
Call pranlesen.plan_gen
sw.Pause
Debug.Print "SomeFunction took " & format(sw.Elapsed * 1000, "0.000000") & " milliseconds"
End Sub

The class is right called as Stopwatch I don't know what's the defect.


Solution

  • If you mean "count the number of processor instructions", no there is no way to do that. However, you can measure elapsed time very accurately. See my article Accurate Performance Timers in VBA for a detailed description of using the Windows API function QueryPerformanceCounter to construct a super-accurate stopwatch in VBA. Here's the full code for the Stopwatch class:

    Option Explicit
    
    Private Declare Function QueryPerformanceCounter Lib "kernel32" ( _
        lpPerformanceCount As UINT64) As Long
    Private Declare Function QueryPerformanceFrequency Lib "kernel32" ( _
        lpFrequency As UINT64) As Long
    
    Private pFrequency As Double
    Private pStartTS As UINT64
    Private pEndTS As UINT64
    Private pElapsed As Double
    Private pRunning As Boolean
    
    Private Type UINT64
        LowPart As Long
        HighPart As Long
    End Type
    
    Private Const BSHIFT_32 = 4294967296# ' 2 ^ 32
    
    Private Function U64Dbl(U64 As UINT64) As Double
        Dim lDbl As Double, hDbl As Double
        lDbl = U64.LowPart
        hDbl = U64.HighPart
        If lDbl < 0 Then lDbl = lDbl + BSHIFT_32
        If hDbl < 0 Then hDbl = hDbl + BSHIFT_32
        U64Dbl = lDbl + BSHIFT_32 * hDbl
    End Function
    
    Private Sub Class_Initialize()
        Dim PerfFrequency As UINT64
        QueryPerformanceFrequency PerfFrequency
        pFrequency = U64Dbl(PerfFrequency)
    End Sub
    
    Public Property Get Elapsed() As Double
        If pRunning Then
            Dim pNow As UINT64
            QueryPerformanceCounter pNow
            Elapsed = pElapsed + (U64Dbl(pNow) - U64Dbl(pStartTS)) / pFrequency
        Else
            Elapsed = pElapsed
        End If
    End Property
    
    Public Sub Start()
        If Not pRunning Then
            QueryPerformanceCounter pStartTS
            pRunning = True
        End If
    End Sub
    
    Public Sub Pause()
        If pRunning Then
            QueryPerformanceCounter pEndTS
            pRunning = False
            pElapsed = pElapsed + (U64Dbl(pEndTS) - U64Dbl(pStartTS)) / pFrequency
        End If
    End Sub
    
    Public Sub Reset()
        pElapsed = 0
        pRunning = False
    End Sub
    
    Public Sub Restart()
        pElapsed = 0
        QueryPerformanceCounter pStartTS
        pRunning = True
    End Sub
    
    Public Property Get Running() As Boolean
       Running = pRunning
    End Property
    

    Paste the above code in a new Class module and name the module "Stopwatch". Then anywhere else in your code you can do something like this:

    Sub DoStuff
        Dim sw As New Stopwatch
        sw.Start
        myResult = SomeFunction(A, B, C)
        sw.Pause
        Debug.Print "SomeFunction took " & Format(sw.Elapsed * 1000, "0.000000") & " milliseconds"
    End Sub