Home | History | Annotate | Download | only in lib
      1 # Copyright 2013 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import os
      7 
      8 from lib.symbol import FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS, TYPEINFO_SYMBOLS
      9 
     10 
     11 LOGGER = logging.getLogger('dmprof')
     12 
     13 # Indexes in dumped heap profile dumps.
     14 VIRTUAL, COMMITTED, ALLOC_COUNT, FREE_COUNT, _, BUCKET_ID = range(6)
     15 
     16 
     17 class Bucket(object):
     18   """Represents a bucket, which is a unit of memory block classification."""
     19 
     20   def __init__(self, stacktrace, allocator_type, typeinfo, typeinfo_name):
     21     self._stacktrace = stacktrace
     22     self._allocator_type = allocator_type
     23     self._typeinfo = typeinfo
     24     self._typeinfo_name = typeinfo_name
     25 
     26     self._symbolized_stackfunction = stacktrace
     27     self._symbolized_joined_stackfunction = ''
     28     self._symbolized_stacksourcefile = stacktrace
     29     self._symbolized_joined_stacksourcefile = ''
     30     self._symbolized_typeinfo = typeinfo_name
     31 
     32     self.component_cache = ''
     33 
     34   def __str__(self):
     35     result = []
     36     result.append(self._allocator_type)
     37     if self._symbolized_typeinfo == 'no typeinfo':
     38       result.append('tno_typeinfo')
     39     else:
     40       result.append('t' + self._symbolized_typeinfo)
     41     result.append('n' + self._typeinfo_name)
     42     result.extend(['%s(@%s)' % (function, sourcefile)
     43                    for function, sourcefile
     44                    in zip(self._symbolized_stackfunction,
     45                           self._symbolized_stacksourcefile)])
     46     return ' '.join(result)
     47 
     48   def symbolize(self, symbol_mapping_cache):
     49     """Makes a symbolized stacktrace and typeinfo with |symbol_mapping_cache|.
     50 
     51     Args:
     52         symbol_mapping_cache: A SymbolMappingCache object.
     53     """
     54     # TODO(dmikurube): Fill explicitly with numbers if symbol not found.
     55     self._symbolized_stackfunction = [
     56         symbol_mapping_cache.lookup(FUNCTION_SYMBOLS, address)
     57         for address in self._stacktrace]
     58     self._symbolized_joined_stackfunction = ' '.join(
     59         self._symbolized_stackfunction)
     60     self._symbolized_stacksourcefile = [
     61         symbol_mapping_cache.lookup(SOURCEFILE_SYMBOLS, address)
     62         for address in self._stacktrace]
     63     self._symbolized_joined_stacksourcefile = ' '.join(
     64         self._symbolized_stacksourcefile)
     65     if not self._typeinfo:
     66       self._symbolized_typeinfo = 'no typeinfo'
     67     else:
     68       self._symbolized_typeinfo = symbol_mapping_cache.lookup(
     69           TYPEINFO_SYMBOLS, self._typeinfo)
     70       if not self._symbolized_typeinfo:
     71         self._symbolized_typeinfo = 'no typeinfo'
     72 
     73   def clear_component_cache(self):
     74     self.component_cache = ''
     75 
     76   @property
     77   def stacktrace(self):
     78     return self._stacktrace
     79 
     80   @property
     81   def allocator_type(self):
     82     return self._allocator_type
     83 
     84   @property
     85   def typeinfo(self):
     86     return self._typeinfo
     87 
     88   @property
     89   def typeinfo_name(self):
     90     return self._typeinfo_name
     91 
     92   @property
     93   def symbolized_stackfunction(self):
     94     return self._symbolized_stackfunction
     95 
     96   @property
     97   def symbolized_joined_stackfunction(self):
     98     return self._symbolized_joined_stackfunction
     99 
    100   @property
    101   def symbolized_stacksourcefile(self):
    102     return self._symbolized_stacksourcefile
    103 
    104   @property
    105   def symbolized_joined_stacksourcefile(self):
    106     return self._symbolized_joined_stacksourcefile
    107 
    108   @property
    109   def symbolized_typeinfo(self):
    110     return self._symbolized_typeinfo
    111 
    112 
    113 class BucketSet(object):
    114   """Represents a set of bucket."""
    115   def __init__(self):
    116     self._buckets = {}
    117     self._code_addresses = set()
    118     self._typeinfo_addresses = set()
    119 
    120   def load(self, prefix):
    121     """Loads all related bucket files.
    122 
    123     Args:
    124         prefix: A prefix string for bucket file names.
    125     """
    126     LOGGER.info('Loading bucket files.')
    127 
    128     n = 0
    129     skipped = 0
    130     while True:
    131       path = '%s.%04d.buckets' % (prefix, n)
    132       if not os.path.exists(path) or not os.stat(path).st_size:
    133         if skipped > 10:
    134           break
    135         n += 1
    136         skipped += 1
    137         continue
    138       LOGGER.info('  %s' % path)
    139       with open(path, 'r') as f:
    140         self._load_file(f)
    141       n += 1
    142       skipped = 0
    143 
    144   def _load_file(self, bucket_f):
    145     for line in bucket_f:
    146       words = line.split()
    147       typeinfo = None
    148       typeinfo_name = ''
    149       stacktrace_begin = 2
    150       for index, word in enumerate(words):
    151         if index < 2:
    152           continue
    153         if word[0] == 't':
    154           typeinfo = int(word[1:], 16)
    155           self._typeinfo_addresses.add(typeinfo)
    156         elif word[0] == 'n':
    157           typeinfo_name = word[1:]
    158         else:
    159           stacktrace_begin = index
    160           break
    161       stacktrace = [int(address, 16) for address in words[stacktrace_begin:]]
    162       for frame in stacktrace:
    163         self._code_addresses.add(frame)
    164       self._buckets[int(words[0])] = Bucket(
    165           stacktrace, words[1], typeinfo, typeinfo_name)
    166 
    167   def __iter__(self):
    168     for bucket_id, bucket_content in self._buckets.iteritems():
    169       yield bucket_id, bucket_content
    170 
    171   def __getitem__(self, bucket_id):
    172     return self._buckets[bucket_id]
    173 
    174   def get(self, bucket_id):
    175     return self._buckets.get(bucket_id)
    176 
    177   def symbolize(self, symbol_mapping_cache):
    178     for bucket_content in self._buckets.itervalues():
    179       bucket_content.symbolize(symbol_mapping_cache)
    180 
    181   def clear_component_cache(self):
    182     for bucket_content in self._buckets.itervalues():
    183       bucket_content.clear_component_cache()
    184 
    185   def iter_addresses(self, symbol_type):
    186     if symbol_type in [FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS]:
    187       for function in self._code_addresses:
    188         yield function
    189     else:
    190       for function in self._typeinfo_addresses:
    191         yield function
    192