| Index: tools/deep_memory_profiler/lib/bucket.py
|
| diff --git a/tools/deep_memory_profiler/lib/bucket.py b/tools/deep_memory_profiler/lib/bucket.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..51af5b2ddd82bc18f1420c4202fa80f5f039f754
|
| --- /dev/null
|
| +++ b/tools/deep_memory_profiler/lib/bucket.py
|
| @@ -0,0 +1,191 @@
|
| +# 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
|
|
|