shaka-packager/tools/deep_memory_profiler/lib/bucket.py

192 lines
5.5 KiB
Python

# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
from lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS
LOGGER = logging.getLogger('dmprof')
# Indexes in dumped heap profile dumps.
VIRTUAL, COMMITTED, ALLOC_COUNT, FREE_COUNT, _, BUCKET_ID = range(6)
class Bucket(object):
"""Represents a bucket, which is a unit of memory block classification."""
def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name):
self._stacktrace = stacktrace
self._allocator_type = allocator_type
self._typeinfo = typeinfo
self._typeinfo_name = typeinfo_name
self._symbolized_stackfunction = stacktrace
self._symbolized_joined_stackfunction = ''
self._symbolized_stacksourcefile = stacktrace
self._symbolized_joined_stacksourcefile = ''
self._symbolized_typeinfo = typeinfo_name
self.component_cache = ''
def __str__(self):
result = []
result.append(self._allocator_type)
if self._symbolized_typeinfo == 'no typeinfo':
result.append('tno_typeinfo')
else:
result.append('t' + self._symbolized_typeinfo)
result.append('n' + self._typeinfo_name)
result.extend(['%s(@%s)' % (function, sourcefile)
for function, sourcefile
in zip(self._symbolized_stackfunction,
self._symbolized_stacksourcefile)])
return ' '.join(result)
def symbolize(self, symbol_mapping_cache):
"""Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|.
Args:
symbol_mapping_cache: A SymbolMappingCache object.
"""
# TODO(dmikurube): Fill explicitly with numbers if symbol not found.
self._symbolized_stackfunction = [
symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address)
for address in self._stacktrace]
self._symbolized_joined_stackfunction = ' '.join(
self._symbolized_stackfunction)
self._symbolized_stacksourcefile = [
symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address)
for address in self._stacktrace]
self._symbolized_joined_stacksourcefile = ' '.join(
self._symbolized_stacksourcefile)
if not self._typeinfo:
self._symbolized_typeinfo = 'no typeinfo'
else:
self._symbolized_typeinfo = symbol_mapping_cache.lookup(
TYPEINFO_SYMBOLS, self._typeinfo)
if not self._symbolized_typeinfo:
self._symbolized_typeinfo = 'no typeinfo'
def clear_component_cache(self):
self.component_cache = ''
@property
def stacktrace(self):
return self._stacktrace
@property
def allocator_type(self):
return self._allocator_type
@property
def typeinfo(self):
return self._typeinfo
@property
def typeinfo_name(self):
return self._typeinfo_name
@property
def symbolized_stackfunction(self):
return self._symbolized_stackfunction
@property
def symbolized_joined_stackfunction(self):
return self._symbolized_joined_stackfunction
@property
def symbolized_stacksourcefile(self):
return self._symbolized_stacksourcefile
@property
def symbolized_joined_stacksourcefile(self):
return self._symbolized_joined_stacksourcefile
@property
def symbolized_typeinfo(self):
return self._symbolized_typeinfo
class BucketSet(object):
"""Represents a set of bucket."""
def __init__(self):
self._buckets = {}
self._code_addresses = set()
self._typeinfo_addresses = set()
def load(self, prefix):
"""Loads all related bucket files.
Args:
prefix: A prefix string for bucket file names.
"""
LOGGER.info('Loading bucket files.')
n = 0
skipped = 0
while True:
path = '%s.%04d.buckets' % (prefix, n)
if not os.path.exists(path) or not os.stat(path).st_size:
if skipped > 10:
break
n += 1
skipped += 1
continue
LOGGER.info(' %s' % path)
with open(path, 'r') as f:
self._load_file(f)
n += 1
skipped = 0
def _load_file(self, bucket_f):
for line in bucket_f:
words = line.split()
typeinfo = None
typeinfo_name = ''
stacktrace_begin = 2
for index, word in enumerate(words):
if index < 2:
continue
if word[0] == 't':
typeinfo = int(word[1:], 16)
self._typeinfo_addresses.add(typeinfo)
elif word[0] == 'n':
typeinfo_name = word[1:]
else:
stacktrace_begin = index
break
stacktrace = [int(address, 16) for address in words[stacktrace_begin:]]
for frame in stacktrace:
self._code_addresses.add(frame)
self._buckets[int(words[0])] = Bucket(
stacktrace, words[1], typeinfo, typeinfo_name)
def __iter__(self):
for bucket_id, bucket_content in self._buckets.iteritems():
yield bucket_id, bucket_content
def __getitem__(self, bucket_id):
return self._buckets[bucket_id]
def get(self, bucket_id):
return self._buckets.get(bucket_id)
def symbolize(self, symbol_mapping_cache):
for bucket_content in self._buckets.itervalues():
bucket_content.symbolize(symbol_mapping_cache)
def clear_component_cache(self):
for bucket_content in self._buckets.itervalues():
bucket_content.clear_component_cache()
def iter_addresses(self, symbol_type):
if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]:
for function in self._code_addresses:
yield function
else:
for function in self._typeinfo_addresses:
yield function