Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support /sys/devices/system/node/nodeN/meminfo #489

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions sysfs/meminfo_numa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright 2023 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux
// +build linux

package sysfs

import (
"bufio"
"bytes"
"fmt"
"io"
"path/filepath"
"strconv"
"strings"

"github.com/prometheus/procfs/internal/util"
)

// Meminfo represents memory statistics for NUMA node.
type Meminfo struct {
MemTotal uint64
MemFree uint64
MemUsed uint64
SwapCached uint64
Active uint64
Inactive uint64
ActiveAnon uint64
InactiveAnon uint64
ActiveFile uint64
InactiveFile uint64
Unevictable uint64
Mlocked uint64
Dirty uint64
Writeback uint64
FilePages uint64
Mapped uint64
AnonPages uint64
Shmem uint64
KernelStack uint64
PageTables uint64
NFS_Unstable uint64
Bounce uint64
WritebackTmp uint64
KReclaimable uint64
Slab uint64
SReclaimable uint64
SUnreclaim uint64
AnonHugePages uint64
ShmemHugePages uint64
ShmemPmdMapped uint64
FileHugePages uint64
FilePmdMapped uint64
HugePages_Total uint64
HugePages_Free uint64
HugePages_Surp uint64
}

func (fs FS) MeminfoNUMA() (map[int]Meminfo, error) {
m := make(map[int]Meminfo)
nodes, err := filepath.Glob(fs.sys.Path(nodePattern))
if err != nil {
return nil, err
}

for _, node := range nodes {
nodeNumbers := nodeNumberRegexp.FindStringSubmatch(node)
if len(nodeNumbers) != 2 {
continue
}
nodeNumber, err := strconv.Atoi(nodeNumbers[1])
if err != nil {
return nil, err
}
b, err := util.ReadFileNoStat(filepath.Join(node, "meminfo"))
if err != nil {
return nil, err
}
meminfo, err := parseMeminfo(bytes.NewReader(b))
if err != nil {
return nil, err
}
m[nodeNumber] = meminfo
}
return m, nil
}

func parseMeminfo(r io.Reader) (Meminfo, error) {
var m Meminfo
s := bufio.NewScanner(r)
for s.Scan() {
// Each line has at least a name and value; we ignore the unit.
// A line example: "Node 0 MemTotal: 395936028 kB"
fields := strings.Fields(s.Text())
if len(fields) < 4 {
return Meminfo{}, fmt.Errorf("malformed meminfo line: %q", s.Text())
}

v, err := strconv.ParseUint(fields[3], 0, 64)
if err != nil {
return Meminfo{}, err
}

switch fields[2] {
case "MemTotal:":
m.MemTotal = v
case "MemFree:":
m.MemFree = v
case "MemUsed:":
m.MemUsed = v
case "SwapCached:":
m.SwapCached = v
case "Active:":
m.Active = v
case "Inactive:":
m.Inactive = v
case "Active(anon):":
m.ActiveAnon = v
case "Inactive(anon):":
m.InactiveAnon = v
case "Active(file):":
m.ActiveFile = v
case "Inactive(file):":
m.InactiveFile = v
case "Unevictable:":
m.Unevictable = v
case "Mlocked:":
m.Mlocked = v
case "Dirty:":
m.Dirty = v
case "Writeback:":
m.Writeback = v
case "FilePages:":
m.FilePages = v
case "Mapped:":
m.Mapped = v
case "AnonPages:":
m.AnonPages = v
case "Shmem:":
m.Shmem = v
case "KernelStack:":
m.KernelStack = v
case "PageTables:":
m.PageTables = v
case "NFS_Unstable:":
m.NFS_Unstable = v
case "Bounce:":
m.Bounce = v
case "WritebackTmp:":
m.WritebackTmp = v
case "KReclaimable:":
m.KReclaimable = v
case "Slab:":
m.Slab = v
case "SReclaimable:":
m.SReclaimable = v
case "SUnreclaim:":
m.SUnreclaim = v
case "AnonHugePages:":
m.AnonHugePages = v
case "ShmemHugePages:":
m.ShmemHugePages = v
case "ShmemPmdMapped:":
m.ShmemPmdMapped = v
case "FileHugePages:":
m.FileHugePages = v
case "FilePmdMapped:":
m.FilePmdMapped = v
case "HugePages_Total:":
m.HugePages_Total = v
case "HugePages_Free:":
m.HugePages_Free = v
case "HugePages_Surp:":
m.HugePages_Surp = v
}
}

return m, nil
}
41 changes: 41 additions & 0 deletions sysfs/meminfo_numa_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2023 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux
// +build linux

package sysfs

import (
"testing"
)

