update TODO
[tint2-nick87720z.git] / test / meminfo.py
blobeb16073865dba738ab7db06d343e846be48e4b76
1 #!/usr/bin/env python2
3 import argparse
4 import sys
7 # Returns true if `value` is an integer represented as a string.
8 def is_int(value):
9 # type: (str) -> bool
10 try:
11 value = int(value)
12 except ValueError:
13 return False
14 return True
17 def get_mappings(pid):
18 mappings = []
19 with open("/proc/{0}/smaps".format(pid)) as f:
20 mapping = None
21 for line in f:
22 if ": " not in line:
23 # Header
24 # 00400000-00447000 r-xp 00000000 fd:00 11667056 /usr/bin/tint2
25 if mapping:
26 mappings.append(mapping)
27 mapping = {}
28 mapping["path"] = line.strip().split(" ", 1)[-1].strip()
29 elif mapping:
30 # Entry
31 # Size: 4 kB
32 # VmFlags: rd mr mw me dw ac sd
33 key, val = [s.strip() for s in line.split(":", 1)]
34 if val.endswith(" kB") and is_int(val.split(" kB", 1)[0]):
35 val = int(val.split(" kB", 1)[0]) * 1024
36 mapping[key] = val
37 else:
38 print "Cannot handle line:", line
39 raise RuntimeException("Parsing error")
40 if mapping:
41 mappings.append(mapping)
42 return mappings
45 def rss_extractor(m):
46 if "Rss" in m and is_int(m["Rss"]):
47 return int(m["Rss"])
48 return 0
51 def private_extractor(m):
52 result = 0
53 if "Private_Clean" in m and is_int(m["Private_Clean"]):
54 result += int(m["Private_Clean"])
55 if "Private_Dirty" in m and is_int(m["Private_Dirty"]):
56 result += int(m["Private_Dirty"])
57 return result
60 def shared_extractor(m):
61 result = 0
62 if "Shared_Clean" in m and is_int(m["Shared_Clean"]):
63 result += int(m["Shared_Clean"])
64 if "Shared_Dirty" in m and is_int(m["Shared_Dirty"]):
65 result += int(m["Shared_Dirty"])
66 return result
69 def extract_mappings(maps, select_func, group_func, val_func=rss_extractor):
70 parts = {}
71 for m in maps:
72 if select_func(m) and val_func(m):
73 group = group_func(m)
74 if group not in parts:
75 parts[group] = 0
76 parts[group] += val_func(m)
77 parts = parts.items()
78 parts.sort(key=lambda p: -p[1])
79 total = sum([p[1] for p in parts])
80 return total, parts
83 def extract_total(maps, args):
84 return extract_mappings(maps,
85 lambda m: True,
86 lambda m: "Total",
87 rss_extractor)
90 def extract_total_shared(maps, args):
91 return extract_mappings(maps,
92 lambda m: True,
93 lambda m: "Shared",
94 shared_extractor)
97 def extract_total_private(maps, args):
98 return extract_mappings(maps,
99 lambda m: True,
100 lambda m: "Private",
101 private_extractor)
104 def extract_code(maps, args):
105 return extract_mappings(maps,
106 lambda m: "ex" in m["VmFlags"],
107 lambda m: m["path"],
108 private_extractor if args.private else rss_extractor)
111 def extract_heap(maps, args):
112 return extract_mappings(maps,
113 lambda m: m["path"] == "[heap]",
114 lambda m: m["path"],
115 private_extractor if args.private else rss_extractor)
118 def extract_stack(maps, args):
119 return extract_mappings(maps,
120 lambda m: m["path"] == "[stack]",
121 lambda m: m["path"],
122 private_extractor if args.private else rss_extractor)
125 def extract_mapped_files(maps, args):
126 return extract_mappings(maps,
127 lambda m: "/" in m["path"] and "ex" not in m["VmFlags"],
128 lambda m: m["path"],
129 private_extractor if args.private else rss_extractor)
132 def extract_other(maps, args):
133 return extract_mappings(maps,
134 lambda m: "/" not in m["path"] and m["path"] != "[stack]" and m["path"] != "[heap]" and "ex" not in m["VmFlags"],
135 lambda m: m["path"],
136 private_extractor if args.private else rss_extractor)
139 def print_histogram(name, maps, extractor_func, args):
140 total, histogram = extractor_func(maps, args)
141 print "{}: {:,} B".format(name, total)
142 if not args.detailed:
143 return
144 max_size_str_len = 0
145 for item, size in histogram:
146 size_str = "{:,}".format(size)
147 padding = max(0, max_size_str_len - len(size_str))
148 max_size_str_len = max(max_size_str_len, len(size_str))
149 print " * {}{} B: {}".format(" " * padding, size_str, item)
152 def show_mem_info(args):
153 maps = get_mappings(args.pid)
154 print_histogram("Total", maps, extract_total, args)
155 print_histogram("Shared", maps, extract_total_shared, args)
156 print_histogram("Private", maps, extract_total_private, args)
157 print "Breakdown:"
158 print_histogram("* Heap", maps, extract_heap, args)
159 print_histogram("* Stack", maps, extract_stack, args)
160 print_histogram("* Memory mapped files", maps, extract_mapped_files, args)
161 print_histogram("* Executable code", maps, extract_code, args)
162 print_histogram("* Other", maps, extract_other, args)
165 def main():
166 parser = argparse.ArgumentParser(description="Prints the memory allocation information of a process.")
167 parser.add_argument("--detailed", action="store_true", help="Show a breakdown for each category.")
168 parser.add_argument("--private", action="store_true", help="Do not take int account memory shared with other processes.")
169 parser.add_argument("pid", help="PID of the process whose memory is to be analyzed.", type=int)
170 parser.set_defaults(detailed=False)
171 parser.set_defaults(private=False)
172 args = parser.parse_args()
173 show_mem_info(args)
176 if __name__ == "__main__":
177 main()