7 # Returns true if `value` is an integer represented as a string.
17 def get_mappings(pid
):
19 with
open("/proc/{0}/smaps".format(pid
)) as f
:
24 # 00400000-00447000 r-xp 00000000 fd:00 11667056 /usr/bin/tint2
26 mappings
.append(mapping
)
28 mapping
["path"] = line
.strip().split(" ", 1)[-1].strip()
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
38 print "Cannot handle line:", line
39 raise RuntimeException("Parsing error")
41 mappings
.append(mapping
)
46 if "Rss" in m
and is_int(m
["Rss"]):
51 def private_extractor(m
):
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"])
60 def shared_extractor(m
):
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"])
69 def extract_mappings(maps
, select_func
, group_func
, val_func
=rss_extractor
):
72 if select_func(m
) and val_func(m
):
74 if group
not in parts
:
76 parts
[group
] += val_func(m
)
78 parts
.sort(key
=lambda p
: -p
[1])
79 total
= sum([p
[1] for p
in parts
])
83 def extract_total(maps
, args
):
84 return extract_mappings(maps
,
90 def extract_total_shared(maps
, args
):
91 return extract_mappings(maps
,
97 def extract_total_private(maps
, args
):
98 return extract_mappings(maps
,
104 def extract_code(maps
, args
):
105 return extract_mappings(maps
,
106 lambda m
: "ex" in m
["VmFlags"],
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]",
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]",
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"],
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"],
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
:
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
)
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
)
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()
176 if __name__
== "__main__":