Skip to content
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ The following individuals have contributed code to this repository
* Nicky Gerritsen <nicky@streamone.nl>
* Rémi Audebert <contact@halfr.net>
* Tobias Schmidt <tobidt@gmail.com>
* Abhi Yerra <abhi@berkeley.edu>
42 changes: 42 additions & 0 deletions fixtures/meminfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
MemTotal: 15666184 kB
MemFree: 440324 kB
Buffers: 1020128 kB
Cached: 12007640 kB
SwapCached: 0 kB
Active: 6761276 kB
Inactive: 6532708 kB
Active(anon): 267256 kB
Inactive(anon): 268 kB
Active(file): 6494020 kB
Inactive(file): 6532440 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 768 kB
Writeback: 0 kB
AnonPages: 266216 kB
Mapped: 44204 kB
Shmem: 1308 kB
Slab: 1807264 kB
SReclaimable: 1738124 kB
SUnreclaim: 69140 kB
KernelStack: 1616 kB
PageTables: 5288 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 7833092 kB
Committed_AS: 530844 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 36596 kB
VmallocChunk: 34359637840 kB
HardwareCorrupted: 0 kB
AnonHugePages: 12288 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 91136 kB
DirectMap2M: 16039936 kB
6 changes: 6 additions & 0 deletions fixtures/net/sockstat
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sockets: used 3014
TCP: inuse 3168 orphan 612 tw 13701 alloc 3169 mem 2734
UDP: inuse 9 mem 2
UDPLITE: inuse 0
RAW: inuse 1
FRAG: inuse 2 memory 2
20 changes: 20 additions & 0 deletions fixtures/net/tcp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16071 1 0000000000000000 100 0 0 10 0
1: 00000000:0056 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16481 1 0000000000000000 100 0 0 10 0
2: 00000000:0057 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16482 1 0000000000000000 100 0 0 10 0
3: 00000000:0BB8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 516865617 1 0000000000000000 100 0 0 10 0
4: 00000000:0058 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16476 1 0000000000000000 100 0 0 10 0
5: 00000000:0059 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16480 1 0000000000000000 100 0 0 10 0
6: 00000000:005A 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 16479 1 0000000000000000 100 0 0 10 0
7: 00000000:01BB 00000000:0000 0A 00000000:00000000 02:00000002 00000000 0 0 3994549147 2 0000000000000000 100 0 1 10 0
8: 260FC90A:01BB AE6857C8:C747 03 00000000:00000000 01:000000DC 00000005 0 0 0 2 0000000000000000
9: 260FC90A:01BB 0E7F51DE:7A79 03 00000000:00000000 01:0000084A 00000005 0 0 0 2 0000000000000000
10: 260FC90A:01BB 89E2E3C9:749B 03 00000000:00000000 01:00000A16 00000005 0 0 0 2 0000000000000000
11: 260FC90A:01BB AE6857C8:C752 03 00000000:00000000 01:0000008E 00000002 0 0 0 2 0000000000000000
12: 260FC90A:01BB D81B38AC:64F9 03 00000000:00000000 01:00000063 00000000 0 0 0 2 0000000000000000
13: 260FC90A:01BB 14288875:155E 03 00000000:00000000 01:00000A16 00000005 0 0 0 2 0000000000000000
14: 260FC90A:01BB 53202464:C9D6 03 00000000:00000000 01:00000051 00000000 0 0 0 2 0000000000000000
15: 260FC90A:01BB 5C49E8DD:F022 03 00000000:00000000 01:0000021F 00000004 0 0 0 2 0000000000000000
16: 260FC90A:01BB 9A99935B:AFF3 03 00000000:00000000 01:00000246 00000004 0 0 0 2 0000000000000000
17: 260FC90A:01BB 231D4B4B:EF00 03 00000000:00000000 01:000001BA 00000004 0 0 0 2 0000000000000000
18: 260FC90A:01BB 162491A5:C524 03 00000000:00000000 01:00000272 00000004 0 0 0 2 0000000000000000
174 changes: 174 additions & 0 deletions meminfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package procfs

import (
"bufio"
"os"
"reflect"
"regexp"
"strconv"
)

