17dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Copyright 2013 The Chromium Authors. All rights reserved.
27dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Use of this source code is governed by a BSD-style license that can be
37dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# found in the LICENSE file.
47dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport logging
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport os
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochLOGGER = logging.getLogger('dmprof')
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch# Indexes in dumped heap profile dumps.
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochVIRTUAL, COMMITTED, ALLOC_COUNT, FREE_COUNT, _, BUCKET_ID = range(6)
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass Bucket(object):
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  """Represents a bucket, which is a unit of memory block classification."""
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name):
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._stacktrace = stacktrace
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._allocator_type = allocator_type
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._typeinfo = typeinfo
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._typeinfo_name = typeinfo_name
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_stackfunction = stacktrace
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_joined_stackfunction = ''
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_stacksourcefile = stacktrace
297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_joined_stacksourcefile = ''
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_typeinfo = typeinfo_name
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self.component_cache = ''
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __str__(self):
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    result = []
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    result.append(self._allocator_type)
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if self._symbolized_typeinfo == 'no typeinfo':
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      result.append('tno_typeinfo')
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    else:
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      result.append('t' + self._symbolized_typeinfo)
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    result.append('n' + self._typeinfo_name)
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    result.extend(['%s(@%s)' % (function, sourcefile)
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                   for function, sourcefile
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                   in zip(self._symbolized_stackfunction,
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                          self._symbolized_stacksourcefile)])
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return ' '.join(result)
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolize(self, symbol_mapping_cache):
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|.
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Args:
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        symbol_mapping_cache: A SymbolMappingCache object.
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # TODO(dmikurube): Fill explicitly with numbers if symbol not found.
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_stackfunction = [
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address)
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        for address in self._stacktrace]
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_joined_stackfunction = ' '.join(
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        self._symbolized_stackfunction)
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_stacksourcefile = [
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address)
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        for address in self._stacktrace]
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._symbolized_joined_stacksourcefile = ' '.join(
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        self._symbolized_stacksourcefile)
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if not self._typeinfo:
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      self._symbolized_typeinfo = 'no typeinfo'
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    else:
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      self._symbolized_typeinfo = symbol_mapping_cache.lookup(
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          TYPEINFO_SYMBOLS, self._typeinfo)
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if not self._symbolized_typeinfo:
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        self._symbolized_typeinfo = 'no typeinfo'
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def clear_component_cache(self):
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self.component_cache = ''
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def stacktrace(self):
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._stacktrace
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def allocator_type(self):
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._allocator_type
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def typeinfo(self):
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._typeinfo
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def typeinfo_name(self):
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._typeinfo_name
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolized_stackfunction(self):
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._symbolized_stackfunction
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolized_joined_stackfunction(self):
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._symbolized_joined_stackfunction
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolized_stacksourcefile(self):
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._symbolized_stacksourcefile
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolized_joined_stacksourcefile(self):
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._symbolized_joined_stacksourcefile
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @property
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolized_typeinfo(self):
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._symbolized_typeinfo
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass BucketSet(object):
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  """Represents a set of bucket."""
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self):
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._buckets = {}
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._code_addresses = set()
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._typeinfo_addresses = set()
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def load(self, prefix):
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """Loads all related bucket files.
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Args:
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        prefix: A prefix string for bucket file names.
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    LOGGER.info('Loading bucket files.')
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    n = 0
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    skipped = 0
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    while True:
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      path = '%s.%04d.buckets' % (prefix, n)
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if not os.path.exists(path) or not os.stat(path).st_size:
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if skipped > 10:
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          break
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        n += 1
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        skipped += 1
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        continue
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.info('  %s' % path)
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      with open(path, 'r') as f:
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        self._load_file(f)
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      n += 1
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      skipped = 0
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def _load_file(self, bucket_f):
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for line in bucket_f:
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      words = line.split()
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      typeinfo = None
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      typeinfo_name = ''
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      stacktrace_begin = 2
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for index, word in enumerate(words):
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if index < 2:
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          continue
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if word[0] == 't':
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          typeinfo = int(word[1:], 16)
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          self._typeinfo_addresses.add(typeinfo)
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        elif word[0] == 'n':
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          typeinfo_name = word[1:]
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        else:
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          stacktrace_begin = index
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          break
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      stacktrace = [int(address, 16) for address in words[stacktrace_begin:]]
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for frame in stacktrace:
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        self._code_addresses.add(frame)
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      self._buckets[int(words[0])] = Bucket(
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          stacktrace, words[1], typeinfo, typeinfo_name)
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __iter__(self):
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for bucket_id, bucket_content in self._buckets.iteritems():
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      yield bucket_id, bucket_content
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __getitem__(self, bucket_id):
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._buckets[bucket_id]
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def get(self, bucket_id):
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._buckets.get(bucket_id)
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def symbolize(self, symbol_mapping_cache):
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for bucket_content in self._buckets.itervalues():
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bucket_content.symbolize(symbol_mapping_cache)
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def clear_component_cache(self):
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for bucket_content in self._buckets.itervalues():
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bucket_content.clear_component_cache()
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def iter_addresses(self, symbol_type):
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]:
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for function in self._code_addresses:
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        yield function
1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    else:
1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for function in self._typeinfo_addresses:
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        yield function
192