Browse code

Merge pull request #8550 from aluzzardi/f-meminfo

system: Add MemInfo utility.

unclejack authored on 2014/10/23 15:31:28
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+package system
1
+
2
+// MemInfo contains memory statistics of the host system.
3
+type MemInfo struct {
4
+	// Total usable RAM (i.e. physical RAM minus a few reserved bits and the
5
+	// kernel binary code).
6
+	MemTotal int64
7
+
8
+	// Amount of free memory.
9
+	MemFree int64
10
+
11
+	// Total amount of swap space available.
12
+	SwapTotal int64
13
+
14
+	// Amount of swap space that is currently unused.
15
+	SwapFree int64
16
+}
0 17
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package system
1
+
2
+import (
3
+	"bufio"
4
+	"errors"
5
+	"io"
6
+	"os"
7
+	"strconv"
8
+	"strings"
9
+
10
+	"github.com/docker/docker/pkg/units"
11
+)
12
+
13
+var (
14
+	ErrMalformed = errors.New("malformed file")
15
+)
16
+
17
+// Retrieve memory statistics of the host system and parse them into a MemInfo
18
+// type.
19
+func ReadMemInfo() (*MemInfo, error) {
20
+	file, err := os.Open("/proc/meminfo")
21
+	if err != nil {
22
+		return nil, err
23
+	}
24
+	defer file.Close()
25
+	return parseMemInfo(file)
26
+}
27
+
28
+func parseMemInfo(reader io.Reader) (*MemInfo, error) {
29
+	meminfo := &MemInfo{}
30
+	scanner := bufio.NewScanner(reader)
31
+	for scanner.Scan() {
32
+		// Expected format: ["MemTotal:", "1234", "kB"]
33
+		parts := strings.Fields(scanner.Text())
34
+
35
+		// Sanity checks: Skip malformed entries.
36
+		if len(parts) < 3 || parts[2] != "kB" {
37
+			continue
38
+		}
39
+
40
+		// Convert to bytes.
41
+		size, err := strconv.Atoi(parts[1])
42
+		if err != nil {
43
+			continue
44
+		}
45
+		bytes := int64(size) * units.KiB
46
+
47
+		switch parts[0] {
48
+		case "MemTotal:":
49
+			meminfo.MemTotal = bytes
50
+		case "MemFree:":
51
+			meminfo.MemFree = bytes
52
+		case "SwapTotal:":
53
+			meminfo.SwapTotal = bytes
54
+		case "SwapFree:":
55
+			meminfo.SwapFree = bytes
56
+		}
57
+
58
+	}
59
+
60
+	// Handle errors that may have occurred during the reading of the file.
61
+	if err := scanner.Err(); err != nil {
62
+		return nil, err
63
+	}
64
+
65
+	return meminfo, nil
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package system
1
+
2
+import (
3
+	"strings"
4
+	"testing"
5
+
6
+	"github.com/docker/docker/pkg/units"
7
+)
8
+
9
+func TestMemInfo(t *testing.T) {
10
+	const input = `
11
+	MemTotal:      1 kB
12
+	MemFree:       2 kB
13
+	SwapTotal:     3 kB
14
+	SwapFree:      4 kB
15
+	Malformed1:
16
+	Malformed2:    1
17
+	Malformed3:    2 MB
18
+	Malformed4:    X kB
19
+	`
20
+	meminfo, err := parseMemInfo(strings.NewReader(input))
21
+	if err != nil {
22
+		t.Fatal(err)
23
+	}
24
+	if meminfo.MemTotal != 1*units.KiB {
25
+		t.Fatalf("Unexpected MemTotal: %d", meminfo.MemTotal)
26
+	}
27
+	if meminfo.MemFree != 2*units.KiB {
28
+		t.Fatalf("Unexpected MemFree: %d", meminfo.MemFree)
29
+	}
30
+	if meminfo.SwapTotal != 3*units.KiB {
31
+		t.Fatalf("Unexpected SwapTotal: %d", meminfo.SwapTotal)
32
+	}
33
+	if meminfo.SwapFree != 4*units.KiB {
34
+		t.Fatalf("Unexpected SwapFree: %d", meminfo.SwapFree)
35
+	}
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !linux
1
+
2
+package system
3
+
4
+func ReadMemInfo() (*MemInfo, error) {
5
+	return nil, ErrNotSupportedPlatform
6
+}