たまに性能情報を取得したいことがありますが、スクリプトでできると便利ですよね。
もくじ:
はじめに
Windowsでよくある実装はPDH (Performance Data Helper)や.NetでSystem.Diagnotics (PerformanceCounterクラス)を使う方法です。詳しくは調べていませんが、おそらく叩いているDLLは同じ。
PowerShellを使う場合には.Netでもいいのですが、WMI (Windows Management Instruments)か最近のバージョンでサポートされているGet-Counterコマンドレットが使いやすいと思います。
一方で、Pythonで性能取得と言えばpsutilモジュール。さすがにWindowsでもLinuxでもクロスプラットフォームで使えます。
厳密には色々違いはあるものの、よくある性能情報の取得がサポートされています。
下記はpsutilとWMIオブジェクトで取得できる主な性能値を列挙したものです。だいたい同じような性能値を並べたつもりですが、やはり厳密には同じものにはなりませんね。
カテゴリ | 項目 | Python (psutil) | PowerShell (Win32_PerfFormattedData…) |
---|---|---|---|
CPU | 使用率[%] | .cpu_percent | ..._PerfOS_Processor.PercentProcessorTime |
メモリ | 利用可能量[Byte] | .virtual_memory.available | ..._PerfOS_Memory.AvailableBytes |
割り当て済み[Byte] | .virtual_memory.used | ..._PerfOS_Memory.CommittedBytes | |
割り当て率[%] | .virtual_memory.percent | ..._PerfOS_Memory.PercentCommittedBytesInUse | |
ディスク | 使用容量率[%] | .disk_usage | – |
空き容量率[%] | – | ..._PerfDisk_LogicalDisk.PercentFreeSpace | |
Write量[Bytes] | .disk_io_counters.write_bytes | – | |
Read量[Bytes] | .disk_io_counters.read_bytes | – | |
Write速度[Bytes/sec] | – | ..._PerfDisk_LogicalDisk.DiskWriteBytesPersec | |
Read速度[Bytes/sec] | – | ..._PerfDisk_LogicalDisk.DiskReadBytesPersec | |
Write数 | .disk_io_counters.write_count | – | |
Read数 | .disk_io_counters.read_count | – | |
Write時間[sec] | .disk_io_counters.write_time | – | |
Read時間[sec] | .disk_io_counters.read_time | – | |
Write応答時間[msec] | – | ..._PerfDisk_LogicalDisk.AvgDisksecPerWrite | |
Read応答時間[sec] | – | ..._PerfDisk_LogicalDisk.AvgDisksecPerRead | |
NIC | 送信量[Bytes] | .net_io_counters.bytes_sent | (Get-NetAdapterStatistics.SentBytes ) |
受信量[Bytes] | .net_io_counters.bytes_recv | (Get-NetAdapterStatistics.ReceivedBytes ) | |
送信速度[Bytes] | – | ..._Tcpip_NetworkInterface.BytesSentPersec | |
受信速度[Bytes] | – | ..._Tcpip_NetworkInterface.BytesReceivedPersec | |
システム | 起動時刻[epoch] | .boot_time | – |
起動時間[sec] | – | ..._PerfOS_System.SystemUpTime |
ディスクの容量に関してはpsutilが使用率(使っているほう)、WMI経由では空き容量(残り使用可能なほう)です。足すと100%になる関係ですね。
また、psutilでは総じて述べ積算量が取得できる一方、WMI経由(またはパフォーマンスカウンタ)では単位時間あたりの量(速度)が取得できたりします。
なお、Get-NetAdapterStatistics
コマンドレットがサポートされているのはWindows 8世代以降(Server 2012以降)のようです。
PowerShellでの情報取得
性能情報を取得するためのWMIオブジェクトはおおよそWin32_PerfFormattedData_...
で始まるものです。
上記の表では長くなるので分けて書いてありますが、例えばメモリの情報はWin32_PerfFormattedData_PerfOS_Memory
でアクセスできます。
取得結果の各パラメータを参照すれば性能値が取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 | > $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Memory > $buf_ | fl * PSComputerName : xxx... __CLASS : Win32_PerfFormattedData_PerfOS_Memory __NAMESPACE : root\cimv2 AvailableBytes : 14109691904 ... CommittedBytes : 12132687872 ... FreeAndZeroPageListBytes : 7944441856 FreeSystemPageTableEntries : 12271612 ... |
メモリの場合は上の例のようにひとつのインスタンスのみですが、マルチコアのCPUなどさらに複数の下位インスタンスに分かれる場合があるので、合計値(_Total)など必要に応じて選ぶとよいと思います。
その他、Windowsで提供されているパフォーマンスカウンタの類はパフォーマンスモニター(管理ツール→システムツール→パフォーマンスで表示できるもの↓)で表示させることができるので、何が利用できるか調べたい場合に活用できます。
性能取得系のコマンドレットはWindows7(Server 2008R2)以降、いくつか追加されているので、最近のバージョンでは比較的快適にできたりします。
特にディスクの応答時間など、短い時間で急激に値が変わるものや、ミリ秒など単位が小さいものについてはWMIオブジェクトを参照するよりもGet-Counter
コマンドレットを使って複数サンプリング&平均値を使う方法がより実用的です。
下記の例は複数回(-MaxSamples
)、一定のインターバル(-SampleInterval
)で測定値を取得したのち、集約して平均値や最大値を使う(Measure-Object
とSelect-Object
)という記述になります。
1 2 3 4 5 6 7 8 9 | function getDiskPerf () { $samples = Get-Counter -Counter "\LogicalDisk(*)\Avg. Disk sec/Read" -SampleInterval 1 -MaxSamples 4; $read_ = $samples.CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average; $read_ *= 1000.0 $samples = Get-Counter -Counter "\LogicalDisk(*)\Avg. Disk sec/Read" -SampleInterval 1 -MaxSamples 4; $write_ = $samples.CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average; $write_ *= 1000.0 return @{ "read_msec" = $read_; "write_msec" = $write_ }; } |
Get-Counter
コマンドレットで指定できるカウンター(-Counter
)はパフォーマンスモニターなどでも使う文字列で、下記(論理ディスクの例)のようにして利用可能なものを調べることができます。
1 2 3 4 5 6 7 8 9 | > Get-Counter -ListSet "LogicalDisk" > (Get-Counter -ListSet "LogicalDisk").Paths | fl * \LogicalDisk(*)\% Free Space ... \LogicalDisk(*)\Avg. Disk Bytes/Transfer \LogicalDisk(*)\Avg. Disk Bytes/Read \LogicalDisk(*)\Avg. Disk Bytes/Write \LogicalDisk(*)\% Idle Time \LogicalDisk(*)\Split IO/Sec |
一連の処理を書いた例は下記のようなものです。
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 | function gatherPerfData () { $fields = @{}; # CPU $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor | Where-Object { $_.Name -eq "_Total" } $fields.Add("processor_total_percent", $buf_.PercentProcessorTime) # memory $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Memory $fields.Add("memory_percent_committed", $buf_.PercentCommittedBytesInUse); $fields.Add("memory_bytes_available", $buf_.AvailableBytes); $fields.Add("memory_bytes_committed", $buf_.CommittedBytes); # disk $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_PerfDisk_LogicalDisk $disk_ = $buf_ | Where-Object { $_.Name -eq "C:" } $fields.Add("disk_primary_percent_free",$disk_.PercentFreeSpace); $fields.Add("disk_primary_bytes_persec_read",$disk_.DiskReadBytesPerSec); $fields.Add("disk_primary_bytes_persec_write",$disk_.DiskWriteBytesPerSec); # disk response time $samples = Get-Counter -Counter "\LogicalDisk(*)\Avg. Disk sec/Read" -SampleInterval 1 -MaxSamples 4; $read_ = $samples.CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average; $read_ *= 1000.0; $samples = Get-Counter -Counter "\LogicalDisk(*)\Avg. Disk sec/Read" -SampleInterval 1 -MaxSamples 4; $write_ = $samples.CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average; $write_ *= 1000.0; $fields.Add("disk_average_readtime_msec", $read_); $fields.Add("disk_average_writetime_msec", $write_); # nic $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_Tcpip_NetworkInterface $sent_ = $buf_.BytesSentPersec | Measure-Object -Sum | Select-Object -ExpandProperty Sum $recv_ = $buf_.BytesReceivedPersec | Measure-Object -Sum | Select-Object -ExpandProperty Sum $fields.Add("network_bytes_persec_sent", $sent_); $fields.Add("network_bytes_persec_received", $recv_); # system $buf_ = Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_System $fields.Add("system_uptime",$buf_.SystemUpTime); return $fields } |
また、この結果はこんな感じになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "processor_total_percent": 15, "memory_percent_committed": 43, "memory_bytes_available": 13748342784, "memory_bytes_committed": 12745031680, "disk_primary_percent_free": 44, "disk_primary_bytes_persec_read": 239, "disk_primary_bytes_persec_write": 0, "disk_average_readtime_msec": 0.4528375, "disk_average_writetime_msec": 0.10, "network_bytes_persec_sent": 1109, "network_bytes_persec_received": 7746, "system_uptime": 44316 } |
psutilを使ったPythonでの情報取得
導入されていない場合はpip経由でインストールすることができます。
1 | > pip install psutil |
たまにインストールに失敗する場合があり、ビルドツール関連のパッケージを追加すると解決するかも知れません。下記はUbuntuでの例です。
1 2 | $ sudo apt install build-essential python3-dev $ sudo pip3 install psutil |
以下はpsutilを使った例です。
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 | import psutil from datetime import datetime def get_parf(): def _ev(num_): return float("{:.2f}".format(num_)) res = {} self.perf_common = {} # cpu cpu_ = [] for i in range(5): cpu_.append(psutil.cpu_percent(1)) # use average value except first one res["processor_total_percent"] = _ev(sum(cpu_[1:]) * 0.25) # memory res["memory_percent_committed"] = psutil.virtual_memory().percent # disk disk_ = psutil.disk_usage("C:/") res["disk_primary_percent_free"] = _ev(100.0 - disk_.percent) disk_ = psutil.disk_io_counters() res["disk_total_readtime_msec"] = disk_.read_time res["disk_total_writetime_msec"] = disk_.write_time res["disk_total_read_count"] = disk_.read_count res["disk_total_write_count"] = disk_.write_count # nic net_ = psutil.net_io_counters() res["network_bytes_received"] = net_.bytes_recv res["network_bytes_sent"] = net_.bytes_sent # system uptime_ = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) res["system_uptime"] = _ev(uptime_.total_seconds()) return res |
おわり。
コメント
Windows用ツールやAnsibleの記事など、いくつか拝見させていただきました。
どれも内容が深く、とても勉強になりました。
ブックマークさせていただきましたので、これからもお世話になります。