Attribute VB_Name = "PerfTimer"
Option Explicit                                              '-İRd-

' Performance Counter API's
Public Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Public Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long

Public Enum ePerf
    epSeconds   ' Seconds
    epMillisecs ' Milliseconds - one thousandth of a second
    epMicrosecs ' Microseconds - one millionth of a second
End Enum

Private cFreq As Currency

' ===========================================================================
' Precise Timer - ProfileStart and ProfileStop
' ===========================================================================
'
' ProfileStart returns the current value of the high-resolution performance
' counter as a Currency data type. This value is passed on to ProfileStop which
' subtracts it from an ending value and returns the difference (elapsed time).
'
' In the case of no high-resolution timer, ProfileStart returns zero.
' Multiple performance timers can be run concurrently if required.
'
' In the case of no high-resolution timer, ProfileStop returns zero.
' ===========================================================================
Public Function ProfileStart() As Currency
    If (cFreq = 0) Then QueryPerformanceFrequency cFreq
    If (cFreq) Then QueryPerformanceCounter ProfileStart
End Function

' Dim c As Currency
' c = ProfileStart
' txtDisplay = FormatElapsed(ProfileStop(c, epMillisecs))

Public Function ProfileStop(ByVal cStart As Currency, Optional ByVal eTimeScale As ePerf) As Double
    Dim cStop As Currency
    If (cFreq) Then
        QueryPerformanceCounter cStop ' cpu tick accurate
        Select Case eTimeScale
            Case epSeconds:   ProfileStop = (CDbl(cStop - cStart) / CDbl(cFreq))
            Case epMillisecs: ProfileStop = (CDbl(cStop - cStart) / CDbl(cFreq)) * 1000#
            Case epMicrosecs: ProfileStop = (CDbl(cStop - cStart) / CDbl(cFreq)) * 1000000#
            ' Multiply by 1000 to convert to milliseconds or 1000000 for microseconds µs
        End Select
    End If
End Function

' ===========================================================================
' Elapsed Time Formatting - FormatElapsed
' ===========================================================================
'
' The return value from ProfileStop can be passed to this function to format
' the elapsed time to a string representation of the decimal value.
'
' The result returned is accurate to the maximum decimal places contained in
' the dblElapsed argument if the optional argument is omitted or set to < 0.
'
' Otherwise, it returns the elapsed time rounded to the number of decimal
' places specified by lngDecPlaces.
' ===========================================================================
Public Function FormatElapsed(ByVal dElapsed As Double, Optional ByVal lDecPlaces As Long = -1) As String
    Select Case lDecPlaces
        Case Is < 0
            FormatElapsed = CStr(CDec(dElapsed))
        Case Is = 0
            FormatElapsed = Format$(CStr(CDec(dElapsed)), "#0")
        Case Else
            FormatElapsed = Format$(CStr(CDec(dElapsed)), "#0." & String$(lDecPlaces, "0"))
    End Select
End Function
' ===========================================================================
