PowerShellでパフォーマンスモニターのデータを取得する。
PowerShellでパフォーマンスモニターのデータを取得してみました。
会社の作業で、パフォーマンスモニターの出力結果を色々と取る作業(実は私は見てるだけ)を行っていたのですが、オペレータの人が「急いで実行、急いで実行」と何やら念仏を唱えながらやっていたので、「それって一括で開始、終了できないんですかね?」と聞いてみました。その人曰く、「それができないのよぉ。」との事。確かにパフォーマンスモニターのGUIでは、データコレクターを複数設定した場合に、それぞれを一括でスタートさせる仕組みにはなっていません。それなら1つにまとめればいいのですが、CPU、MEM、DISK、NET、GPUと大項目別にデータコレクターを設定していたので、きっとジャンル別に分けたかったのでしょう。
自分でやると気が付かない「面倒くさい」
自分が作業を行うときは、例え100回のコピペ作業でも黙々とやってしまいますが、他人がそれを行っているのを見ると非常に「非効率だな」と感じてしまうものです。ということで、PowerShellでのスクリプトを作ってしまおうと思いましたので、サンプル含めご覧ください。
Get-Counter、Import-Counter、Export-CounterでOKです。
意外とあっさり、Get-Counterでパフォーマンスモニターの結果は取得できます。 ただ、問題が2つほど。
- Ctrl+Cで止める事になるが、それ以降はスクリプトが動かない。
- 取りたいカウンター情報を少しでも間違えると動かない。
Ctrl+Cで止める前提でどのように構成するか?
カウンターの取得スクリプトと、カウンターデータの抽出スクリプトを分けます。カウンターの取得スクリプトは途中でCtrl+Cで強制終了なのですが、ファイル出力までは、上手くいきます。そこまでうまくいけば、抽出スクリプトは楽です。
正しいカウンター情報を得るには?
パラメータ"ListSet"は、パフォーマンスモニターのカウンター情報を列挙してくれます。この列挙情報は普通にFormat-Listで出力させてもデータの多い部分は「...」ではしょられてしまいます。ま、PowerShellですから、まじめに出力するように手を加えて上げればきれいに出力できます。ただ、データは多いです。普通にテキストを眺めていてもなんだかなぁ、と思いましたので、今回は手動でHTML&CSSによる、きれいな出力をするようにしました。
サンプル:カウンター情報を列挙する
# # カウンターリストを出力します。 # $output = "<!DOCTYPE html>`n" $output += "<html lang=`"ja`">`n" $output += "<head><meta charset=`"UTF-8`">`n" $output += "<title>Windows Performance Monitor Counter List</title>`n" $output += "<link rel=`"stylesheet`" href=`"StyleSheet1.css`">`n" $output += "</head>`n" $output += "<body>`n" $output += "<h1>Windows Performance Monitor Counter List</h1>`n" $list = Get-Counter -ListSet * $listCount = 1 foreach ($item in $list) { $output += ("<h2> No.{0} {1}</h2>`n" -F $listCount, $item.CounterSetName) $listCount += 1 $output += "<table border=`"1`">" $output += "<tr>" $output += "<th>CounterSetType</th>" $output += ("<td>" + $item.CounterSetType + "</td>") $output += "</tr>`n" $output += "<tr>" $output += "<th>Description</th>" $output += ("<td>" + $item.Description + "</td>") $output += "</tr>`n" $row = 1 foreach ($item3 in $item.Counter) { $output += "<tr>" $output += ("<th>Counter{0}</th>" -F $row) $output += ("<td>{0}</td>" -F $item3) $output += "</tr>`n" $row += 1 } $output += "</table>`n" } $output += "</body></html>" $output | Out-File -FilePath "PerformanceCounters.html" -Encoding utf8 -Force
/* thanks https://webliker.info/75964/ */ h1 { color: #364e96;/*文字色*/ border: solid 3px #364e96;/*線色*/ padding: 0.5em;/*文字周りの余白*/ border-radius: 0.5em;/*角丸*/ } h2 { padding: 0.4em 0.5em;/*文字の上下 左右の余白*/ color: #494949;/*文字色*/ background: #f4f4f4;/*背景色*/ border-left: solid 5px #7db4e6;/*左線*/ border-bottom: solid 3px #d7d7d7;/*下線*/ } table{ width: 100%; border-collapse: collapse; } table tr{ border-bottom: solid 2px white; font-size: 12px; } table tr:last-child{ border-bottom: none; } table th{ position: relative; text-align: left; width: 15%; background-color: #52c2d0; color: white; padding: 10px 0; }
CSSは、もらい物です。
なかなかきれいに出力できてます。
サンプル:カウンター情報を取得する。
# # パフォーマンスログを取得する # #Get-Counter -ListSet * | Format-List > ListSet.txt # Windowsサーバリソースのデータ収集項目と判断基準の一例 # https://www.ashisuto.co.jp/product/category/quality/loadrunner/technical/list/1195227_3454.html # # CPU \Processor(_Total)\% Processor Time ※80%~90%以内 # CPU \System\Processor Queue Length ※CPUあたり2未満 # MEMORY \Memory\Available Mbytes ※5MB以上 # MEMORY \Memory\Pages /sec ※20以内 # MEMORY \Process(_Total)\Working Set ※参考値として取得 # Disk \PhysicalDisk(*)\Avg. Disk Queue Length ※ディスク毎に2未満 # $counters = @( # "\Processor(_Total)\% Processor Time", # "\System\Processor Queue Length", # "\Memory\Available Mbytes", # "\Memory\Pages/sec", # "\Process(_Total)\Working Set", # "\PhysicalDisk(*)\Avg. Disk Queue Length" # ) # 出力対象を決定します。 $counters = @( "\Processor(_Total)\% Processor Time", "\Processor(_Total)\% User Time", "\Processor(_Total)\% Privileged Time", "\System\Processor Queue Length", "\Memory\Available MBytes", "\Memory\Pages/sec", "\PhysicalDisk(*)\% Disk Read Time", "\PhysicalDisk(*)\Disk Read Bytes/sec", "\PhysicalDisk(*)\Avg. Disk Bytes/Read", "\PhysicalDisk(*)\Avg. Disk Read Queue Length", "\PhysicalDisk(*)\% Disk Write Time", "\PhysicalDisk(*)\Disk Write Bytes/sec", "\PhysicalDisk(*)\Avg. Disk Bytes/Write", "\PhysicalDisk(*)\Avg. Disk Write Queue Length", "\PhysicalDisk(*)\Current Disk Queue Length", "\Network Interface(*)\Bytes Received/sec", "\Network Interface(*)\Bytes Sent/sec", "\Network Interface(*)\Output Queue Length" ) # ファイル名を作成します。 $now = Get-Date -Format "yyyyMMdd_hhmmss" $output = ".\PerfLog_{0}.blg" -F $now # パフォーマンスモニタの出力値を取得します。Ctrl+Cで終了します。 Get-Counter -Counter $counters -SampleInterval 1 -Continuous | export-counter -Force -Path $output
サンプル:カウンターログからデータを抽出する。
# # パフォーマンスログをCSVに展開する # $files = Get-ChildItem -Path ".\" -Filter "*.blg" foreach ($item in $files) { Write-Host $item.Name -ForegroundColor Yellow Import-Counter -Path $item.Name | Export-counter -FileFormat "CSV" -Path ($item.BaseName + ".csv") -Force }
最大の問題:どのカウンター値を取得して、どの閾値で問題を切り分けるか?
大きなカテゴリとしては、以下の4つになると思います。
- CPU
- MEMORY
- DISK
- NETWORK
CPU
決して、CPU使用率:100%は問題ではないのです。むしろハードウェアをぎりぎりまで使い切ったら優秀です。しかし、コア数の少ないシステムにおいて1つのプログラムが100%近くCPUを消費し続けると、GUIの応答性が下がったり、発熱による暴走に至ったりと良いことはありません。効率よく使うか、安定を求めるか。悩むところではあります。
また、CPUがアップアップなのかを測るカウンター値として「\System\Processor Queue Length」があります。昔から「2以上」が閾値なのですが、今使っている化け物PC(XEON 44コア?)ですと、暇なコアが多くてQueueが上がることはまずないです。こんな化け物で仕事するとは思いもしませんでしたが、パフォーマンス測定も難しくさせます。
MEMORY
メモリが潤沢にあるなら、わざわざハードディスクの仮想メモリに送り込んだり、取り戻したりする必要はないはずです。仮想メモリとのやり取りが多いならメモリ不足が考えられます。とは言っても、128GBのメインメモリならまず、起きないことです。CPU/MEMORYは性能直結ファクターなので見極める必要があるのですが、新しいハードウェアにマッチした判断基準がまだないような気がしています。
DISK
今ではSSDの登場により、「くっそ遅い」事はなくなりましたが、それでも効率よくI/Oしているのかは測りたいところです。HDDの場合はセクタ、クラスタ単位のI/Oを意識していましたが、SSDの登場によりHDD的見方では行けない気がします。
NETWORK
9600bpsから始まった私のネットワーク人生も今や25Gbps。1Gbpsのハブでは足りなくて、ハブを求めて右往左往することもしばしば。
そもそもでありますが、1GbpsのLANで1Gbpsフルフル使えるとは思っていません。一体どこにTCP/IPの限界があるのでしょう。
ということで、すみません。全く持ってまとまった情報を持ち得ていないことが判明しました。次回までに情報収集と実測を行いたいと思います。