-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlhstats.ps1
291 lines (209 loc) · 9.2 KB
/
lhstats.ps1
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
Set-StrictMode -Version 2.0
#Name of the file to output raw stats
$statExportFile = "lhstats.csv"
#Store the output stats in the current script directory
$Invocation = (Get-Variable MyInvocation).Value
$statsExportFilePath = Join-Path (Split-Path $Invocation.MyCommand.Path) $statExportFile
Write-Host "Use CTRL+C to end."
Write-Host "Logging results to:" $statsExportFilePath
#By default show the stat headers at least once.
$displayHeader = $true
#Track number of stats reported
$iterations = 0
$displayRealtimeStats = $false
if($displayRealtimeStats -eq $false) {
write-host "Generating stats for first 1 minute period. Please wait..."
}
#Periodically re-show the column headers at this interval.
#Set to 0 to disable.
$displayHeaderInterval = 0
#Define storage and size of running average variables.
$stats5min = New-Object System.Collections.ArrayList
$sizeMax5min = (5 * 60)
$stats1min = New-Object System.Collections.ArrayList
$sizeMax1min = (1 * 60)
#Placeholder global variable to store the process name.
#Set later via function call to lookup value.
$ProcessName_LinearHash = ""
#Counters to query when checking the LinearHash service
$counters = @(
"% Processor Time",
"IO Read Operations/sec",
"IO Write Operations/sec",
"IO Other Operations/sec",
"IO Read Bytes/sec",
"IO Write Bytes/sec",
"IO Other Bytes/sec")
Function resolveLinearHashEXE() {
#Query the list of services for the LinearHash service EXE path
$pathLinearHash = Get-WmiObject win32_service | ?{$_.Name -eq 'LinearHash'} | Select-Object -Expand PathName
if ([String]::IsNullOrEmpty($pathLinearHash) -eq $True) {
#Return nothing if not found
return ""
}
#Chop starting after the last slash
$posChopStart = $pathLinearHash.LastIndexOf('\') + 1
#Chop enough up to the last period file extension
$posChopLen = $pathLinearHash.LastIndexOf('.') - $posChopStart
#Extract the EXE name excluding the file extension
$lhEXE = $pathLinearHash.Substring($posChopStart,$posChopLen)
return $lhEXE
}
Function calculateAverages($stats, $desc) {
#Visual length of the description column in characters
$descColLen = 27
#Container object of columns containing the average values for each column
$tmpAvgCol = New-Object PSObject
#Setup the description column
$i = $desc.PadRight($descColLen, " ") + "";
#$x = " Averages "
$x = "Averages "
$tmpAvgCol | Add-Member -Type NoteProperty -Name $i -Value $x
#For each of the counters calculate the average
foreach($i in $Global:counters){
#Manipulate the column headers
$i_after = $i -replace "Bytes/sec","b/s"
if ($i -ne $i_after) {
$scaleChange = $true
} else {
$scaleChange = $false
}
$i = $i_after
$i = $i -replace "Operations/sec","op/s"
$i = $i -replace "IO ",""
$i = $i -replace "% Processor Time","CPU %"
#Measure the average
$x = $stats | measure-object $i -Average | Select-Object -expand Average
#Write-Host "Avg: " $i " Val: " $x
if ($scaleChange -eq $true) {
$x = $x / 1024
$i = $i -replace "b/s","K/s"
}
$x = [math]::Round($x)
$x = "{0:N0}" -f $x
#Add this column to the container object
$tmpAvgCol | Add-Member -Type NoteProperty -Name $i -Value $x
} #foreach($i in $Global:counters){
return ,$tmpAvgCol
}
function trim-StatCollection($col, $timePeriodSec) {
$timeProperty = "Timestamp"
$timePeriodSec = $timePeriodSec * -1
$timeTruncatePrior = (Get-Date).AddSeconds($timePeriodSec)
#On Server 2008/2012
$colTrimmed = $col | Where-Object {$_.Timestamp -gt $timeTruncatePrior}
#Works only on Server 2012
#$colTrimmed = $col | Where-Object -Property $timeProperty -gt $timeTruncatePrior
return ,$colTrimmed
}
Function get-LinearHashActivity {
$process = $Global:ProcessName_LinearHash
$lhc = Get-Counter ("\Process("+$process+")\*");
$r = New-Object PSObject
$r | Add-Member -Type NoteProperty -Name "Timestamp" -Value (Get-Date -format "yy/MM/dd HH:mm:ss").ToString()
$r | Add-Member -Type NoteProperty -Name "Iteration" -Value $Global:iterations
foreach($counter in $Global:counters){
#write-host "Setting up counter" $counter
$i = $counter
$v = $lhc.CounterSamples | Where {$_.Path -like ("*" + $i)} | Select -ExpandProperty CookedValue
$v = [math]::Round($v)
#$v = "{0:N0}" -f $v
$i = $i -replace "Bytes/sec","b/s"
$i = $i -replace "Operations/sec","op/s"
$i = $i -replace "IO ",""
$i = $i -replace "% Processor Time","CPU %"
#Useful for debugging if we want to generate stats based on the iteration count
#to check if the interval averages calculate correctly
#$v = $Global:iterations
$r | Add-Member -Type NoteProperty -Name $i -Value $v
}
#Check if this loop should display the header row
if ($Global:displayHeader -eq $false) {
#For periodically showing the table headers
if (
($displayHeaderInterval -gt 0) -and
(($Global:iterations % $displayHeaderInterval) -eq 0)
) {
$Global:displayHeader = $true
} else {
$Global:displayHeader = $false
}
}
#Should the headers be displayed in this iterations output?
if($Global:displayHeader -eq $true) {
#Show the headers
$outputRaw = $r | Format-Table -Property * -AutoSize
#Since the tabler headers were just displayed assume they won't be displayed again
$Global:displayHeader = $false
} else {
#Hide the headers
$outputRaw = $r | Format-Table -Property * -AutoSize -HideTableHeaders
}
#Add the current interval stat to the running averages
[void]$Global:stats1min.add($r)
[void]$Global:stats5min.add($r)
#Display current interval stat if set
if($displayRealtimeStats -eq $true) {
$output = $outputRaw | Out-String
#Trim trailing lines of the regular output so the table is tight
$output = $output.Trim("`r`n")
Write-Host $output
}
#Update the stats file with current interval stat
#Append property only works on Server 2012
#$r | Export-CSV -Path $Global:statsExportFilePath -noclobber -append -force
#Append output to CSV file. Works on 2008/2012
$CSVContent = $r | ConvertTo-Csv
$CSVContent[2..$CSVContent.count] | add-content $Global:statsExportFilePath
$timeEnd = Get-Date
$timeRunningDuration = New-TimeSpan -Start $Global:timeStart1 -End $timeEnd
$timeLastDisplayDuration = New-TimeSpan -Start $Global:timeDisplayLast -End $timeEnd
if (($timeRunningDuration.TotalMinutes -gt 1) -and ($Global:avg1Displayed -eq $false)) {
#Show the first 1 minute average stats since the last 5 minute average was displayed
$statsToDisplay = trim-StatCollection -col $Global:stats1min -timePeriodSec (1 * 60)
$toDisplay = calculateAverages -stats $statsToDisplay -desc "1 Min Interval"
$toDisplay | Format-Table -Property * -AutoSize
$Global:stats1min.Clear()
$Global:avg1Displayed = $True
$Global:timeDisplayLast = Get-Date
} else {
if ($timeRunningDuration.TotalMinutes -gt 5) {
#Show the 5 minute average stats
$statsToDisplay = trim-StatCollection -col $Global:stats5min -timePeriodSec (5 * 60)
$toDisplay = calculateAverages -stats $statsToDisplay -desc "5 Min Interval"
$toDisplay | Format-Table -Property * -AutoSize
$Global:stats5min.Clear()
$Global:timeStart1 = Get-Date
$Global:timeDisplayLast = Get-Date
$Global:avg1Displayed = $False
} else {
if (($timeLastDisplayDuration.TotalMinutes -gt 1)) {
#Show the additional 1 minute average stats
$statsToDisplay = trim-StatCollection -col $Global:stats1min -timePeriodSec (1 * 60)
$toDisplay = calculateAverages -stats $statsToDisplay -desc "1 Min Interval"
$toDisplay | Format-Table -Property * -AutoSize
$Global:stats1min.Clear()
$Global:timeDisplayLast = Get-Date
}
}
}
$Global:iterations = $Global:iterations + 1
}
#Controls when the 1 minute average stats
#have been displayed.
$avg1Displayed = $False
#Store when the last 1 minute average was displayed
$timeStart1 = Get-Date
$timeDisplayLast = $timeStart1
#Call function to find the EXE name of the installed LinearHash service.
$ProcessName_LinearHash = resolveLinearHashEXE
if ($ProcessName_LinearHash.length -eq 0) {
write-host "No LinearHash service found."
Exit
}
#Main processing loop
while ($true){
#Call function to update all stats and display any output
get-LinearHashActivity
start-sleep 1
}