// Meminfo represents memory statistics.
type Meminfo struct {
// Total usable ram (i.e. physical ram minus a few reserved
// bits and the kernel binary code)
MemTotal int64 `meminfo:"MemTotal"`
// The sum of LowFree+HighFree
MemFree int64 `meminfo:"MemFree"`
// An estimate of how much memory is available for starting
// new applications, without swapping. Calculated from
// MemFree, SReclaimable, the size of the file LRU lists, and
// the low watermarks in each zone. The estimate takes into
// account that the system needs some page cache to function
// well, and that not all reclaimable slab will be
// reclaimable, due to items being in use. The impact of those
// factors will vary from system to system.
MemAvailable int64 `meminfo:"MemAvailable"`
// Relatively temporary storage for raw disk blocks shouldn't
// get tremendously large (20MB or so)
Buffers int64 `meminfo:"Buffers"`
Cached int64 `meminfo:"Cached"`
// Memory that once was swapped out, is swapped back in but
// still also is in the swapfile (if memory is needed it
// doesn't need to be swapped out AGAIN because it is already
// in the swapfile. This saves I/O)
SwapCached int64 `meminfo:"SwapCached"`
// Memory that has been used more recently and usually not
// reclaimed unless absolutely necessary.
Active int64 `meminfo:"Active"`
// Memory which has been less recently used. It is more
// eligible to be reclaimed for other purposes
Inactive int64 `meminfo:"Inactive"`
ActiveAnon int64 `meminfo:"Active(anon)"`
InactiveAnon int64 `meminfo:"Inactive(anon)"`
ActiveFile int64 `meminfo:"Active(file)"`
InactiveFile int64 `meminfo:"Inactive(file)"`
Unevictable int64 `meminfo:"Unevictable"`
Mlocked int64 `meminfo:"Mlocked"`
// total amount of swap space available
SwapTotal int64 `meminfo:"SwapTotal"`
// Memory which has been evicted from RAM, and is temporarily
// on the disk
SwapFree int64 `meminfo:"SwapFree"`
// Memory which is waiting to get written back to the disk
Dirty int64 `meminfo:"Dirty"`
// Memory which is actively being written back to the disk
Writeback int64 `meminfo:"Writeback"`
// Non-file backed pages mapped into userspace page tables
AnonPages int64 `meminfo:"AnonPages"`
// files which have been mmaped, such as libraries
Mapped int64 `meminfo:"Mapped"`
Shmem int64 `meminfo:"Shmem"`
// in-kernel data structures cache
Slab int64 `meminfo:"Slab"`
// Part of Slab, that might be reclaimed, such as caches
SReclaimable int64 `meminfo:"SReclaimable"`
// Part of Slab, that cannot be reclaimed on memory pressure
SUnreclaim int64 `meminfo:"SUnreclaim"`
KernelStack int64 `meminfo:"KernelStack"`
// amount of memory dedicated to the lowest level of page
// tables.
PageTables int64 `meminfo:"PageTables"`
// NFS pages sent to the server, but not yet committed to
// stable storage
NFSUnstable int64 `meminfo:"NFS_Unstable"`
// Memory used for block device "bounce buffers"
Bounce int64 `meminfo:"Bounce"`
// Memory used by FUSE for temporary writeback buffers
WritebackTmp int64 `meminfo:"WritebackTmp"`
// Based on the overcommit ratio ('vm.overcommit_ratio'),
// this is the total amount of memory currently available to
// be allocated on the system. This limit is only adhered to
// if strict overcommit accounting is enabled (mode 2 in
// 'vm.overcommit_memory').
// The CommitLimit is calculated with the following formula:
// CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
// overcommit_ratio / 100 + [total swap pages]
// For example, on a system with 1G of physical RAM and 7G
// of swap with a `vm.overcommit_ratio` of 30 it would
// yield a CommitLimit of 7.3G.
// For more details, see the memory overcommit documentation
// in vm/overcommit-accounting.
CommitLimit int64 `meminfo:"CommitLimit"`
// The amount of memory presently allocated on the system.
// The committed memory is a sum of all of the memory which
// has been allocated by processes, even if it has not been
// "used" by them as of yet. A process which malloc()'s 1G
// of memory, but only touches 300M of it will show up as
// using 1G. This 1G is memory which has been "committed" to
// by the VM and can be used at any time by the allocating
// application. With strict overcommit enabled on the system
// (mode 2 in 'vm.overcommit_memory'),allocations which would
// exceed the CommitLimit (detailed above) will not be permitted.
// This is useful if one needs to guarantee that processes will
// not fail due to lack of memory once that memory has been
// successfully allocated.
CommittedAS int64 `meminfo:"Committed_AS"`
// total size of vmalloc memory area
VmallocTotal int64 `meminfo:"VmallocTotal"`
// amount of vmalloc area which is used
VmallocUsed int64 `meminfo:"VmallocUsed"`
// largest contiguous block of vmalloc area which is free
VmallocChunk int64 `meminfo:"VmallocChunk"`
HardwareCorrupted int64 `meminfo:"HardwareCorrupted"`
AnonHugePages int64 `meminfo:"AnonHugePages"`
HugePagesTotal int64 `meminfo:"HugePages_Total"`
HugePagesFree int64 `meminfo:"HugePages_Free"`
HugePagesRsvd int64 `meminfo:"HugePages_Rsvd"`
HugePagesSurp int64 `meminfo:"HugePages_Surp"`
Hugepagesize int64 `meminfo:"Hugepagesize"`
DirectMap4k int64 `meminfo:"DirectMap4k"`
DirectMap2M int64 `meminfo:"DirectMap2M"`
}

