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