Skip to content

Commit

Permalink
Use MemAvailable when it's available for Linux 3.14+ kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
monicasarbu committed May 10, 2017
1 parent 653b7f4 commit 34de5a6
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
privileges in a process token.
- Added utility code for interfacing with linux NETLINK_INET_DIAG. #60
- Added `ProcEnv` for getting a process's environment variables. #61
- Read `MemAvailable` value for kernel 3.14+

### Changed
- Changed several `OpenProcess` calls on Windows to request the lowest possible
Expand Down
59 changes: 34 additions & 25 deletions sigar_linux_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,38 @@ func (self *LoadAverage) Get() error {
}

func (self *Mem) Get() error {
var buffers, cached uint64
table := map[string]*uint64{
"MemTotal": &self.Total,
"MemFree": &self.Free,
"Buffers": &buffers,
"Cached": &cached,
}

if err := parseMeminfo(table); err != nil {
table, err := parseMeminfo()
if err != nil {
return err
}

self.Used = self.Total - self.Free
kern := buffers + cached
self.ActualFree = self.Free + kern
self.ActualUsed = self.Used - kern
self.Total, _ = table["MemTotal"]
self.Free, _ = table["MemFree"]
buffers, _ := table["Buffers"]
cached, _ := table["Cached"]

if available, ok := table["MemAvailable"]; ok {
// MemAvailable is in /proc/meminfo (kernel 3.14+)
self.ActualFree = available
} else {
self.ActualFree = self.Free + buffers + cached
}

self.Used = self.Total - self.ActualFree
self.ActualUsed = self.Used

return nil
}

func (self *Swap) Get() error {
table := map[string]*uint64{
"SwapTotal": &self.Total,
"SwapFree": &self.Free,
}

if err := parseMeminfo(table); err != nil {
table, err := parseMeminfo()
if err != nil {
return err
}
self.Total, _ = table["SwapTotal"]
self.Free, _ = table["SwapFree"]

self.Used = self.Total - self.Free
return nil
Expand Down Expand Up @@ -353,20 +356,26 @@ func (self *ProcExe) Get(pid int) error {
return nil
}

func parseMeminfo(table map[string]*uint64) error {
return readFile(Procd+"/meminfo", func(line string) bool {
func parseMeminfo() (map[string]uint64, error) {
table := map[string]uint64{}

err := readFile(Procd+"/meminfo", func(line string) bool {
fields := strings.Split(line, ":")

if ptr := table[fields[0]]; ptr != nil {
num := strings.TrimLeft(fields[1], " ")
val, err := strtoull(strings.Fields(num)[0])
if err == nil {
*ptr = val * 1024
}
if len(fields) != 2 {
return true // skip on errors
}

num := strings.TrimLeft(fields[1], " ")
val, err := strtoull(strings.Fields(num)[0])
if err != nil {
return true // skip on errors
}
table[fields[0]] = val * 1024 //in bytes

return true
})
return table, err
}

func readFile(file string, handler func(string) bool) error {
Expand Down
219 changes: 219 additions & 0 deletions sigar_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,225 @@ DirectMap2M: 333824 kB
}
}

func TestLinuxMemAndSwapKernel_3_14(t *testing.T) {
setUp(t)
defer tearDown(t)

meminfoContents := `
MemTotal: 500184 kB
MemFree: 31360 kB
MemAvailable: 414168 kB
Buffers: 28740 kB
Cached: 325408 kB
SwapCached: 264 kB
Active: 195476 kB
Inactive: 198612 kB
Active(anon): 14920 kB
Inactive(anon): 27268 kB
Active(file): 180556 kB
Inactive(file): 171344 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 524284 kB
SwapFree: 520352 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 39772 kB
Mapped: 24132 kB
Shmem: 2236 kB
Slab: 57988 kB
SReclaimable: 43524 kB
SUnreclaim: 14464 kB
KernelStack: 2464 kB
PageTables: 3096 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 774376 kB
Committed_AS: 490916 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 63424 kB
DirectMap2M: 460800 kB
`

meminfoFile := procd + "/meminfo"
err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444)
if err != nil {
t.Fatal(err)
}

mem := sigar.Mem{}
if assert.NoError(t, mem.Get()) {
assert.Equal(t, uint64(500184*1024), mem.Total)
assert.Equal(t, uint64(31360*1024), mem.Free)
assert.Equal(t, uint64(414168*1024), mem.ActualFree)
}

swap := sigar.Swap{}
if assert.NoError(t, swap.Get()) {
assert.Equal(t, uint64(524284*1024), swap.Total)
assert.Equal(t, uint64(520352*1024), swap.Free)
}
}

func TestLinuxMemAndSwapMissingMemTotal(t *testing.T) {
setUp(t)
defer tearDown(t)

meminfoContents := `
MemFree: 31360 kB
MemAvailable: 414168 kB
Buffers: 28740 kB
Cached: 325408 kB
SwapCached: 264 kB
Active: 195476 kB
Inactive: 198612 kB
Active(anon): 14920 kB
Inactive(anon): 27268 kB
Active(file): 180556 kB
Inactive(file): 171344 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 524284 kB
SwapFree: 520352 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 39772 kB
Mapped: 24132 kB
Shmem: 2236 kB
Slab: 57988 kB
SReclaimable: 43524 kB
SUnreclaim: 14464 kB
KernelStack: 2464 kB
PageTables: 3096 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 774376 kB
Committed_AS: 490916 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 63424 kB
DirectMap2M: 460800 kB
`

meminfoFile := procd + "/meminfo"
err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444)
if err != nil {
t.Fatal(err)
}

mem := sigar.Mem{}
if assert.NoError(t, mem.Get()) {
assert.Equal(t, uint64(0), mem.Total)
assert.Equal(t, uint64(31360*1024), mem.Free)
assert.Equal(t, uint64(414168*1024), mem.ActualFree)
}

swap := sigar.Swap{}
if assert.NoError(t, swap.Get()) {
assert.Equal(t, uint64(524284*1024), swap.Total)
assert.Equal(t, uint64(520352*1024), swap.Free)
}
}

func TestLinuxMemAndSwapKernel_3_14_memavailable_zero(t *testing.T) {
setUp(t)
defer tearDown(t)

meminfoContents := `
MemTotal: 148535680 kB
MemFree: 417356 kB
MemAvailable: 0 kB
Buffers: 1728 kB
Cached: 129928 kB
SwapCached: 8208 kB
Active: 141088676 kB
Inactive: 5568132 kB
Active(anon): 141076780 kB
Inactive(anon): 5556936 kB
Active(file): 11896 kB
Inactive(file): 11196 kB
Unevictable: 3648 kB
Mlocked: 3648 kB
SwapTotal: 4882428 kB
SwapFree: 0 kB
Dirty: 808 kB
Writeback: 220 kB
AnonPages: 146521272 kB
Mapped: 41384 kB
Shmem: 105864 kB
Slab: 522648 kB
SReclaimable: 233508 kB
SUnreclaim: 289140 kB
KernelStack: 85024 kB
PageTables: 368760 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 79150268 kB
Committed_AS: 272491684 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 78061568 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 124388 kB
DirectMap2M: 5105664 kB
DirectMap1G: 147849216 kB
`

meminfoFile := procd + "/meminfo"
err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444)
if err != nil {
t.Fatal(err)
}

mem := sigar.Mem{}
if assert.NoError(t, mem.Get()) {
assert.Equal(t, uint64(148535680*1024), mem.Total)
assert.Equal(t, uint64(417356*1024), mem.Free)
assert.Equal(t, uint64(0), mem.ActualFree)
}

swap := sigar.Swap{}
if assert.NoError(t, swap.Get()) {
assert.Equal(t, uint64(4882428*1024), swap.Total)
assert.Equal(t, uint64(0), swap.Free)
}

}

func TestFDUsage(t *testing.T) {
setUp(t)
defer tearDown(t)
Expand Down

0 comments on commit 34de5a6

Please sign in to comment.