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): |