Commit 618fe8e5 authored by Benoît Lizé's avatar Benoît Lizé Committed by Commit Bot

tools/android: Show the footprint of allocators in parse_smaps.py.

Adds an option to show the total footprint of an allocator (one of malloc(),
partition_alloc and V8) in parse_smaps.py.

Example output:
$ tools/android/native_lib_memory/parse_smaps.py --pid 12803 \
  --show-allocator-footprint partition_alloc
[...]
Footprint from partition_alloc: 13648 kB

Bug: 998048
Change-Id: I9b9b062565e56188979c43380a411bca0f2db282
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1781645
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarEgor Pasko <pasko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693061}
parent 33c6d20e
...@@ -21,6 +21,7 @@ from devil.android import device_utils ...@@ -21,6 +21,7 @@ from devil.android import device_utils
class Mapping(object): class Mapping(object):
"""A single entry (mapping) in /proc/[pid]/smaps.""" """A single entry (mapping) in /proc/[pid]/smaps."""
def __init__(self, start, end, permissions, offset, pathname): def __init__(self, start, end, permissions, offset, pathname):
"""Initializes an instance. """Initializes an instance.
...@@ -163,6 +164,17 @@ def _PrintSwapStats(mappings): ...@@ -163,6 +164,17 @@ def _PrintSwapStats(mappings):
_PrintMappingsMetric(mappings, 'Swap') _PrintMappingsMetric(mappings, 'Swap')
def _FootprintForAnonymousMapping(mapping):
assert mapping.pathname.startswith('[anon:')
if (mapping.pathname == '[anon:libc_malloc]'
and mapping.fields['Shared_Dirty'] != 0):
# libc_malloc mappings can come from the zygote. In this case, the shared
# dirty memory is likely dirty in the zygote, don't count it.
return mapping.fields['Rss']
else:
return mapping.fields['Private_Dirty']
def _PrintEstimatedFootprintStats(mappings, page_table_kb): def _PrintEstimatedFootprintStats(mappings, page_table_kb):
print 'Private Dirty:' print 'Private Dirty:'
_PrintMappingsMetric(mappings, 'Private_Dirty') _PrintMappingsMetric(mappings, 'Private_Dirty')
...@@ -178,7 +190,12 @@ def _PrintEstimatedFootprintStats(mappings, page_table_kb): ...@@ -178,7 +190,12 @@ def _PrintEstimatedFootprintStats(mappings, page_table_kb):
def _ComputeEstimatedFootprint(mappings, page_table_kb): def _ComputeEstimatedFootprint(mappings, page_table_kb):
"""Returns the estimated footprint in kiB.""" """Returns the estimated footprint in kiB.
Args:
mappings: ([Mapping]) all process mappings.
page_table_kb: (int) Sizeof the page tables in kiB.
"""
footprint = page_table_kb footprint = page_table_kb
for mapping in mappings: for mapping in mappings:
# Chrome shared memory. # Chrome shared memory.
...@@ -187,12 +204,8 @@ def _ComputeEstimatedFootprint(mappings, page_table_kb): ...@@ -187,12 +204,8 @@ def _ComputeEstimatedFootprint(mappings, page_table_kb):
# account for its entirety. # account for its entirety.
if mapping.pathname.startswith('/dev/ashmem/shared_memory'): if mapping.pathname.startswith('/dev/ashmem/shared_memory'):
footprint += mapping.fields['Rss'] footprint += mapping.fields['Rss']
elif mapping.pathname.startswith('[anon:libc_malloc]'): elif mapping.pathname.startswith('[anon'):
if mapping.fields['Shared_Dirty'] == 0: footprint += _FootprintForAnonymousMapping(mapping)
footprint += mapping.fields['Rss']
else:
footprint += mapping.fields['Private_Dirty'] # Shared dirty is likely
# from the zygote.
# Mappings without a name are most likely Chrome's native memory allocators: # Mappings without a name are most likely Chrome's native memory allocators:
# v8, PartitionAlloc, Oilpan. # v8, PartitionAlloc, Oilpan.
# All of it should be charged to our process. # All of it should be charged to our process.
...@@ -208,6 +221,21 @@ def _ComputeEstimatedFootprint(mappings, page_table_kb): ...@@ -208,6 +221,21 @@ def _ComputeEstimatedFootprint(mappings, page_table_kb):
return footprint return footprint
def _ShowAllocatorFootprint(mappings, allocator):
"""Shows the total footprint from a specific allocator.
Args:
mappings: ([Mapping]) all process mappings.
allocator: (str) Allocator name.
"""
total_footprint = 0
pathname = '[anon:%s]' % allocator
for mapping in mappings:
if mapping.pathname == pathname:
total_footprint += _FootprintForAnonymousMapping(mapping)
print '\tFootprint from %s: %d kB' % (allocator, total_footprint)
def _CreateArgumentParser(): def _CreateArgumentParser():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--pid', help='PID.', required=True, type=int) parser.add_argument('--pid', help='PID.', required=True, type=int)
...@@ -216,6 +244,10 @@ def _CreateArgumentParser(): ...@@ -216,6 +244,10 @@ def _CreateArgumentParser():
action='store_true') action='store_true')
parser.add_argument('--store-smaps', help='Store the smaps file locally', parser.add_argument('--store-smaps', help='Store the smaps file locally',
action='store_true') action='store_true')
parser.add_argument('--show-allocator-footprint',
help='Show the footprint from a given allocator',
choices=['v8', 'libc_malloc', 'partition_alloc'],
nargs='+')
return parser return parser
...@@ -239,6 +271,11 @@ def main(): ...@@ -239,6 +271,11 @@ def main():
else: else:
_PrintSwapStats(mappings) _PrintSwapStats(mappings)
if args.show_allocator_footprint:
print '\n\nMemory Allocators footprint:'
for allocator in args.show_allocator_footprint:
_ShowAllocatorFootprint(mappings, allocator)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment