Skip to content

Instantly share code, notes, and snippets.

@vtta
Last active May 17, 2024 08:08
Show Gist options
  • Save vtta/7684bbf150684b77cd645844644f5285 to your computer and use it in GitHub Desktop.
Save vtta/7684bbf150684b77cd645844644f5285 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# Output looks like this:
# Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 1,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2,Node 2
# MemTotal,MemFree,MemUsed,SwapCached,Active,Inactive,Active(anon),Inactive(anon),Active(file),Inactive(file),Unevictable,Mlocked,Dirty,Writeback,FilePages,Mapped,AnonPages,Shmem,KernelStack,PageTables,SecPageTables,NFS_Unstable,Bounce,WritebackTmp,KReclaimable,Slab,SReclaimable,SUnreclaim,AnonHugePages,ShmemHugePages,ShmemPmdMapped,FileHugePages,FilePmdMapped,Unaccepted,HugePages_Total,HugePages_Free,HugePages_Surp,MemTotal,MemFree,MemUsed,SwapCached,Active,Inactive,Active(anon),Inactive(anon),Active(file),Inactive(file),Unevictable,Mlocked,Dirty,Writeback,FilePages,Mapped,AnonPages,Shmem,KernelStack,PageTables,SecPageTables,NFS_Unstable,Bounce,WritebackTmp,KReclaimable,Slab,SReclaimable,SUnreclaim,AnonHugePages,ShmemHugePages,ShmemPmdMapped,FileHugePages,FilePmdMapped,Unaccepted,HugePages_Total,HugePages_Free,HugePages_Surp
# 129366064,63343124,66022940,0,9543140,48625776,684,26279856,9542456,22345920,4,0,56,0,31936192,232932,25303716,47812,28528,61316,0,0,0,0,1733292,2227608,1733292,494316,15962112,0,0,0,0,0,0,0,0,266338304,234928788,31409516,0,11534512,17090340,7204,3807400,11527308,13282940,16,16,104,0,24816780,180816,3786656,6532,10160,52652,0,0,0,0,2382112,2620996,2382112,238884,1972224,0,0,0,0,0,0,0,0
# 129366064,63343124,66022940,0,9543140,48626264,684,26280344,9542456,22345920,4,0,56,0,31936192,233048,25303740,47812,28512,61368,0,0,0,0,1733292,2227616,1733292,494324,15962112,0,0,0,0,0,0,0,0,266338304,234928636,31409668,0,11534516,17090336,7204,3807400,11527312,13282936,16,16,104,0,24816780,180640,3786656,6532,10160,52652,0,0,0,0,2382160,2621036,2382160,238876,1972224,0,0,0,0,0,0,0,0
# 129366064,63343376,66022688,0,9543148,48626444,692,26280528,9542456,22345916,4,0,60,0,31936192,233324,25303916,47812,28496,61336,0,0,0,0,1733292,2227616,1733292,494324,15962112,0,0,0,0,0,0,0,0,266338304,234928028,31410276,0,11534520,17090332,7204,3807400,11527316,13282932,16,16,112,0,24816780,180640,3786656,6532,10144,52652,0,0,0,0,2382160,2621484,2382160,239324,1972224,0,0,0,0,0,0,0,0
# ...
# Can be read by pandas via:
# df = pd.read_csv("numa-meminfo.log", header=[0,1])
# Source file and its format:
# $ cat /sys/devices/system/node/node1/meminfo
# Node 1 MemTotal: 129366064 kB
# Node 1 MemFree: 63741984 kB
# Node 1 MemUsed: 65624080 kB
# Node 1 SwapCached: 0 kB
# Node 1 Active: 9498176 kB
# Node 1 Inactive: 48305840 kB
# Node 1 Active(anon): 660 kB
# Node 1 Inactive(anon): 26065500 kB
# Node 1 Active(file): 9497516 kB
# Node 1 Inactive(file): 22240340 kB
# Node 1 Unevictable: 4 kB
# Node 1 Mlocked: 0 kB
# Node 1 Dirty: 64 kB
# Node 1 Writeback: 0 kB
# Node 1 FilePages: 31785672 kB
# Node 1 Mapped: 228456 kB
# Node 1 AnonPages: 25090548 kB
# Node 1 Shmem: 47812 kB
# Node 1 KernelStack: 28432 kB
# Node 1 PageTables: 58128 kB
# Node 1 SecPageTables: 0 kB
# Node 1 NFS_Unstable: 0 kB
# Node 1 Bounce: 0 kB
# Node 1 WritebackTmp: 0 kB
# Node 1 KReclaimable: 1706736 kB
# Node 1 Slab: 2201460 kB
# Node 1 SReclaimable: 1706736 kB
# Node 1 SUnreclaim: 494724 kB
# Node 1 AnonHugePages: 15962112 kB
# Node 1 ShmemHugePages: 0 kB
# Node 1 ShmemPmdMapped: 0 kB
# Node 1 FileHugePages: 0 kB
# Node 1 FilePmdMapped: 0 kB
# Node 1 Unaccepted: 0 kB
# Node 1 HugePages_Total: 0
# Node 1 HugePages_Free: 0
# Node 1 HugePages_Surp: 0
import re
import time
from pathlib import Path
from typing import List, Optional
import fire
# from rich import print
# meminfo is represented as a dict of dicts
# {
# 0: {
# 'MemTotal': '0',
# 'MemFree': '0',
# ...
# },
# 1: {
# 'MemTotal': '129366064',
# ...
# },
# ...
# }
class MemInfo:
nodes = dict()
record_re = re.compile(r"^Node\s+(?P<nid>\d+)\s+(?P<key>[\w+\(\)]+):\s+(?P<value>\d+)(\s+kB)?$", re.M)
@property
def node_glob(self):
return Path("/sys/devices/system/node").glob("node*/meminfo")
def __init__(self, nodes: Optional[List[int]] = None):
if isinstance(nodes, int):
nodes = [nodes]
for f in sorted(self.node_glob):
nid = int(f.parent.stem[4:])
if nodes and nid not in nodes:
continue
self.nodes[nid] = dict([
(match.group("key"), match.group("value")) for match in self.record_re.finditer(f.read_text())
])
def csv_header(self):
line0 = ",".join([",".join([f"Node {nid}"] * len(node)) for nid, node in self.nodes.items()])
line1 = ",".join([",".join(node.keys()) for node in self.nodes.values()])
return line0 + "\n" + line1
def csv_row(self):
return ",".join([",".join(node.values()) for node in self.nodes.values()])
def main(delay: int = 1, nodes: List[int] = []):
show_header = True
try:
while True:
meminfo = MemInfo(nodes)
if show_header:
show_header = False
print(meminfo.csv_header())
# flush to avoid broken pipe error
print(meminfo.csv_row(), flush=True)
time.sleep(delay)
except KeyboardInterrupt:
pass
if __name__ == "__main__":
fire.Fire(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment