Help us understand the problem. What is going on with this article?

goでwindowsのWMI経由からディスクIOPSを取得してみた

More than 1 year has passed since last update.

WindowsのWMI経由からDisk IOPSをgoで取得してみました。

環境

項目 内容
Windows 2012R2
Go 1.9.2

使ったパッケージ

以下のパッケージを使用しました。

https://github.com/StackExchange/wmi

ドキュメント

https://godoc.org/github.com/StackExchange/wmi

ソース

以下は、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)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away