-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcPerformanceMeter.cls
More file actions
320 lines (236 loc) · 11.4 KB
/
cPerformanceMeter.cls
File metadata and controls
320 lines (236 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "cPerformanceMeter"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Option Base 1
'Option Compare Text
'# <author> Daniel Grass
'# <mail> dani.grass@bluewin.ch
'#Region
'# Public Subs, Functions and Properties
'#======================================================================================================================
'# Accessible in this class
'#======================================================================================================================
' |> Get | --- About :: Returns description of the class.
' |> Get | --- Name :: Returns name of the class.
' |> Get | --- Version :: Returns version string for the class [e.g. #.# (year)].
'#======================================================================================================================
'# References
'#======================================================================================================================
'Private Declare Sub MemCopy Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, source As Any, ByVal bytes As Long)
'#======================================================================================================================
'# Dependencies to other classes
'#======================================================================================================================
' cDataTable :: used to store the results of each execution
' cStopWatchHD :: used to measure the elapsed time for execution in micro seconds
'#======================================================================================================================
'# Application Constants, Enumerations & Types
'#======================================================================================================================
Private Const C_Name As String = "cPerformanceMeter.cls"
Public Enum OutputChannel
StringOut = 1
ImmedateWindowOut = 2
FileOut = 3
End Enum
'#======================================================================================================================
'# Private Variables
'#======================================================================================================================
Private m_Storage As cDataTable 'The table holding the results of all runs
Private m_Timer As cStopWatchHD 'The stop watch itself
Private m_Runtime As Double 'The runtime of a dedecated run
Private m_RunID As Long 'The RunID of a dedicated run
Private m_SingleRun(1 To 3) As Variant 'Array holding the result of a single run
'#Region
'#======================================================================================================================
'# Class Initialization, Termination & Properties
'#======================================================================================================================
Private Sub Class_Initialize()
' ************************************************
' Class constructor.
' ************************************************
'Debug.Print "|> Initializing:= " & Me.Name
Set m_Storage = New cDataTable
Set m_Timer = New cStopWatchHD
m_Storage.DefineTable 3, "RunID, RunDescription, RunTime (s)"
End Sub
Private Sub Class_Terminate()
' ************************************************
' Class destructor.
' ************************************************
'Debug.Print "|> Terminating:= " & Me.Name
Set m_Storage = Nothing
Set m_Timer = Nothing
End Sub
Public Property Get Version() As String
' ************************************************
' Version string of the current class.
' Contains a list of (historical) changes to the class within the comments of the procedure.
' ************************************************
'Version = "Version 1.0 (2017)" 'Initial release
Version = "Version 1.1 (2018-08)" 'Redesigned PrintReport to prevent performance issue with string concatination in combination with high numbers of records.
End Property
Public Property Get About() As String
' ***********************************************
' String that describes the current class.
' ***********************************************
About = "<Description of the Class> Version: " & Me.Version & "." & VBA.vbCrLf & VBA.vbCrLf
About = About & "For additional details please contact the author."
End Property
Public Property Get Name() As String
' ***********************************************
' Returns the name of the class.
' ***********************************************
Name = C_Name
End Property
'#Region
'#======================================================================================================================
'# cStopWatchHD Manipulation
'#======================================================================================================================
Public Sub Reset()
m_Timer.Reset
End Sub
Public Sub Restart()
m_Timer.Restart
End Sub
Public Sub Start()
m_Timer.Start
End Sub
Public Sub Pause()
m_Timer.Pause
End Sub
Public Sub LogRun(RunDescription As String, Optional RunID As Long = -1)
m_Runtime = m_Timer.Elapsed
m_SingleRun(1) = RunID
m_SingleRun(2) = RunDescription
m_SingleRun(3) = m_Runtime
m_Storage.RecordAdd m_SingleRun
End Sub
'#Region
'#======================================================================================================================
'# Perf Meter Methods
'#======================================================================================================================
Public Sub PrintReport(Optional OutputTo As OutputChannel = ImmedateWindowOut, Optional IncludeDetails As Boolean = False, Optional ByRef stOut As String, Optional stFileOut As String = "") 'As String
Dim stRunID As String
Dim stRunDescr As String
Dim stRunTime As String
Dim stHeaderOut As String
Dim stOutput As String
Dim stSummaryHeaderOut As String
Dim stSummaryOut As String
Dim aRecord As Variant
Dim stHeader As Variant
Dim i As Long
Dim htRunDescr As cHashTable
Dim tSummary As cDataTable
Dim rSummary(1 To 5) As Variant
Dim lptrToData As Long
Dim iFH As Integer
'Dim stRunDescr As String
Dim dblMin As Double: dblMin = 0
Dim dblMax As Double: dblMax = 0
Dim dblRunTime As Double: dblRunTime = 0
Set tSummary = New cDataTable
Set htRunDescr = New cHashTable
tSummary.DefineTable 5, "NoOfRuns, RunDescription, MinRuntime, MaxRuntime, AvgRuntime"
'create header
For Each stHeader In m_Storage.Headers
stHeaderOut = stHeaderOut & stHeader & vbTab
Next
stHeaderOut = stHeaderOut & vbCrLf
'Check for detailed report with output channel other than file
If IncludeDetails = True And OutputTo <> FileOut Then
MsgBox "Detailed output only supported when writing to file. Summary report will be produced!", vbInformation
End If
'Create file handle if output to file
If OutputTo = FileOut Then
iFH = FreeFile
Open stFileOut For Output As #iFH
End If
'process the logged data
m_Storage.RsMoveFirst
Do While Not m_Storage.RsEOF
stRunID = m_Storage.Item(1)
stRunDescr = m_Storage.Item(2)
stRunTime = Format(m_Storage.Item(3), "0.000000")
dblRunTime = m_Storage.Item(3)
'create the detail record if required
If IncludeDetails = True And OutputTo = FileOut Then
'here goes the file output
stOutput = stOutput & stRunID & vbTab
stOutput = stOutput & stRunDescr & vbTab
stOutput = stOutput & stRunTime
Print #iFH, stOutput
stOutput = ""
End If
'create the summary data
If htRunDescr.Exists(stRunDescr) Then
'get the pointer to the summary table
lptrToData = htRunDescr.Item(stRunDescr)
'update the summary table
tSummary.Item("NoOfRuns", lptrToData) = tSummary.Item("NoOfRuns", lptrToData) + 1
'maintain min and max values
If dblRunTime > tSummary.Item("MaxRuntime", lptrToData) Then tSummary.Item("MaxRuntime", lptrToData) = dblRunTime
If dblRunTime < tSummary.Item("MinRuntime", lptrToData) Then tSummary.Item("MinRuntime", lptrToData) = dblRunTime
'calculate the average value - calculate the travelling mean: ('previous mean' * ('count' - 1) + 'new value') / 'count'
tSummary.Item("AvgRuntime", lptrToData) = (tSummary.Item("AvgRuntime", lptrToData) * (tSummary.Item("NoOfRuns", lptrToData) - 1) + dblRunTime) / tSummary.Item("NoOfRuns", lptrToData)
Else
'add record to the summary table
rSummary(1) = 1
rSummary(2) = stRunDescr
rSummary(3) = dblRunTime
rSummary(4) = dblRunTime
rSummary(5) = dblRunTime
tSummary.RecordAdd rSummary
'add key to the hash table with pointer to summary table
htRunDescr.Add stRunDescr, tSummary.NumItems
End If
m_Storage.RsMoveNext
Loop
'create the summary
'create summary header
For Each stHeader In tSummary.Headers
stSummaryHeaderOut = stSummaryHeaderOut & stHeader & vbTab
Next
stSummaryHeaderOut = stSummaryHeaderOut & vbCrLf
'process the summary table
tSummary.RsMoveFirst
Do While Not tSummary.RsEOF
stSummaryOut = stSummaryOut & tSummary.Item(1) & vbTab
stSummaryOut = stSummaryOut & tSummary.Item(2) & vbTab
stSummaryOut = stSummaryOut & Format(tSummary.Item(3), "0.000000") & vbTab
stSummaryOut = stSummaryOut & Format(tSummary.Item(4), "0.000000") & vbTab
stSummaryOut = stSummaryOut & Format(tSummary.Item(5), "0.000000") & vbCrLf
tSummary.RsMoveNext
Loop
'produce the final output
stOutput = "*** Report Start ***" & vbCrLf & vbCrLf & "*** Summary ***" & vbCrLf & stSummaryHeaderOut & stSummaryOut & vbCrLf & vbCrLf & "*** Report End ***"
If OutputTo = FileOut Then
If IncludeDetails = True Then
'add the summary to the end of the file
stOutput = vbCrLf & vbCrLf & "*** Summary ***" & vbCrLf & stSummaryHeaderOut & stSummaryOut & vbCrLf & vbCrLf & "*** Report End ***"
Print #iFH, stOutput
Else
'simply dump the summary
Print #iFH, stOutput
End If
Close #iFH
Else
If OutputTo = StringOut Then
stOut = stOutput
ElseIf OutputTo = ImmedateWindowOut Then
Debug.Print stOutput
Else
MsgBox "Not supported output channel!", vbInformation
End If
End If
End Sub
Public Function Clear()
m_Storage.TruncateTable False
m_Timer.Reset
End Function