WindowsのWMI経由からDisk IOPSをgoで取得してみました。
環境
項目 | 内容 |
---|---|
Windows | 2012R2 |
Go | 1.9.2 |
使ったパッケージ
以下のパッケージを使用しました。
ドキュメント
ソース
以下は、Cドライブの読み書きIOPSを1秒間隔で取得して表示します。
package main
import (
"fmt"
"log"
"time"
"github.com/StackExchange/wmi"
)
// Windowsの物理ディスクパフォーマンスデータクラスの構造体
// https://msdn.microsoft.com/en-us/library/aa394308(v=vs.85).aspx
type Win32_PerfRawData_PerfDisk_PhysicalDisk struct {
AvgDiskBytesPerRead uint64 // 読み取り操作中にディスクから転送された平均バイト数
AvgDiskBytesPerRead_Base uint32 // AvgDiskBytesPerReadの基本値
AvgDiskBytesPerTransfer uint64 // 書き込みまたは読み取り操作中にディスクに転送された、またはディスクから転送された平均バイト数
AvgDiskBytesPerTransfer_Base uint64 // AvgDiskBytesPerTransferの基本値。この値は、発生した操作の累積数を表します
AvgDiskBytesPerWrite uint64 // 書き込み操作中にディスクに転送された平均バイト数
AvgDiskBytesPerWrite_Base uint64 // AvgDiskBytesPerWriteの基本値。この値は、発生した操作の累積数を表します
AvgDiskQueueLength uint64 // サンプル間隔中に選択されたディスクに対してキューに入れられた読み取り要求と書き込み要求の平均数
AvgDiskReadQueueLength uint64 // サンプル間隔中に選択したディスクに対してキューに入れられた読み取り要求の平均数
AvgDiskSecPerRead uint32 // ディスクからのデータの読み取り操作の平均時間(秒単位)
AvgDiskSecPerRead_Base uint32 // AvgDiskSecPerReadの基本値。この値は、発生した操作の累積数を表します
AvgDiskSecPerTransfer uint32 // 平均ディスク転送時間(秒)
AvgDiskSecPerTransfer_Base uint32 // AvgDiskSecPerTransferの基本値。この値は、発生した操作の累積数を表します
AvgDiskSecPerWrite uint32 // ディスクへのデータの書き込み操作の平均時間(秒単位)
AvgDiskSecPerWrite_Base uint32 // AvgDiskSecPerWriteの基本値。この値は、発生した操作の累積数を表します
AvgDiskWriteQueueLength uint64 // サンプル間隔中に選択されたディスクに対してキューされた書き込み要求の平均数。時間軸は100ナノ秒です
CurrentDiskQueueLength uint32 // パフォーマンスデータが収集された時点でディスク上で未処理の要求の数
DiskBytesPerSec uint64 // 書き込みまたは読み取り操作中にディスクに/からディスクに転送される速度
DiskReadBytesPerSec uint64 // 読み取り操作中にディスクからバイトが転送される速度
DiskReadsPerSec uint32 // ディスク上の読み取り操作の割合
DiskTransfersPerSec uint32 // ディスク上の読み取りおよび書き込み操作の割合
DiskWriteBytesPerSec uint64 // 書き込み操作中にバイトがディスクに転送される速度
DiskWritesPerSec uint32 // ディスク上の書き込み操作の割合
Frequency_Object uint64 // Timestamp_Objectの頻度(秒単位)。このプロパティはプロバイダによって定義されます
Frequency_PerfTime uint64 // Timestamp_Perftimeの頻度(秒単位)。値は、Windows関数QueryPerformanceCounterを呼び出すことで取得できます
Frequency_Sys100NS uint64 // Timestamp_Sys100NS(10000000)の頻度(毎秒ティック)
Name string // 統計またはメトリックが分かっているラベル
PercentDiskReadTime uint64 // 選択したディスクドライブが読み取り要求を処理している間に経過した時間の割合
PercentDiskReadTime_Base uint64 // PercentDiskReadTimeの基本値
PercentDiskTime uint64 // 選択したディスクドライブがビジー状態になっている時間のうち、読み取りまたは書き込み要求を処理している時間の割合
PercentDiskTime_Base uint64 // PercentDiskTimeの基本値
PercentDiskWriteTime uint64 // 選択したディスクドライブが書き込み要求を処理している間に経過した時間の割合
PercentDiskWriteTime_Base uint64 // PercentDiskWriteTimeの基本値
PercentIdleTime uint64 // ディスクがアイドル状態だったサンプル間隔中の時間の割合
PercentIdleTime_Base uint64 // PercentIdleTimeの基本値
SplitIOPerSec uint32 // ディスクへのI / Oが複数のI / Oに分割されたレート
Timestamp_Object uint64 // オブジェクト定義のタイムスタンプ
Timestamp_PerfTime uint64 // 高性能カウンタのタイムスタンプ。Windows関数QueryPerformanceCounterを呼び出すと、値を取得できます
Timestamp_Sys100NS uint64 // 100ナノ秒単位のタイムスタンプ値。このプロパティはWin32_Perfから継承されます
}
func getWmiObject(t string) []Win32_PerfRawData_PerfDisk_PhysicalDisk {
var dst []Win32_PerfRawData_PerfDisk_PhysicalDisk
q := wmi.CreateQuery(&dst, "Where Name = '"+t+"'")
if err := wmi.Query(q, &dst); err != nil {
log.Fatal(err)
}
return dst
}
func main() {
var beforeTotalReadIo uint32
var beforeTotalWriteIo uint32
var afterTotalReadIo uint32
var afterTotalWriteIo uint32
// ラベル
readIoLabel := "ReadIO:"
writeIoLabel := "WriteIO:"
// CドライブのRead/Write IOを表示する
targetDrive := "0 C:"
for {
wmiResultObject := getWmiObject(targetDrive)
if beforeTotalReadIo == 0 && beforeTotalWriteIo == 0 {
for _, v := range wmiResultObject {
if v.DiskReadsPerSec >= 0 {
beforeTotalReadIo = v.DiskReadsPerSec
}
if v.DiskWritesPerSec >= 0 {
beforeTotalWriteIo = v.DiskWritesPerSec
}
}
} else {
for _, v := range wmiResultObject {
if v.DiskReadsPerSec >= 0 {
afterTotalReadIo = v.DiskReadsPerSec
}
if v.DiskWritesPerSec >= 0 {
afterTotalWriteIo = v.DiskWritesPerSec
}
readIo := afterTotalReadIo - beforeTotalReadIo
writeIo := afterTotalWriteIo - beforeTotalWriteIo
fmt.Printf("%s %d\n", readIoLabel, readIo)
fmt.Printf("%s %d\n", writeIoLabel, writeIo)
beforeTotalReadIo = afterTotalReadIo
beforeTotalWriteIo = afterTotalWriteIo
time.Sleep(1 * time.Second)
}
}
}
}
WMIで取得できる値はトータルなので、データ取得前後で差分を出す必要があります。
使用例
PS C:\Users\Administrator\Desktop\wmi> go build
PS C:\Users\Administrator\Desktop\wmi> .\wmi.exe
ReadIO: 0
WriteIO: 0
ReadIO: 0
WriteIO: 0
ReadIO: 0
WriteIO: 6
(snip)