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 datetime
67dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport json
77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport logging
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochimport sys
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.pageframe import PFNCounts
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.policy import PolicySet
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom lib.subcommand import SubCommand
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochLOGGER = logging.getLogger('dmprof')
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass PolicyCommands(SubCommand):
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self, command):
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    super(PolicyCommands, self).__init__(
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'Usage: %%prog %s [-p POLICY] <first-dump> [shared-first-dumps...]' %
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        command)
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._parser.add_option('-p', '--policy', type='string', dest='policy',
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            help='profile with POLICY', metavar='POLICY')
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    self._parser.add_option('--alternative-dirs', dest='alternative_dirs',
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            metavar='/path/on/target@/path/on/host[:...]',
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            help='Read files in /path/on/host/ instead of '
287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 'files in /path/on/target/.')
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._parser.add_option('--timestamp', dest='timestamp',
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            action='store_true', help='Use timestamp.')
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._timestamp = False
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def _set_up(self, sys_argv):
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    options, args = self._parse_args(sys_argv, 1)
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    dump_path = args[1]
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    shared_first_dump_paths = args[2:]
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    alternative_dirs_dict = {}
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if options.alternative_dirs:
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for alternative_dir_pair in options.alternative_dirs.split(':'):
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        target_path, host_path = alternative_dir_pair.split('@', 1)
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        alternative_dirs_dict[target_path] = host_path
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    (bucket_set, dumps) = SubCommand.load_basic_files(
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump_path, True, alternative_dirs=alternative_dirs_dict)
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._timestamp = options.timestamp
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    pfn_counts_dict = {}
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for shared_first_dump_path in shared_first_dump_paths:
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      shared_dumps = SubCommand._find_all_dumps(shared_first_dump_path)
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for shared_dump in shared_dumps:
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        pfn_counts = PFNCounts.load(shared_dump)
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if pfn_counts.pid not in pfn_counts_dict:
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          pfn_counts_dict[pfn_counts.pid] = []
547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        pfn_counts_dict[pfn_counts.pid].append(pfn_counts)
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    policy_set = PolicySet.load(SubCommand._parse_policy_list(options.policy))
577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return policy_set, dumps, pfn_counts_dict, bucket_set
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _apply_policy(self, dump, pfn_counts_dict, policy, bucket_set,
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    first_dump_time):
617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """Aggregates the total memory size of each component.
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Iterate through all stacktraces and attribute them to one of the components
647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    based on the policy.  It is important to apply policy in right order.
657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Args:
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump: A Dump object.
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        pfn_counts_dict: A dict mapping a pid to a list of PFNCounts.
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        policy: A Policy object.
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        bucket_set: A BucketSet object.
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        first_dump_time: An integer representing time when the first dump is
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            dumped.
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Returns:
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        A dict mapping components and their corresponding sizes.
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    """
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    LOGGER.info('  %s' % dump.path)
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    all_pfn_dict = {}
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if pfn_counts_dict:
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.info('    shared with...')
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for pid, pfnset_list in pfn_counts_dict.iteritems():
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        closest_pfnset_index = None
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        closest_pfnset_difference = 1024.0
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        for index, pfnset in enumerate(pfnset_list):
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          time_difference = pfnset.time - dump.time
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          if time_difference >= 3.0:
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            break
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          elif ((time_difference < 0.0 and pfnset.reason != 'Exiting') or
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                (0.0 <= time_difference and time_difference < 3.0)):
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            closest_pfnset_index = index
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            closest_pfnset_difference = time_difference
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          elif time_difference < 0.0 and pfnset.reason == 'Exiting':
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            closest_pfnset_index = None
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            break
957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if closest_pfnset_index:
967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          for pfn, count in pfnset_list[closest_pfnset_index].iter_pfn:
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            all_pfn_dict[pfn] = all_pfn_dict.get(pfn, 0) + count
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          LOGGER.info('      %s (time difference = %f)' %
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      (pfnset_list[closest_pfnset_index].path,
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                       closest_pfnset_difference))
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        else:
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          LOGGER.info('      (no match with pid:%d)' % pid)
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes = dict((c, 0) for c in policy.components)
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    PolicyCommands._accumulate_malloc(dump, policy, bucket_set, sizes)
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    verify_global_stats = PolicyCommands._accumulate_maps(
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump, all_pfn_dict, policy, bucket_set, sizes)
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # TODO(dmikurube): Remove the verifying code when GLOBAL_STATS is removed.
1117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # http://crbug.com/245603.
1127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for verify_key, verify_value in verify_global_stats.iteritems():
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dump_value = dump.global_stat('%s_committed' % verify_key)
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if dump_value != verify_value:
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        LOGGER.warn('%25s: %12d != %d (%d)' % (
1167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            verify_key, dump_value, verify_value, dump_value - verify_value))
1177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['mmap-no-log'] = (
1197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump.global_stat('profiled-mmap_committed') -
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sizes['mmap-total-log'])
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['mmap-total-record'] = dump.global_stat('profiled-mmap_committed')
1227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['mmap-total-record-vm'] = dump.global_stat('profiled-mmap_virtual')
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['tc-no-log'] = (
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump.global_stat('profiled-malloc_committed') -
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sizes['tc-total-log'])
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['tc-total-record'] = dump.global_stat('profiled-malloc_committed')
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['tc-unused'] = (
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sizes['mmap-tcmalloc'] -
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        dump.global_stat('profiled-malloc_committed'))
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if sizes['tc-unused'] < 0:
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.warn('    Assuming tc-unused=0 as it is negative: %d (bytes)' %
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                  sizes['tc-unused'])
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sizes['tc-unused'] = 0
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    sizes['tc-total'] = sizes['mmap-tcmalloc']
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # TODO(dmikurube): global_stat will be deprecated.
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # See http://crbug.com/245603.
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for key, value in {
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'total': 'total_committed',
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'filemapped': 'file_committed',
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'absent': 'absent_committed',
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'file-exec': 'file-exec_committed',
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'file-nonexec': 'file-nonexec_committed',
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'anonymous': 'anonymous_committed',
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'stack': 'stack_committed',
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'other': 'other_committed',
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'unhooked-absent': 'nonprofiled-absent_committed',
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'total-vm': 'total_virtual',
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'filemapped-vm': 'file_virtual',
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'anonymous-vm': 'anonymous_virtual',
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'other-vm': 'other_virtual' }.iteritems():
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if key in sizes:
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        sizes[key] = dump.global_stat(value)
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if 'mustbezero' in sizes:
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      removed_list = (
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'profiled-mmap_committed',
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-absent_committed',
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-anonymous_committed',
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-file-exec_committed',
1627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-file-nonexec_committed',
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-stack_committed',
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          'nonprofiled-other_committed')
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sizes['mustbezero'] = (
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          dump.global_stat('total_committed') -
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          sum(dump.global_stat(removed) for removed in removed_list))
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if 'total-exclude-profiler' in sizes:
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sizes['total-exclude-profiler'] = (
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          dump.global_stat('total_committed') -
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          (sizes['mmap-profiler'] + sizes['mmap-type-profiler']))
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if 'hour' in sizes:
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sizes['hour'] = (dump.time - first_dump_time) / 60.0 / 60.0
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if 'minute' in sizes:
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      sizes['minute'] = (dump.time - first_dump_time) / 60.0
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if 'second' in sizes:
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if self._timestamp:
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        sizes['second'] = datetime.datetime.fromtimestamp(dump.time).isoformat()
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      else:
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        sizes['second'] = dump.time - first_dump_time
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return sizes
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @staticmethod
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def _accumulate_malloc(dump, policy, bucket_set, sizes):
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for bucket_id, _, committed, _, _ in dump.iter_stacktrace:
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      bucket = bucket_set.get(bucket_id)
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if not bucket or bucket.allocator_type == 'malloc':
1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        component_match = policy.find_malloc(bucket)
1907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      elif bucket.allocator_type == 'mmap':
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        continue
1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      else:
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        assert False
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      sizes[component_match] += committed
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      assert not component_match.startswith('mmap-')
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if component_match.startswith('tc-'):
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        sizes['tc-total-log'] += committed
1997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      else:
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        sizes['other-total-log'] += committed
2017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  @staticmethod
2037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def _accumulate_maps(dump, pfn_dict, policy, bucket_set, sizes):
2047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # TODO(dmikurube): Remove the dict when GLOBAL_STATS is removed.
2057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # http://crbug.com/245603.
2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    global_stats = {
2077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'total': 0,
2087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'file-exec': 0,
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'file-nonexec': 0,
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'anonymous': 0,
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'stack': 0,
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'other': 0,
2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'nonprofiled-file-exec': 0,
2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'nonprofiled-file-nonexec': 0,
2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'nonprofiled-anonymous': 0,
2167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'nonprofiled-stack': 0,
2177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'nonprofiled-other': 0,
2187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'profiled-mmap': 0,
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for key, value in dump.iter_map:
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      # TODO(dmikurube): Remove the subtotal code when GLOBAL_STATS is removed.
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      # It's temporary verification code for transition described in
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      # http://crbug.com/245603.
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      committed = 0
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if 'committed' in value[1]:
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        committed = value[1]['committed']
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      global_stats['total'] += committed
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      key = 'other'
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      name = value[1]['vma']['name']
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if name.startswith('/'):
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if value[1]['vma']['executable'] == 'x':
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          key = 'file-exec'
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        else:
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          key = 'file-nonexec'
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      elif name == '[stack]':
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        key = 'stack'
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      elif name == '':
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        key = 'anonymous'
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      global_stats[key] += committed
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if value[0] == 'unhooked':
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        global_stats['nonprofiled-' + key] += committed
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if value[0] == 'hooked':
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        global_stats['profiled-mmap'] += committed
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if value[0] == 'unhooked':
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if pfn_dict and dump.pageframe_length:
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          for pageframe in value[1]['pageframe']:
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            component_match = policy.find_unhooked(value, pageframe, pfn_dict)
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            sizes[component_match] += pageframe.size
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        else:
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          component_match = policy.find_unhooked(value)
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          sizes[component_match] += int(value[1]['committed'])
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      elif value[0] == 'hooked':
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if pfn_dict and dump.pageframe_length:
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          for pageframe in value[1]['pageframe']:
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            component_match, _ = policy.find_mmap(
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                value, bucket_set, pageframe, pfn_dict)
2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            sizes[component_match] += pageframe.size
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            assert not component_match.startswith('tc-')
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            if component_match.startswith('mmap-'):
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch              sizes['mmap-total-log'] += pageframe.size
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            else:
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch              sizes['other-total-log'] += pageframe.size
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        else:
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          component_match, _ = policy.find_mmap(value, bucket_set)
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          sizes[component_match] += int(value[1]['committed'])
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          if component_match.startswith('mmap-'):
2697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            sizes['mmap-total-log'] += int(value[1]['committed'])
2707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          else:
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            sizes['other-total-log'] += int(value[1]['committed'])
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      else:
2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        LOGGER.error('Unrecognized mapping status: %s' % value[0])
2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return global_stats
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass CSVCommand(PolicyCommands):
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self):
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    super(CSVCommand, self).__init__('csv')
2817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def do(self, sys_argv):
2837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._output(
2857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
2887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    max_components = 0
2897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for label in policy_set:
2907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      max_components = max(max_components, len(policy_set[label].components))
2917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for label in sorted(policy_set):
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      components = policy_set[label].components
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if len(policy_set) > 1:
2957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        out.write('%s%s\n' % (label, ',' * (max_components - 1)))
2967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      out.write('%s%s\n' % (
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ','.join(components), ',' * (max_components - len(components))))
2987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.info('Applying a policy %s to...' % label)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for index, dump in enumerate(dumps):
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if index == 0:
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          first_dump_time = dump.time
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        component_sizes = self._apply_policy(
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            dump, pfn_counts_dict, policy_set[label], bucket_set,
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            first_dump_time)
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        s = []
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        for c in components:
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          if c in ('hour', 'minute', 'second'):
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            if isinstance(component_sizes[c], str):
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              s.append('%s' % component_sizes[c])
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            else:
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              s.append('%05.5f' % (component_sizes[c]))
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          else:
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            s.append('%05.5f' % (component_sizes[c] / 1024.0 / 1024.0))
3157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        out.write('%s%s\n' % (
3167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch              ','.join(s), ',' * (max_components - len(components))))
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bucket_set.clear_component_cache()
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return 0
3217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass JSONCommand(PolicyCommands):
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self):
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    super(JSONCommand, self).__init__('json')
3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def do(self, sys_argv):
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._output(
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
3317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    json_base = {
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      'version': 'JSON_DEEP_2',
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      'policies': {},
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for label in sorted(policy_set):
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      json_base['policies'][label] = {
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'legends': policy_set[label].components,
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        'snapshots': [],
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.info('Applying a policy %s to...' % label)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for index, dump in enumerate(dumps):
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if index == 0:
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          first_dump_time = dump.time
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        component_sizes = self._apply_policy(
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            dump, pfn_counts_dict, policy_set[label], bucket_set,
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            first_dump_time)
3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        component_sizes['dump_path'] = dump.path
3527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        component_sizes['dump_time'] = datetime.datetime.fromtimestamp(
3537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            dump.time).strftime('%Y-%m-%d %H:%M:%S')
3547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        json_base['policies'][label]['snapshots'].append(component_sizes)
3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bucket_set.clear_component_cache()
3577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    json.dump(json_base, out, indent=2, sort_keys=True)
3597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return 0
3617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass ListCommand(PolicyCommands):
3647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def __init__(self):
3657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    super(ListCommand, self).__init__('list')
3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def do(self, sys_argv):
3687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
3693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._output(
3707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
3717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for label in sorted(policy_set):
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      LOGGER.info('Applying a policy %s to...' % label)
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      for dump in dumps:
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        component_sizes = self._apply_policy(
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            dump, pfn_counts_dict, policy_set[label], bucket_set, dump.time)
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        out.write('%s for %s:\n' % (label, dump.path))
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        for c in policy_set[label].components:
3807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          if c in ['hour', 'minute', 'second']:
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            out.write('%40s %12.3f\n' % (c, component_sizes[c]))
3827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          else:
3837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            out.write('%40s %12d\n' % (c, component_sizes[c]))
3847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bucket_set.clear_component_cache()
3867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return 0
388