From 6f716d14c8c78465ae6ad574916f322b88d5b501 Mon Sep 17 00:00:00 2001 From: Joseph Malicki Date: Wed, 1 Jun 2022 00:59:32 -0700 Subject: [PATCH 1/2] Add support for Linux discards and flushes in IOCounterStats. These were added in kernels 4.18 and 5.5, respectively. Flushes (i.e. fsyncs) are especially important for logging for database servers and the like, as flushes can be a very limiting factor on IO throughput. --- disk/disk.go | 35 +++--- disk/disk_linux.go | 62 +++++++++-- disk/disk_linux_test.go | 122 +++++++++++++++++++++ disk/disk_test.go | 4 +- .../linux/diskstats-post5.5/proc/diskstats | 4 + disk/testdata/linux/diskstats-pre4.18/diskstats | 4 + .../linux/diskstats-pre4.18/proc/diskstats | 4 + .../testdata/linux/diskstats-pre5.5/proc/diskstats | 4 + 8 files changed, 213 insertions(+), 26 deletions(-) create mode 100644 disk/disk_linux_test.go create mode 100644 disk/testdata/linux/diskstats-post5.5/proc/diskstats create mode 100644 disk/testdata/linux/diskstats-pre4.18/diskstats create mode 100644 disk/testdata/linux/diskstats-pre4.18/proc/diskstats create mode 100644 disk/testdata/linux/diskstats-pre5.5/proc/diskstats diff --git a/disk/disk.go b/disk/disk.go index dd4cc1d..18df3a8 100644 --- a/disk/disk.go +++ b/disk/disk.go @@ -30,20 +30,27 @@ type PartitionStat struct { } type IOCountersStat struct { - ReadCount uint64 `json:"readCount"` - MergedReadCount uint64 `json:"mergedReadCount"` - WriteCount uint64 `json:"writeCount"` - MergedWriteCount uint64 `json:"mergedWriteCount"` - ReadBytes uint64 `json:"readBytes"` - WriteBytes uint64 `json:"writeBytes"` - ReadTime uint64 `json:"readTime"` - WriteTime uint64 `json:"writeTime"` - IopsInProgress uint64 `json:"iopsInProgress"` - IoTime uint64 `json:"ioTime"` - WeightedIO uint64 `json:"weightedIO"` - Name string `json:"name"` - SerialNumber string `json:"serialNumber"` - Label string `json:"label"` + ReadCount uint64 `json:"readCount"` + MergedReadCount uint64 `json:"mergedReadCount"` + WriteCount uint64 `json:"writeCount"` + MergedWriteCount uint64 `json:"mergedWriteCount"` + ReadBytes uint64 `json:"readBytes"` + WriteBytes uint64 `json:"writeBytes"` + ReadTime uint64 `json:"readTime"` + WriteTime uint64 `json:"writeTime"` + IopsInProgress uint64 `json:"iopsInProgress"` + IoTime uint64 `json:"ioTime"` + WeightedIO uint64 `json:"weightedIO"` + DiscardCount uint64 `json:"discardCount"` + MergedDiscardCount uint64 `json:"mergedDiscardCount"` + DiscardBytes uint64 `json:"discardBytes"` + DiscardTime uint64 `json:"discardTime"` + FlushCount uint64 `json:"flushCount"` + FlushTime uint64 `json:"flushTime"` + + Name string `json:"name"` + SerialNumber string `json:"serialNumber"` + Label string `json:"label"` } func (d UsageStat) String() string { diff --git a/disk/disk_linux.go b/disk/disk_linux.go index 3911af9..48c6c95 100644 --- a/disk/disk_linux.go +++ b/disk/disk_linux.go @@ -455,18 +455,58 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC if err != nil { return ret, err } + discards := uint64(0) + mergedDiscards := uint64(0) + dbytes := uint64(0) + dtime := uint64(0) + if len(fields) >= 18 { + discards, err = strconv.ParseUint((fields[14]), 10, 64) + if err != nil { + return ret, err + } + mergedDiscards, err = strconv.ParseUint((fields[15]), 10, 64) + if err != nil { + return ret, err + } + dbytes, err = strconv.ParseUint((fields[16]), 10, 64) + if err != nil { + return ret, err + } + dtime, err = strconv.ParseUint((fields[17]), 10, 64) + if err != nil { + return ret, err + } + } + flushes := uint64(0) + ftime := uint64(0) + if len(fields) >= 20 { + flushes, err = strconv.ParseUint((fields[18]), 10, 64) + if err != nil { + return ret, err + } + ftime, err = strconv.ParseUint((fields[19]), 10, 64) + if err != nil { + return ret, err + } + } d := IOCountersStat{ - ReadBytes: rbytes * sectorSize, - WriteBytes: wbytes * sectorSize, - ReadCount: reads, - WriteCount: writes, - MergedReadCount: mergedReads, - MergedWriteCount: mergedWrites, - ReadTime: rtime, - WriteTime: wtime, - IopsInProgress: iopsInProgress, - IoTime: iotime, - WeightedIO: weightedIO, + ReadBytes: rbytes * sectorSize, + WriteBytes: wbytes * sectorSize, + ReadCount: reads, + WriteCount: writes, + MergedReadCount: mergedReads, + MergedWriteCount: mergedWrites, + ReadTime: rtime, + WriteTime: wtime, + IopsInProgress: iopsInProgress, + IoTime: iotime, + WeightedIO: weightedIO, + DiscardCount: discards, + MergedDiscardCount: mergedDiscards, + DiscardBytes: dbytes * sectorSize, + DiscardTime: dtime, + FlushCount: flushes, + FlushTime: ftime, } if d == empty { continue diff --git a/disk/disk_linux_test.go b/disk/disk_linux_test.go new file mode 100644 index 0000000..8d63186 --- /dev/null +++ b/disk/disk_linux_test.go @@ -0,0 +1,122 @@ +//go:build linux +// +build linux + +package disk + +import ( + "os" + "testing" +) + +func TestDiskStatsPost55(t *testing.T) { + orig := os.Getenv("HOST_PROC") + defer os.Setenv("HOST_PROC", orig) + + os.Setenv("HOST_PROC", "testdata/linux/diskstats-post5.5/proc") + ios, err := IOCounters("sda", "sdc") + if err != nil { + t.Error("IOCounters failed") + } + + expected := IOCountersStat{ + ReadCount: 256838102, + MergedReadCount: 620512, + ReadBytes: 5028599594 * sectorSize, + ReadTime: 226563271, + WriteCount: 418236058, + MergedWriteCount: 7573415, + WriteBytes: 8577305933 * sectorSize, + WriteTime: 171833267, + IopsInProgress: 0, + IoTime: 141604084, + WeightedIO: 402232601, + DiscardCount: 168817, + MergedDiscardCount: 110, + DiscardBytes: 4991981424 * sectorSize, + DiscardTime: 387582, + FlushCount: 983197, + FlushTime: 3448479, + Name: "sdc", + SerialNumber: "", + Label: "", + } + if ios["sdc"] != expected { + t.Logf("IOCounterStats gave wrong results: expected %v actual %v", expected, ios["sdc"]) + t.Error("IOCounterStats gave wrong results") + } +} + +func TestDiskStatsPre55(t *testing.T) { + orig := os.Getenv("HOST_PROC") + os.Setenv("HOST_PROC", "testdata/linux/diskstats-pre5.5/proc") + defer os.Setenv("HOST_PROC", orig) + + ios, err := IOCounters("sda", "sdc") + if err != nil { + t.Error("IOCounters failed") + } + expected := IOCountersStat{ + ReadCount: 256838102, + MergedReadCount: 620512, + ReadBytes: 5028599594 * sectorSize, + ReadTime: 226563271, + WriteCount: 418236058, + MergedWriteCount: 7573415, + WriteBytes: 8577305933 * sectorSize, + WriteTime: 171833267, + IopsInProgress: 0, + IoTime: 141604084, + WeightedIO: 402232601, + DiscardCount: 168817, + MergedDiscardCount: 110, + DiscardBytes: 4991981424 * sectorSize, + DiscardTime: 387582, + FlushCount: 0, + FlushTime: 0, + Name: "sdc", + SerialNumber: "", + Label: "", + } + if ios["sdc"] != expected { + t.Logf("IOCounterStats gave wrong results: expected %v actual %v", expected, ios) + t.Error("IOCounterStats gave wrong results") + } + +} + +func TestDiskStatsPre418(t *testing.T) { + orig := os.Getenv("HOST_PROC") + defer os.Setenv("HOST_PROC", orig) + + os.Setenv("HOST_PROC", "testdata/linux/diskstats-pre4.18/proc") + ios, err := IOCounters("sda", "sdc") + if err != nil { + t.Error("IOCounters failed") + } + expected := IOCountersStat{ + ReadCount: 256838102, + MergedReadCount: 620512, + ReadBytes: 5028599594 * sectorSize, + ReadTime: 226563271, + WriteCount: 418236058, + MergedWriteCount: 7573415, + WriteBytes: 8577305933 * sectorSize, + WriteTime: 171833267, + IopsInProgress: 0, + IoTime: 141604084, + WeightedIO: 402232601, + DiscardCount: 0, + MergedDiscardCount: 0, + DiscardBytes: 0, + DiscardTime: 0, + FlushCount: 0, + FlushTime: 0, + Name: "sdc", + SerialNumber: "", + Label: "", + } + if ios["sdc"] != expected { + t.Logf("IOCounterStats gave wrong results: expected %v actual %v", expected, ios["sdc"]) + t.Error("IOCounterStats gave wrong results") + } +} diff --git a/disk/disk_test.go b/disk/disk_test.go index 5adae5c..4f79043 100644 --- a/disk/disk_test.go +++ b/disk/disk_test.go @@ -123,9 +123,11 @@ func TestDiskIOCountersStat_String(t *testing.T) { WriteCount: 200, ReadBytes: 300, WriteBytes: 400, + DiscardCount: 500, + FlushCount: 600, SerialNumber: "SERIAL", } - e := `{"readCount":100,"mergedReadCount":0,"writeCount":200,"mergedWriteCount":0,"readBytes":300,"writeBytes":400,"readTime":0,"writeTime":0,"iopsInProgress":0,"ioTime":0,"weightedIO":0,"name":"sd01","serialNumber":"SERIAL","label":""}` + e := `{"readCount":100,"mergedReadCount":0,"writeCount":200,"mergedWriteCount":0,"readBytes":300,"writeBytes":400,"readTime":0,"writeTime":0,"iopsInProgress":0,"ioTime":0,"weightedIO":0,"discardCount":500,"mergedDiscardCount":0,"discardBytes":0,"discardTime":0,"flushCount":600,"flushTime":0,"name":"sd01","serialNumber":"SERIAL","label":""}` if e != fmt.Sprintf("%v", v) { t.Errorf("DiskUsageStat string is invalid: %v", v) } diff --git a/disk/testdata/linux/diskstats-post5.5/proc/diskstats b/disk/testdata/linux/diskstats-post5.5/proc/diskstats new file mode 100644 index 0000000..8ddc0b9 --- /dev/null +++ b/disk/testdata/linux/diskstats-post5.5/proc/diskstats @@ -0,0 +1,4 @@ + 8 0 sda 251490562 587923 4907991349 207940386 418695352 7259232 8579533525 94584901 0 140322864 306361336 169975 208 4992138504 371249 984400 3464799 + 8 1 sda1 251488338 587923 4907983293 207938421 418695352 7259232 8579533525 94584901 0 140322088 302894572 169975 208 4992138504 371249 0 0 + 8 32 sdc 256838102 620512 5028599594 226563271 418236058 7573415 8577305933 171833267 0 141604084 402232601 168817 110 4991981424 387582 983197 3448479 + 8 33 sdc1 256835879 620512 5028591546 226561154 418236058 7573415 8577305933 171833267 0 141603284 398782004 168817 110 4991981424 387582 0 0 \ No newline at end of file diff --git a/disk/testdata/linux/diskstats-pre4.18/diskstats b/disk/testdata/linux/diskstats-pre4.18/diskstats new file mode 100644 index 0000000..0ca92a2 --- /dev/null +++ b/disk/testdata/linux/diskstats-pre4.18/diskstats @@ -0,0 +1,4 @@ + 8 0 sda 251490562 587923 4907991349 207940386 418695352 7259232 8579533525 94584901 0 140322864 306361336 + 8 1 sda1 251488338 587923 4907983293 207938421 418695352 7259232 8579533525 94584901 0 140322088 302894572 + 8 32 sdc 256838102 620512 5028599594 226563271 418236058 7573415 8577305933 171833267 0 141604084 402232601 + 8 33 sdc1 256835879 620512 5028591546 226561154 418236058 7573415 8577305933 171833267 0 141603284 398782004 \ No newline at end of file diff --git a/disk/testdata/linux/diskstats-pre4.18/proc/diskstats b/disk/testdata/linux/diskstats-pre4.18/proc/diskstats new file mode 100644 index 0000000..0ca92a2 --- /dev/null +++ b/disk/testdata/linux/diskstats-pre4.18/proc/diskstats @@ -0,0 +1,4 @@ + 8 0 sda 251490562 587923 4907991349 207940386 418695352 7259232 8579533525 94584901 0 140322864 306361336 + 8 1 sda1 251488338 587923 4907983293 207938421 418695352 7259232 8579533525 94584901 0 140322088 302894572 + 8 32 sdc 256838102 620512 5028599594 226563271 418236058 7573415 8577305933 171833267 0 141604084 402232601 + 8 33 sdc1 256835879 620512 5028591546 226561154 418236058 7573415 8577305933 171833267 0 141603284 398782004 \ No newline at end of file diff --git a/disk/testdata/linux/diskstats-pre5.5/proc/diskstats b/disk/testdata/linux/diskstats-pre5.5/proc/diskstats new file mode 100644 index 0000000..afdbdab --- /dev/null +++ b/disk/testdata/linux/diskstats-pre5.5/proc/diskstats @@ -0,0 +1,4 @@ + 8 0 sda 251490562 587923 4907991349 207940386 418695352 7259232 8579533525 94584901 0 140322864 306361336 169975 208 4992138504 371249 + 8 1 sda1 251488338 587923 4907983293 207938421 418695352 7259232 8579533525 94584901 0 140322088 302894572 169975 208 4992138504 371249 + 8 32 sdc 256838102 620512 5028599594 226563271 418236058 7573415 8577305933 171833267 0 141604084 402232601 168817 110 4991981424 387582 + 8 33 sdc1 256835879 620512 5028591546 226561154 418236058 7573415 8577305933 171833267 0 141603284 398782004 168817 110 4991981424 387582 \ No newline at end of file From 4201ef19df877533ed45526c9c20a970fc02a4e3 Mon Sep 17 00:00:00 2001 From: Joseph Malicki Date: Wed, 1 Jun 2022 12:02:07 -0700 Subject: [PATCH 2/2] gofmt --- disk/disk.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/disk/disk.go b/disk/disk.go index 18df3a8..d61c5fa 100644 --- a/disk/disk.go +++ b/disk/disk.go @@ -41,13 +41,12 @@ type IOCountersStat struct { IopsInProgress uint64 `json:"iopsInProgress"` IoTime uint64 `json:"ioTime"` WeightedIO uint64 `json:"weightedIO"` - DiscardCount uint64 `json:"discardCount"` + DiscardCount uint64 `json:"discardCount"` MergedDiscardCount uint64 `json:"mergedDiscardCount"` DiscardBytes uint64 `json:"discardBytes"` DiscardTime uint64 `json:"discardTime"` FlushCount uint64 `json:"flushCount"` FlushTime uint64 `json:"flushTime"` - Name string `json:"name"` SerialNumber string `json:"serialNumber"` Label string `json:"label"`