Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Unified Diff: tools/deep_memory_profiler/dmprof.py

Issue 15511005: Breakdown "unhooked" memory regions by VMA pathnames and permissions. (Closed) Base URL: git@github.com:dmikurube/chromium.git@work
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/deep_memory_profiler/dmprof.py
diff --git a/tools/deep_memory_profiler/dmprof.py b/tools/deep_memory_profiler/dmprof.py
index 8327f96e5a56d209ef5498ac7d668a953af2b773..e3aa57464a7f2d009794e259d3d8e8cd09741f17 100644
--- a/tools/deep_memory_profiler/dmprof.py
+++ b/tools/deep_memory_profiler/dmprof.py
@@ -377,12 +377,14 @@ class Rule(object):
def __init__(self,
name,
- mmap,
+ allocator_type,
stackfunction_pattern=None,
stacksourcefile_pattern=None,
- typeinfo_pattern=None):
+ typeinfo_pattern=None,
+ mappedfile_pattern=None,
+ mappedexecutable_pattern=None):
self._name = name
- self._mmap = mmap
+ self._allocator_type = allocator_type
self._stackfunction_pattern = None
if stackfunction_pattern:
@@ -398,13 +400,22 @@ class Rule(object):
if typeinfo_pattern:
self._typeinfo_pattern = re.compile(typeinfo_pattern + r'\Z')
+ self._mappedfile_pattern = None
+ if mappedfile_pattern:
+ self._mappedfile_pattern = re.compile(mappedfile_pattern + r'\Z')
+
+ self._mappedexecutable_pattern = None
+ if mappedexecutable_pattern:
+ self._mappedexecutable_pattern = re.compile(
+ mappedexecutable_pattern + r'\Z')
+
@property
def name(self):
return self._name
@property
- def mmap(self):
- return self._mmap
+ def allocator_type(self):
+ return self._allocator_type
@property
def stackfunction_pattern(self):
@@ -418,6 +429,14 @@ class Rule(object):
def typeinfo_pattern(self):
return self._typeinfo_pattern
+ @property
+ def mappedfile_pattern(self):
+ return self._mappedfile_pattern
+
+ @property
+ def mappedexecutable_pattern(self):
+ return self._mappedexecutable_pattern
+
class Policy(object):
"""Represents a policy, a content of a policy file."""
@@ -460,7 +479,7 @@ class Policy(object):
typeinfo = bucket.typeinfo_name
for rule in self._rules:
- if (bucket.mmap == rule.mmap and
+ if (bucket.allocator_type == rule.allocator_type and
(not rule.stackfunction_pattern or
rule.stackfunction_pattern.match(stackfunction)) and
(not rule.stacksourcefile_pattern or
@@ -471,6 +490,19 @@ class Policy(object):
assert False
+ def find_unhooked(self, region):
+ for rule in self._rules:
+ if (region[0] == 'unhooked' and
+ rule.allocator_type == 'unhooked' and
+ (not rule.mappedfile_pattern or
+ rule.mappedfile_pattern.match(region[1]['vma']['name'])) and
+ (not rule.mappedexecutable_pattern or
+ rule.mappedexecutable_pattern.match(
+ region[1]['vma']['executable']))):
+ return rule.name
+
+ assert False
+
@staticmethod
def load(filename, filetype):
"""Loads a policy file of |filename| in a |format|.
@@ -525,10 +557,12 @@ class Policy(object):
stacksourcefile = rule.get('stacksourcefile')
rules.append(Rule(
rule['name'],
- rule['allocator'] == 'mmap',
+ rule['allocator'], # allocator_type
stackfunction,
stacksourcefile,
- rule['typeinfo'] if 'typeinfo' in rule else None))
+ rule['typeinfo'] if 'typeinfo' in rule else None,
+ rule.get('mappedfile'),
+ rule.get('mappedexecutable')))
return Policy(rules, policy['version'], policy['components'])
@@ -598,9 +632,9 @@ class PolicySet(object):
class Bucket(object):
"""Represents a bucket, which is a unit of memory block classification."""
- def __init__(self, stacktrace, mmap, typeinfo, typeinfo_name):
+ def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name):
self._stacktrace = stacktrace
- self._mmap = mmap
+ self._allocator_type = allocator_type
self._typeinfo = typeinfo
self._typeinfo_name = typeinfo_name
@@ -614,7 +648,7 @@ class Bucket(object):
def __str__(self):
result = []
- result.append('mmap' if self._mmap else 'malloc')
+ result.append(self._allocator_type)
if self._symbolized_typeinfo == 'no typeinfo':
result.append('tno_typeinfo')
else:
@@ -659,8 +693,8 @@ class Bucket(object):
return self._stacktrace
@property
- def mmap(self):
- return self._mmap
+ def allocator_type(self):
+ return self._allocator_type
@property
def typeinfo(self):
@@ -740,7 +774,7 @@ class BucketSet(object):
for frame in stacktrace:
self._code_addresses.add(frame)
self._buckets[int(words[0])] = Bucket(
- stacktrace, words[1] == 'mmap', typeinfo, typeinfo_name)
+ stacktrace, words[1], typeinfo, typeinfo_name)
def __iter__(self):
for bucket_id, bucket_content in self._buckets.iteritems():
@@ -778,6 +812,12 @@ class Dump(object):
r'^ ([ \(])([a-f0-9]+)([ \)])-([ \(])([a-f0-9]+)([ \)])\s+'
r'(hooked|unhooked)\s+(.+)$', re.IGNORECASE)
+ _HOOKED_PATTERN = re.compile(r'(.+) ([0-9]+) / ([0-9]+) @ ([0-9]+)')
+ _UNHOOKED_PATTERN = re.compile(r'(.+) ([0-9]+) / ([0-9]+)')
+
+ _OLD_HOOKED_PATTERN = re.compile(r'(.+) @ ([0-9]+)')
+ _OLD_UNHOOKED_PATTERN = re.compile(r'(.+) ([0-9]+)')
+
_TIME_PATTERN_FORMAT = re.compile(
r'^Time: ([0-9]+/[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+)(\.[0-9]+)?')
_TIME_PATTERN_SECONDS = re.compile(r'^Time: ([0-9]+)$')
@@ -958,12 +998,15 @@ class Dump(object):
ln += 1
self._map = {}
+ current_vma = dict()
while True:
entry = proc_maps.ProcMaps.parse_line(self._lines[ln])
if entry:
+ current_vma = dict()
for _, _, attr in self._procmaps.iter_range(entry.begin, entry.end):
for key, value in entry.as_dict().iteritems():
attr[key] = value
+ current_vma[key] = value
ln += 1
continue
matched = self._HOOK_PATTERN.match(self._lines[ln])
@@ -973,9 +1016,51 @@ class Dump(object):
# 5: end address
# 7: hooked or unhooked
# 8: additional information
+ if matched.group(7) == 'hooked':
+ matched_hooked = self._HOOKED_PATTERN.match(matched.group(8))
+ if matched_hooked:
+ region_info = {
+ 'vma': current_vma,
+ 'type': matched_hooked.group(1),
+ 'committed': int(matched_hooked.group(2)),
+ 'virtual': int(matched_hooked.group(3)),
+ 'bucket_id': int(matched_hooked.group(4)),
+ }
+ else:
+ matched_old_hooked = self._OLD_HOOKED_PATTERN.match(matched.group(8))
+ if matched_old_hooked:
+ region_info = {
+ 'vma': current_vma,
+ 'type': matched_hooked.group(1),
+ 'bucket_id': int(matched_hooked.group(2)),
+ }
+ else:
+ region_info = { 'vma': current_vma }
+ elif matched.group(7) == 'unhooked':
+ matched_unhooked = self._UNHOOKED_PATTERN.match(matched.group(8))
+ if matched_unhooked:
+ region_info = {
+ 'vma': current_vma,
+ 'type': matched_unhooked.group(1),
+ 'committed': int(matched_unhooked.group(2)),
+ 'virtual': int(matched_unhooked.group(3)),
+ }
+ else:
+ matched_old_unhooked = self._OLD_UNHOOKED_PATTERN.match(
+ matched.group(8))
+ if matched_old_unhooked:
+ region_info = {
+ 'vma': current_vma,
+ 'type': matched_unhooked.group(1),
+ 'committed': int(matched_unhooked.group(2)),
+ }
+ else:
+ region_info = { 'vma': current_vma }
+ else:
+ assert matched.group(7) in ['hooked', 'unhooked']
+
self._map[(int(matched.group(2), 16),
- int(matched.group(5), 16))] = (matched.group(7),
- matched.group(8))
+ int(matched.group(5), 16))] = (matched.group(7), region_info)
ln += 1
def _extract_stacktrace_lines(self, line_number):
@@ -1288,6 +1373,7 @@ class PolicyCommands(Command):
sizes = dict((c, 0) for c in policy.components)
PolicyCommands._accumulate(dump, policy, bucket_set, sizes)
+ PolicyCommands._accumulate_map(dump, policy, sizes)
sizes['mmap-no-log'] = (
dump.global_stat('profiled-mmap_committed') -
@@ -1302,6 +1388,10 @@ class PolicyCommands(Command):
sizes['tc-unused'] = (
sizes['mmap-tcmalloc'] -
dump.global_stat('profiled-malloc_committed'))
+ if sizes['tc-unused'] < 0:
+ LOGGER.warn(' Assuming tc-unused=0 as it is negative: %d (bytes)' %
+ sizes['tc-unused'])
+ sizes['tc-unused'] = 0
sizes['tc-total'] = sizes['mmap-tcmalloc']
for key, value in {
@@ -1314,11 +1404,6 @@ class PolicyCommands(Command):
'stack': 'stack_committed',
'other': 'other_committed',
'unhooked-absent': 'nonprofiled-absent_committed',
- 'unhooked-anonymous': 'nonprofiled-anonymous_committed',
- 'unhooked-file-exec': 'nonprofiled-file-exec_committed',
- 'unhooked-file-nonexec': 'nonprofiled-file-nonexec_committed',
- 'unhooked-stack': 'nonprofiled-stack_committed',
- 'unhooked-other': 'nonprofiled-other_committed',
'total-vm': 'total_virtual',
'filemapped-vm': 'file_virtual',
'anonymous-vm': 'anonymous_virtual',
@@ -1366,6 +1451,13 @@ class PolicyCommands(Command):
else:
sizes['other-total-log'] += int(words[COMMITTED])
+ @staticmethod
+ def _accumulate_map(dump, policy, sizes):
+ for _, value in dump.iter_map:
+ if value[0] == 'unhooked':
+ component_match = policy.find_unhooked(value)
+ sizes[component_match] += int(value[1]['committed'])
+
class CSVCommand(PolicyCommands):
def __init__(self):
@@ -1512,16 +1604,17 @@ class MapCommand(Command):
if not x:
out.write('None\n')
elif x[0] == 'hooked':
- attrs = x[1].split()
- assert len(attrs) == 3
- bucket_id = int(attrs[2])
+ region_info = x[1]
+ bucket_id = region_info['bucket_id']
bucket = bucket_set.get(bucket_id)
component = policy.find(bucket)
- out.write('hooked %s: %s @ %d\n' % (attrs[0], component, bucket_id))
+ out.write('hooked %s: %s @ %d\n' % (
+ region_info['type'], component, bucket_id))
else:
- attrs = x[1].split()
- size = int(attrs[1])
- out.write('unhooked %s: %d bytes committed\n' % (attrs[0], size))
+ region_info = x[1]
+ size = region_info['committed']
+ out.write('unhooked %s: %d bytes committed\n' % (
+ region_info['type'], size))
class ExpandCommand(Command):

Powered by Google App Engine
This is Rietveld 408576698