Skip to content

Commit

Permalink
SD-1123 Collect disk IO stats on Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Gardner committed Apr 22, 2015
1 parent 81b043e commit 9608cd4
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 1 deletion.
2 changes: 1 addition & 1 deletion fakes/fake_sigar.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package fakes
import (
"time"

sigar "github.com/cloudfoundry/gosigar"
sigar "github.com/scalingdata//gosigar"
)

type FakeSigar struct {
Expand Down
9 changes: 9 additions & 0 deletions sigar_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ func (self *FileSystemList) Get() error {
return err
}

func (self *DiskList) Get() error {
return notImplemented()
}

func (self *ProcList) Get() error {
n := C.proc_listpids(C.PROC_ALL_PIDS, 0, nil, 0)
if n <= 0 {
Expand Down Expand Up @@ -465,3 +469,8 @@ func task_info(pid int, info *C.struct_proc_taskallinfo) error {

return nil
}

func notImplemented() error {
panic("Not Implemented")
return nil
}
26 changes: 26 additions & 0 deletions sigar_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,29 @@ type ProcExe struct {
Cwd string
Root string
}

type DiskList struct {
List map[string]DiskIo
}

type DiskIo struct {
ReadOps uint64
ReadBytes uint64
ReadTimeMs uint64
WriteOps uint64
WriteBytes uint64
WriteTimeMs uint64
IoTimeMs uint64
}

func (self DiskIo) Delta(other DiskIo) DiskIo {
return DiskIo {
ReadOps: self.ReadOps - other.ReadOps,
ReadBytes: self.ReadBytes - other.ReadBytes,
ReadTimeMs: self.ReadTimeMs - other.ReadTimeMs,
WriteOps: self.WriteOps - other.WriteOps,
WriteBytes: self.WriteBytes - other.WriteBytes,
WriteTimeMs: self.WriteTimeMs - other.WriteTimeMs,
IoTimeMs: self.IoTimeMs - other.IoTimeMs,
}
}
70 changes: 70 additions & 0 deletions sigar_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,58 @@ func (self *FileSystemList) Get() error {
return err
}

func (self *DiskList) Get() error {
/* List all the partitions, and check the major/minor device ID
to find which are devices vs. partitions (ex. sda v. sda1) */
devices := make(map[string]bool)
diskList := make(map[string]DiskIo)
err := readFile(Procd+"/partitions", func(line string) bool {
fields := strings.Fields(line)
if len(fields) < 4 {
return true
}
majorDevId, err := strtoull(fields[0])
if err != nil {
return true
}
minorDevId, err := strtoull(fields[1])
if err != nil {
return true
}
if isNotPartition(majorDevId, minorDevId) {
devices[fields[3]] = true
}
return true
})

/* Get all device stats from /proc/diskstats and filter by
devices from /proc/partitions */
err = readFile(Procd+"/diskstats", func(line string) bool {
fields := strings.Fields(line)
if len(fields) < 13 {
return true
}
deviceName := fields[2]
if _, ok := devices[deviceName]; !ok {
return true
}
io := DiskIo {}
io.ReadOps, _ = strtoull(fields[3])
readBytes, _ := strtoull(fields[5])
io.ReadBytes = readBytes * 512
io.ReadTimeMs, _ = strtoull(fields[6])
io.WriteOps, _ = strtoull(fields[7])
writeBytes, _ := strtoull(fields[9])
io.WriteBytes = writeBytes * 512
io.WriteTimeMs, _ = strtoull(fields[10])
io.IoTimeMs, _ = strtoull(fields[12])
diskList[deviceName] = io
return true
})
self.List = diskList
return err
}

func (self *ProcList) Get() error {
dir, err := os.Open(Procd)
if err != nil {
Expand Down Expand Up @@ -388,3 +440,21 @@ func readProcFile(pid int, name string) ([]byte, error) {

return contents, err
}

/* For SCSI and IDE devices, only display devices and not individual partitions.
For other major numbers, show all devices regardless of minor (for LVM, for example).
As described here: http://www.linux-tutorial.info/modules.php?name=MContent&pageid=94 */
func isNotPartition(majorDevId, minorDevId uint64) bool {
if majorDevId == 3 || majorDevId == 22 || // IDE0_MAJOR IDE1_MAJOR
majorDevId == 33 || majorDevId == 34 || // IDE2_MAJOR IDE3_MAJOR
majorDevId == 56 || majorDevId == 57 || // IDE4_MAJOR IDE5_MAJOR
(majorDevId >= 88 && majorDevId <= 91) { // IDE6_MAJOR to IDE_IDE9_MAJOR
return (minorDevId & 0x3F) == 0 // IDE uses bottom 10 bits for partitions
}
if majorDevId == 8 || // SCSI_DISK0_MAJOR
(majorDevId >= 65 && majorDevId <= 71) || // SCSI_DISK1_MAJOR to SCSI_DISK7_MAJOR
(majorDevId >= 128 && majorDevId <= 135) { // SCSI_DISK8_MAJOR to SCSI_DISK15_MAJOR
return (minorDevId & 0x0F) == 0 // SCSI uses bottom 8 bits for partitions
}
return true
}
79 changes: 79 additions & 0 deletions sigar_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,83 @@ DirectMap2M: 333824 kB
Expect(swap.Free).To(BeNumerically("==", 786428*1024))
})
})

Describe("DiskIO", func() {
var diskstatFile string
var partitionsFile string
BeforeEach(func() {
partitionsFile = procd + "/partitions"
partitionsContents := `
major minor #blocks name
8 0 41943040 sda
8 1 512000 sda1
8 2 41430016 sda2
253 0 40476672 dm-0
253 1 950272 dm-1
`
diskstatFile = procd + "/diskstats"
diskstatContents := `
1 0 ram0 0 0 0 0 0 0 0 0 0 0 0
1 1 ram1 0 0 0 0 0 0 0 0 0 0 0
1 2 ram2 0 0 0 0 0 0 0 0 0 0 0
1 3 ram3 0 0 0 0 0 0 0 0 0 0 0
1 4 ram4 0 0 0 0 0 0 0 0 0 0 0
1 5 ram5 0 0 0 0 0 0 0 0 0 0 0
1 6 ram6 0 0 0 0 0 0 0 0 0 0 0
1 7 ram7 0 0 0 0 0 0 0 0 0 0 0
1 8 ram8 0 0 0 0 0 0 0 0 0 0 0
1 9 ram9 0 0 0 0 0 0 0 0 0 0 0
1 10 ram10 0 0 0 0 0 0 0 0 0 0 0
1 11 ram11 0 0 0 0 0 0 0 0 0 0 0
1 12 ram12 0 0 0 0 0 0 0 0 0 0 0
1 13 ram13 0 0 0 0 0 0 0 0 0 0 0
1 14 ram14 0 0 0 0 0 0 0 0 0 0 0
1 15 ram15 0 0 0 0 0 0 0 0 0 0 0
7 0 loop0 0 0 0 0 0 0 0 0 0 0 0
7 1 loop1 0 0 0 0 0 0 0 0 0 0 0
7 2 loop2 0 0 0 0 0 0 0 0 0 0 0
7 3 loop3 0 0 0 0 0 0 0 0 0 0 0
7 4 loop4 0 0 0 0 0 0 0 0 0 0 0
7 5 loop5 0 0 0 0 0 0 0 0 0 0 0
7 6 loop6 0 0 0 0 0 0 0 0 0 0 0
7 7 loop7 0 0 0 0 0 0 0 0 0 0 0
8 0 sda 7089 1514 243714 6329 86342 820181 7159936 1397746 0 50380 1404142
8 1 sda1 560 243 12192 133 64 5182 10504 955 0 218 1085
8 2 sda2 6375 1271 230290 6161 77130 814999 7149432 1395024 0 48563 1401264
253 0 dm-0 7255 0 226842 8638 895753 0 7149432 40185506 0 50361 40194137
253 1 dm-1 307 0 2456 116 0 0 0 0 0 116 116
`
err := ioutil.WriteFile(partitionsFile, []byte(partitionsContents), 0444)
Expect(err).ToNot(HaveOccurred())

err = ioutil.WriteFile(diskstatFile, []byte(diskstatContents), 0444)
Expect(err).ToNot(HaveOccurred())
})

It("skips non-block devices", func() {
ioStat := sigar.DiskList{}
err := ioStat.Get()
Expect(err).ToNot(HaveOccurred())

_, ok := ioStat.List["ram0"]
Expect(ok).To(Equal(false))
_, ok = ioStat.List["loop0"]
Expect(ok).To(Equal(false))
})

It("returns correct disk IO info", func() {
ioStat := sigar.DiskList{}
err := ioStat.Get()
Expect(err).ToNot(HaveOccurred())

Expect(ioStat.List["sda"].ReadOps).To(Equal(uint64(7089)))
Expect(ioStat.List["sda"].ReadBytes).To(Equal(uint64(243714 * 512)))
Expect(ioStat.List["sda"].ReadTimeMs).To(Equal(uint64(6329)))
Expect(ioStat.List["sda"].WriteOps).To(Equal(uint64(86342)))
Expect(ioStat.List["sda"].WriteBytes).To(Equal(uint64(7159936 * 512)))
Expect(ioStat.List["sda"].WriteTimeMs).To(Equal(uint64(1397746)))
Expect(ioStat.List["sda"].IoTimeMs).To(Equal(uint64(50380)))
})
})
})
4 changes: 4 additions & 0 deletions sigar_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ func (self *FileSystemList) Get() error {
return notImplemented()
}

func (self *DiskList) Get() error {
return notImplemented()
}

func (self *ProcList) Get() error {
return notImplemented()
}
Expand Down

0 comments on commit 9608cd4

Please sign in to comment.