func TestMeminfoNUMA(t *testing.T) {
fs, err := NewFS(sysTestFixtures)
if err != nil {
t.Fatal(err)
}

meminfo, err := fs.MeminfoNUMA()
if err != nil {
t.Fatal(err)
}

if want, got := uint64(133), meminfo[1].HugePages_Total; want != got {
t.Errorf("want meminfo stat HugePages_Total value %d, got %d", want, got)
}

if want, got := uint64(134), meminfo[1].HugePages_Free; want != got {
t.Errorf("want meminfo stat HugePages_Free value %d, got %d", want, got)
}
}
24 changes: 24 additions & 0 deletions sysfs/numa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2023 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux
// +build linux

package sysfs

import "regexp"

var (
nodePattern = "devices/system/node/node[0-9]*"
nodeNumberRegexp = regexp.MustCompile(`.*devices/system/node/node([0-9]*)`)
)
6 changes: 0 additions & 6 deletions sysfs/vmstat_numa.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,12 @@ import (
"bytes"
"fmt"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/prometheus/procfs/internal/util"
)

var (
nodePattern = "devices/system/node/node[0-9]*"
nodeNumberRegexp = regexp.MustCompile(`.*devices/system/node/node([0-9]*)`)
)

type VMStat struct {
NrFreePages uint64
NrZoneInactiveAnon uint64
Expand Down
78 changes: 78 additions & 0 deletions testdata/fixtures.ttar
Original file line number Diff line number Diff line change
Expand Up @@ -12727,6 +12727,45 @@ Mode: 775
Directory: fixtures/sys/devices/system/node/node1
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/node/node1/meminfo
Lines: 35
Node 1 MemTotal: 101 kB
Node 1 MemFree: 102 kB
Node 1 MemUsed: 103 kB
Node 1 SwapCached: 104 kB
Node 1 Active: 105 kB
Node 1 Inactive: 106 kB
Node 1 Active(anon): 107 kB
Node 1 Inactive(anon): 108 kB
Node 1 Active(file): 109 kB
Node 1 Inactive(file): 110 kB
Node 1 Unevictable: 111 kB
Node 1 Mlocked: 112 kB
Node 1 Dirty: 113 kB
Node 1 Writeback: 114 kB
Node 1 FilePages: 115 kB
Node 1 Mapped: 116 kB
Node 1 AnonPages: 117 kB
Node 1 Shmem: 118 kB
Node 1 KernelStack: 119 kB
Node 1 PageTables: 120 kB
Node 1 NFS_Unstable: 121 kB
Node 1 Bounce: 122 kB
Node 1 WritebackTmp: 123 kB
Node 1 KReclaimable: 124 kB
Node 1 Slab: 125 kB
Node 1 SReclaimable: 126 kB
Node 1 SUnreclaim: 127 kB
Node 1 AnonHugePages: 128 kB
Node 1 ShmemHugePages: 129 kB
Node 1 ShmemPmdMapped: 130 kB
Node 1 FileHugePages: 131 kB
Node 1 FilePmdMapped: 132 kB
Node 1 HugePages_Total: 133
Node 1 HugePages_Free: 134
Node 1 HugePages_Surp: 135EOF
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/node/node1/vmstat
Lines: 6
nr_free_pages 1
Expand All @@ -12740,6 +12779,45 @@ Mode: 644
Directory: fixtures/sys/devices/system/node/node2
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/node/node2/meminfo
Lines: 35
Node 2 MemTotal: 201 kB
Node 2 MemFree: 202 kB
Node 2 MemUsed: 203 kB
Node 2 SwapCached: 204 kB
Node 2 Active: 205 kB
Node 2 Inactive: 206 kB
Node 2 Active(anon): 207 kB
Node 2 Inactive(anon): 208 kB
Node 2 Active(file): 209 kB
Node 2 Inactive(file): 210 kB
Node 2 Unevictable: 211 kB
Node 2 Mlocked: 212 kB
Node 2 Dirty: 213 kB
Node 2 Writeback: 214 kB
Node 2 FilePages: 215 kB
Node 2 Mapped: 216 kB
Node 2 AnonPages: 217 kB
Node 2 Shmem: 218 kB
Node 2 KernelStack: 219 kB
Node 2 PageTables: 220 kB
Node 2 NFS_Unstable: 221 kB
Node 2 Bounce: 222 kB
Node 2 WritebackTmp: 223 kB
Node 2 KReclaimable: 224 kB
Node 2 Slab: 225 kB
Node 2 SReclaimable: 226 kB
Node 2 SUnreclaim: 227 kB
Node 2 AnonHugePages: 228 kB
Node 2 ShmemHugePages: 229 kB
Node 2 ShmemPmdMapped: 230 kB
Node 2 FileHugePages: 231 kB
Node 2 FilePmdMapped: 232 kB
Node 2 HugePages_Total: 233
Node 2 HugePages_Free: 234
Node 2 HugePages_Surp: 235EOF
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/node/node2/vmstat
Lines: 6
nr_free_pages 7
Expand Down