// NewMeminfo returns kernel/system statistics read from /proc/stat.
func NewMeminfo() (Meminfo, error) {
fs, err := NewFS(DefaultMountPoint)
if err != nil {
return Meminfo{}, err
}

return fs.NewMeminfo()
}

// NewMeminfo returns an information about current kernel/system statistics.
func (fs FS) NewMeminfo() (m Meminfo, err error) {
f, err := os.Open(fs.Path("meminfo"))
if err != nil {
return Meminfo{}, err
}
defer f.Close()

st := reflect.TypeOf(m)
re := regexp.MustCompile(m.regex())
s := bufio.NewScanner(f)

for s.Scan() {
line := s.Text()

submatch := re.FindAllStringSubmatch(line, 1)
if submatch == nil {
continue
}

key := submatch[0][1]
val := submatch[0][2]

for i := 0; i < st.NumField(); i++ {
field := st.Field(i)
if field.Tag.Get("meminfo") == key {
v, err := strconv.ParseInt(val, 10, 64)
if err != nil {
// no op
}
reflect.ValueOf(&m).Elem().Field(i).SetInt(v)
}
}
}

return m, nil
}

func (m Meminfo) regex() string {
return "([A-Za-z0-9()_]*): *([0-9]*).*$"
}
118 changes: 118 additions & 0 deletions meminfo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package procfs

import (
"reflect"
"regexp"
"testing"
)

func TestMeminfo_regex(t *testing.T) {

var expected = []struct {
Line string
Key string
Value string
}{
{
Line: "Inactive(file): 6532440 kB",
Key: "Inactive(file)",
Value: "6532440",
},
{
Line: "Writeback: 0 kB",

Key: "Writeback",
Value: "0",
},
{
Line: "Writeback: 123",
Key: "Writeback",
Value: "123",
},
{
Line: "HugePages_Total: 0",
Key: "HugePages_Total",
Value: "0",
},
{
Line: "DirectMap2M: 16039936 kB",
Key: "DirectMap2M",
Value: "16039936",
},
}

m := Meminfo{}
re := regexp.MustCompile(m.regex())

for _, i := range expected {
submatch := re.FindAllStringSubmatch(i.Line, 1)
if submatch == nil {
t.Errorf("regex fail")
}

if submatch[0][1] != i.Key {
t.Errorf("Key failed for %s", i.Key)
}
if submatch[0][2] != i.Value {
t.Errorf("Value failed for %s", i.Value)
}

}

}

func TestMeminfo(t *testing.T) {
expected := Meminfo{
MemTotal: 15666184,
MemFree: 440324,
Buffers: 1020128,
Cached: 12007640,
SwapCached: 0,
Active: 6761276,
Inactive: 6532708,
ActiveAnon: 267256,
InactiveAnon: 268,
ActiveFile: 6494020,
InactiveFile: 6532440,
Unevictable: 0,
Mlocked: 0,
SwapTotal: 0,
SwapFree: 0,
Dirty: 768,
Writeback: 0,
AnonPages: 266216,
Mapped: 44204,
Shmem: 1308,
Slab: 1807264,
SReclaimable: 1738124,
SUnreclaim: 69140,
KernelStack: 1616,
PageTables: 5288,
NFSUnstable: 0,
Bounce: 0,
WritebackTmp: 0,
CommitLimit: 7833092,
CommittedAS: 530844,
VmallocTotal: 34359738367,
VmallocUsed: 36596,
VmallocChunk: 34359637840,
HardwareCorrupted: 0,
AnonHugePages: 12288,
HugePagesTotal: 0,
HugePagesFree: 0,
HugePagesRsvd: 0,
HugePagesSurp: 0,
Hugepagesize: 2048,
DirectMap4k: 91136,
DirectMap2M: 16039936,
}

have, err := FS("fixtures").NewMeminfo()
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(have, expected) {
t.Errorf("structs are not equal")
}
}
Loading