Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Unified Diff: tools/deep_memory_profiler/dmprof.py

Issue 9812010: Breakdown nonprofiled memory regions (f.k.a. 'unknown'), and add new policy files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: reflected the comments. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/deep_memory_profiler/dmprof ('k') | tools/deep_memory_profiler/policy.l0.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/deep_memory_profiler/dmprof.py
diff --git a/tools/deep_memory_profiler/dmprof.py b/tools/deep_memory_profiler/dmprof.py
deleted file mode 100755
index e9c642c80d168cb82a2b455cabe0aa0efb16ccf0..0000000000000000000000000000000000000000
--- a/tools/deep_memory_profiler/dmprof.py
+++ /dev/null
@@ -1,767 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""The deep heap profiler script for Chrome."""
-
-from datetime import datetime
-import json
-import os
-import re
-import subprocess
-import sys
-import tempfile
-
-BUCKET_ID = 5
-VIRTUAL = 0
-COMMITTED = 1
-ALLOC_COUNT = 2
-FREE_COUNT = 3
-NULL_REGEX = re.compile('')
-PPROF_PATH = os.path.join(os.path.dirname(__file__),
- os.pardir,
- os.pardir,
- 'third_party',
- 'tcmalloc',
- 'chromium',
- 'src',
- 'pprof')
-
-# Heap Profile Dump versions
-
-# DUMP_DEEP_1 DOES NOT distinct mmap regions and malloc chunks.
-# Their stacktraces DO contain mmap* or tc-* at their tops.
-# They should be processed by POLICY_DEEP_1.
-DUMP_DEEP_1 = 'DUMP_DEEP_1'
-
-# DUMP_DEEP_2 DOES distinct mmap regions and malloc chunks.
-# Their stacktraces still DO contain mmap* or tc-*.
-# They should be processed by POLICY_DEEP_1.
-DUMP_DEEP_2 = 'DUMP_DEEP_2'
-
-# DUMP_DEEP_3 DOES distinct mmap regions and malloc chunks.
-# Their stacktraces DO NOT contain mmap* or tc-*.
-# They should be processed by POLICY_DEEP_2.
-DUMP_DEEP_3 = 'DUMP_DEEP_3'
-
-# Heap Profile Policy versions
-
-# POLICY_DEEP_1 DOES NOT include allocation_type columns.
-# mmap regions are distincted w/ mmap frames in the pattern column.
-POLICY_DEEP_1 = 'POLICY_DEEP_1'
-
-# POLICY_DEEP_2 DOES include allocation_type columns.
-# mmap regions are distincted w/ the allocation_type column.
-POLICY_DEEP_2 = 'POLICY_DEEP_2'
-
-# TODO(dmikurube): Avoid global variables.
-address_symbol_dict = {}
-appeared_addresses = set()
-components = []
-
-
-class Policy(object):
-
- def __init__(self, name, mmap, pattern):
- self.name = name
- self.mmap = mmap
- self.condition = re.compile(pattern + r'\Z')
-
-
-def get_component(policy_list, bucket, mmap):
- """Returns a component name which a given bucket belongs to.
-
- Args:
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- bucket: A Bucket object to be searched for.
- mmap: True if searching for a mmap region.
-
- Returns:
- A string representing a component name.
- """
- if not bucket:
- return 'no-bucket'
- if bucket.component:
- return bucket.component
-
- stacktrace = ''.join(
- address_symbol_dict[a] + ' ' for a in bucket.stacktrace).strip()
-
- for policy in policy_list:
- if mmap == policy.mmap and policy.condition.match(stacktrace):
- bucket.component = policy.name
- return policy.name
-
- assert False
-
-
-class Bucket(object):
-
- def __init__(self, stacktrace):
- self.stacktrace = stacktrace
- self.component = ''
-
-
-class Log(object):
-
- """A class representing one dumped log data."""
- def __init__(self, log_path, buckets):
- self.log_path = log_path
- with open(self.log_path, mode='r') as log_f:
- self.log_lines = log_f.readlines()
- self.log_version = ''
- sys.stderr.write('parsing a log file:%s\n' % log_path)
- self.mmap_stacktrace_lines = []
- self.malloc_stacktrace_lines = []
- self.counters = {}
- self.log_time = os.stat(self.log_path).st_mtime
- self.parse_log(buckets)
-
- @staticmethod
- def dump_stacktrace_lines(stacktrace_lines, buckets):
- """Prints a given stacktrace.
-
- Args:
- stacktrace_lines: A list of strings which are valid as stacktraces.
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- """
- for l in stacktrace_lines:
- words = l.split()
- bucket = buckets.get(int(words[BUCKET_ID]))
- if not bucket:
- continue
- for i in range(0, BUCKET_ID - 1):
- sys.stdout.write(words[i] + ' ')
- for address in bucket.stacktrace:
- sys.stdout.write((address_symbol_dict.get(address) or address) + ' ')
- sys.stdout.write('\n')
-
- def dump_stacktrace(self, buckets):
- """Prints stacktraces contained in the log.
-
- Args:
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- """
- self.dump_stacktrace_lines(self.mmap_stacktrace_lines, buckets)
- self.dump_stacktrace_lines(self.malloc_stacktrace_lines, buckets)
-
- @staticmethod
- def accumulate_size_for_pprof(stacktrace_lines, policy_list, buckets,
- component_name, mmap):
- """Accumulates size of committed chunks and the number of allocated chunks.
-
- Args:
- stacktrace_lines: A list of strings which are valid as stacktraces.
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- component_name: A name of component for filtering.
- mmap: True if searching for a mmap region.
-
- Returns:
- Two integers which are the accumulated size of committed regions and the
- number of allocated chunks, respectively.
- """
- com_committed = 0
- com_allocs = 0
- for l in stacktrace_lines:
- words = l.split()
- bucket = buckets.get(int(words[BUCKET_ID]))
- if (not bucket or
- (component_name and
- component_name != get_component(policy_list, bucket, mmap))):
- continue
-
- com_committed += int(words[COMMITTED])
- com_allocs += int(words[ALLOC_COUNT]) - int(words[FREE_COUNT])
-
- return com_committed, com_allocs
-
- @staticmethod
- def dump_stacktrace_lines_for_pprof(stacktrace_lines, policy_list,
- buckets, component_name, mmap):
- """Prints information of stacktrace lines for pprof.
-
- Args:
- stacktrace_lines: A list of strings which are valid as stacktraces.
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- component_name: A name of component for filtering.
- mmap: True if searching for a mmap region.
- """
- for l in stacktrace_lines:
- words = l.split()
- bucket = buckets.get(int(words[BUCKET_ID]))
- if (not bucket or
- (component_name and
- component_name != get_component(policy_list, bucket, mmap))):
- continue
-
- sys.stdout.write('%6d: %8s [%6d: %8s] @' % (
- int(words[ALLOC_COUNT]) - int(words[FREE_COUNT]),
- words[COMMITTED],
- int(words[ALLOC_COUNT]) - int(words[FREE_COUNT]),
- words[COMMITTED]))
- for address in bucket.stacktrace:
- sys.stdout.write(' ' + address)
- sys.stdout.write('\n')
-
- def dump_for_pprof(self, policy_list, buckets, mapping_lines, component_name):
- """Converts the log file so it can be processed by pprof.
-
- Args:
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- mapping_lines: A list of strings containing /proc/.../maps.
- component_name: A name of component for filtering.
- """
- sys.stdout.write('heap profile: ')
- com_committed, com_allocs = self.accumulate_size_for_pprof(
- self.mmap_stacktrace_lines, policy_list, buckets, component_name,
- True)
- add_committed, add_allocs = self.accumulate_size_for_pprof(
- self.malloc_stacktrace_lines, policy_list, buckets, component_name,
- False)
- com_committed += add_committed
- com_allocs += add_allocs
-
- sys.stdout.write('%6d: %8s [%6d: %8s] @ heapprofile\n' % (
- com_allocs, com_committed, com_allocs, com_committed))
-
- self.dump_stacktrace_lines_for_pprof(
- self.mmap_stacktrace_lines, policy_list, buckets, component_name,
- True)
- self.dump_stacktrace_lines_for_pprof(
- self.malloc_stacktrace_lines, policy_list, buckets, component_name,
- False)
-
- sys.stdout.write('MAPPED_LIBRARIES:\n')
- for l in mapping_lines:
- sys.stdout.write(l)
-
- @staticmethod
- def check_stacktrace_line(stacktrace_line, buckets):
- """Checks if a given stacktrace_line is valid as stacktrace.
-
- Args:
- stacktrace_line: A string to be checked.
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
-
- Returns:
- True if the given stacktrace_line is valid.
- """
- words = stacktrace_line.split()
- if len(words) < BUCKET_ID + 1:
- return False
- if words[BUCKET_ID - 1] != '@':
- return False
- bucket = buckets.get(int(words[BUCKET_ID]))
- if bucket:
- for address in bucket.stacktrace:
- appeared_addresses.add(address)
- return True
-
- @staticmethod
- def skip_lines_while(line_number, max_line_number, skipping_condition):
- """Increments line_number until skipping_condition(line_number) is false.
- """
- while skipping_condition(line_number):
- line_number += 1
- if line_number >= max_line_number:
- sys.stderr.write('invalid heap profile dump.')
- return line_number
- return line_number
-
- def parse_stacktraces_while_valid(self, buckets, log_lines, ln):
- """Parses stacktrace lines while the lines are valid.
-
- Args:
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- log_lines: A list of lines to be parsed.
- ln: An integer representing the starting line number in log_lines.
-
- Returns:
- A pair of a list of valid lines and an integer representing the last
- line number in log_lines.
- """
- ln = self.skip_lines_while(
- ln, len(log_lines), lambda n: not log_lines[n].split()[0].isdigit())
- stacktrace_lines_start = ln
- ln = self.skip_lines_while(
- ln, len(log_lines),
- lambda n: self.check_stacktrace_line(log_lines[n], buckets))
- return (log_lines[stacktrace_lines_start:ln], ln)
-
- def parse_stacktraces(self, buckets):
- """Parses lines in self.log_lines as stacktrace.
-
- Valid stacktrace lines are stored into self.mmap_stacktrace_lines and
- self.malloc_stacktrace_lines.
-
- Args:
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
-
- Returns:
- A string representing a version of the stacktrace dump. '' for invalid
- dump.
- """
- version = ''
-
- # Skip until an identifiable line.
- headers = ('STACKTRACES:\n', 'MMAP_STACKTRACES:\n', 'heap profile: ')
- ln = self.skip_lines_while(
- 0, len(self.log_lines),
- lambda n: not self.log_lines[n].startswith(headers))
-
- # Identify a version.
- if self.log_lines[ln].startswith('heap profile: '):
- version = self.log_lines[ln][13:].strip()
- if version == DUMP_DEEP_2 or version == DUMP_DEEP_3:
- ln = self.skip_lines_while(
- ln, len(self.log_lines),
- lambda n: self.log_lines[n] != 'MMAP_STACKTRACES:\n')
- else:
- sys.stderr.write(' invalid heap profile dump version:%s\n' % version)
- return ''
- elif self.log_lines[ln] == 'STACKTRACES:\n':
- version = DUMP_DEEP_1
- elif self.log_lines[ln] == 'MMAP_STACKTRACES:\n':
- version = DUMP_DEEP_2
-
- if version == DUMP_DEEP_3:
- sys.stderr.write(' heap profile dump version: %s\n' % version)
- (self.mmap_stacktrace_lines, ln) = self.parse_stacktraces_while_valid(
- buckets, self.log_lines, ln)
- ln = self.skip_lines_while(
- ln, len(self.log_lines),
- lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n')
- (self.malloc_stacktrace_lines, ln) = self.parse_stacktraces_while_valid(
- buckets, self.log_lines, ln)
- return version
-
- elif version == DUMP_DEEP_2:
- sys.stderr.write(' heap profile dump version: %s\n' % version)
- (self.mmap_stacktrace_lines, ln) = self.parse_stacktraces_while_valid(
- buckets, self.log_lines, ln)
- ln = self.skip_lines_while(
- ln, len(self.log_lines),
- lambda n: self.log_lines[n] != 'MALLOC_STACKTRACES:\n')
- (self.malloc_stacktrace_lines, ln) = self.parse_stacktraces_while_valid(
- buckets, self.log_lines, ln)
- self.malloc_stacktrace_lines.extend(self.mmap_stacktrace_lines)
- self.mmap_stacktrace_lines = []
- return version
-
- elif version == DUMP_DEEP_1:
- sys.stderr.write(' heap profile dump version: %s\n' % version)
- (self.malloc_stacktrace_lines, ln) = self.parse_stacktraces_while_valid(
- buckets, self.log_lines, ln)
- return version
-
- else:
- sys.stderr.write(' invalid heap profile dump version:%s\n' % version)
- return ''
-
- def parse_global_stats(self):
- """Parses lines in self.log_lines as global stats."""
- ln = self.skip_lines_while(
- 0, len(self.log_lines),
- lambda n: self.log_lines[n] != 'GLOBAL_STATS:\n')
-
- for prefix in ['total', 'file', 'anonymous', 'other', 'mmap', 'tcmalloc']:
- ln = self.skip_lines_while(
- ln, len(self.log_lines),
- lambda n: self.log_lines[n].split()[0] != prefix)
- words = self.log_lines[ln].split()
- self.counters[prefix + '_virtual'] = int(words[-2])
- self.counters[prefix + '_committed'] = int(words[-1])
-
- def parse_log(self, buckets):
- self.parse_global_stats()
- self.log_version = self.parse_stacktraces(buckets)
-
- @staticmethod
- def accumulate_size_for_policy(stacktrace_lines,
- policy_list, buckets, sizes, mmap):
- for l in stacktrace_lines:
- words = l.split()
- bucket = buckets.get(int(words[BUCKET_ID]))
- component_match = get_component(policy_list, bucket, mmap)
- sizes[component_match] += int(words[COMMITTED])
-
- if component_match.startswith('tc-'):
- sizes['tc-total-log'] += int(words[COMMITTED])
- elif component_match.startswith('mmap-'):
- sizes['mmap-total-log'] += int(words[COMMITTED])
- else:
- sizes['other-total-log'] += int(words[COMMITTED])
-
- def apply_policy(self, policy_list, buckets, first_log_time):
- """Aggregates the total memory size of each component.
-
- Iterate through all stacktraces and attribute them to one of the components
- based on the policy. It is important to apply policy in right order.
-
- Args:
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- first_log_time: An integer representing time when the first log is
- dumped.
-
- Returns:
- A dict mapping components and their corresponding sizes.
- """
-
- sys.stderr.write('apply policy:%s\n' % (self.log_path))
- sizes = dict((c, 0) for c in components)
-
- self.accumulate_size_for_policy(self.mmap_stacktrace_lines,
- policy_list, buckets, sizes, True)
- self.accumulate_size_for_policy(self.malloc_stacktrace_lines,
- policy_list, buckets, sizes, False)
-
- sizes['mmap-no-log'] = self.counters['mmap_committed'] - sizes[
- 'mmap-total-log']
- sizes['mmap-total-record'] = self.counters['mmap_committed']
- sizes['mmap-total-record-vm'] = self.counters['mmap_virtual']
-
- sizes['tc-no-log'] = self.counters['tcmalloc_committed'] - sizes[
- 'tc-total-log']
- sizes['tc-total-record'] = self.counters['tcmalloc_committed']
- sizes['tc-unused'] = sizes['mmap-tcmalloc'] - self.counters[
- 'tcmalloc_committed']
- sizes['tc-total'] = sizes['mmap-tcmalloc']
-
- for key, value in { 'total': 'total_committed',
- 'filemapped': 'file_committed',
- 'anonymous': 'anonymous_committed',
- 'other': 'other_committed',
- 'total-vm': 'total_virtual',
- 'filemapped-vm': 'file_virtual',
- 'anonymous-vm': 'anonymous_virtual',
- 'other-vm': 'other_virtual' }.items():
- if key in sizes:
- sizes[key] = self.counters[value]
-
- if 'unknown' in sizes:
- sizes['unknown'] = self.counters['total_committed'] - self.counters[
- 'mmap_committed']
- if 'total-exclude-profiler' in sizes:
- sizes['total-exclude-profiler'] = self.counters[
- 'total_committed'] - sizes['mmap-profiler']
- if 'hour' in sizes:
- sizes['hour'] = (self.log_time - first_log_time) / 60.0 / 60.0
- if 'minute' in sizes:
- sizes['minute'] = (self.log_time - first_log_time) / 60.0
- if 'second' in sizes:
- sizes['second'] = self.log_time - first_log_time
-
- return sizes
-
- @staticmethod
- def accumulate_size_for_expand(stacktrace_lines, policy_list, buckets,
- component_name, depth, sizes, mmap):
- for line in stacktrace_lines:
- words = line.split()
- bucket = buckets.get(int(words[BUCKET_ID]))
- component_match = get_component(policy_list, bucket, mmap)
- if component_match == component_name:
- stacktrace_sequence = ''
- for address in bucket.stacktrace[1 : min(len(bucket.stacktrace),
- 1 + depth)]:
- stacktrace_sequence += address_symbol_dict[address] + ' '
- if not stacktrace_sequence in sizes:
- sizes[stacktrace_sequence] = 0
- sizes[stacktrace_sequence] += int(words[COMMITTED])
-
- def expand(self, policy_list, buckets, component_name, depth):
- """Prints all stacktraces in a given component of given depth.
-
- Args:
- policy_list: A list containing Policy objects. (Parsed policy data by
- parse_policy.)
- buckets: A dict mapping bucket ids and their corresponding Bucket
- objects.
- component_name: A name of component for filtering.
- depth: An integer representing depth to be printed.
- """
- sizes = {}
-
- self.accumulate_size_for_expand(
- self.mmap_stacktrace_lines, policy_list, buckets, component_name,
- depth, sizes, True)
- self.accumulate_size_for_expand(
- self.malloc_stacktrace_lines, policy_list, buckets, component_name,
- depth, sizes, False)
-
- sorted_sizes_list = sorted(
- sizes.iteritems(), key=(lambda x: x[1]), reverse=True)
- total = 0
- for size_pair in sorted_sizes_list:
- sys.stdout.write('%10d %s\n' % (size_pair[1], size_pair[0]))
- total += size_pair[1]
- sys.stderr.write('total: %d\n' % (total))
-
-
-def update_symbols(symbol_path, mapping_lines, chrome_path):
- """Updates address/symbol mapping on memory and in a .symbol cache file.
-
- It reads cached address/symbol mapping from a .symbol file if it exists.
- Then, it resolves unresolved addresses from a Chrome binary with pprof.
- Both mappings on memory and in a .symbol cache file are updated.
-
- Symbol files are formatted as follows:
- <Address> <Symbol>
- <Address> <Symbol>
- <Address> <Symbol>
- ...
-
- Args:
- symbol_path: A string representing a path for a .symbol file.
- mapping_lines: A list of strings containing /proc/.../maps.
- chrome_path: A string representing a path for a Chrome binary.
- """
- with open(symbol_path, mode='a+') as symbol_f:
- symbol_lines = symbol_f.readlines()
- if symbol_lines:
- for line in symbol_lines:
- items = line.split(None, 1)
- address_symbol_dict[items[0]] = items[1].rstrip()
-
- unresolved_addresses = sorted(
- a for a in appeared_addresses if a not in address_symbol_dict)
-
- if unresolved_addresses:
- with tempfile.NamedTemporaryFile(
- suffix='maps', prefix="dmprof", mode='w+') as pprof_in:
- with tempfile.NamedTemporaryFile(
- suffix='symbols', prefix="dmprof", mode='w+') as pprof_out:
- for line in mapping_lines:
- pprof_in.write(line)
-
- for address in unresolved_addresses:
- pprof_in.write(address + '\n')
-
- pprof_in.seek(0)
-
- p = subprocess.Popen(
- '%s --symbols %s' % (PPROF_PATH, chrome_path),
- shell=True, stdin=pprof_in, stdout=pprof_out)
- p.wait()
-
- pprof_out.seek(0)
- symbols = pprof_out.readlines()
- symbol_f.seek(0, 2)
- for address, symbol in zip(unresolved_addresses, symbols):
- stripped_symbol = symbol.strip()
- address_symbol_dict[address] = stripped_symbol
- symbol_f.write('%s %s\n' % (address, symbol.strip()))
-
-
-def parse_policy(policy_path):
- """Parses policy file.
-
- A policy file contains component's names and their
- stacktrace pattern written in regular expression.
- Those patterns are matched against each symbols of
- each stacktraces in the order written in the policy file
-
- Args:
- policy_path: A path for a policy file.
- Returns:
- A list containing component's name and its regex object
- """
- with open(policy_path, mode='r') as policy_f:
- policy_lines = policy_f.readlines()
-
- policy_version = POLICY_DEEP_1
- if policy_lines[0].startswith('heap profile policy: '):
- policy_version = policy_lines[0][21:].strip()
- policy_lines.pop(0)
- policy_list = []
-
- if policy_version == POLICY_DEEP_2 or policy_version == POLICY_DEEP_1:
- sys.stderr.write(' heap profile policy version: %s\n' % policy_version)
- for line in policy_lines:
- if line[0] == '#':
- continue
-
- if policy_version == POLICY_DEEP_2:
- (name, allocation_type, pattern) = line.strip().split(None, 2)
- mmap = False
- if allocation_type == 'mmap':
- mmap = True
- elif policy_version == POLICY_DEEP_1:
- name = line.split()[0]
- pattern = line[len(name) : len(line)].strip()
- mmap = False
-
- if pattern != 'default':
- policy_list.append(Policy(name, mmap, pattern))
- if components.count(name) == 0:
- components.append(name)
-
- else:
- sys.stderr.write(' invalid heap profile policy version: %s\n' % (
- policy_version))
-
- return policy_list
-
-
-def main():
- if (len(sys.argv) < 4) or (not (sys.argv[1] in ['--csv',
- '--json',
- '--expand',
- '--list',
- '--stacktrace',
- '--pprof'])):
- sys.stderr.write("""Usage:
-%s [options] <chrome-binary> <policy> <profile> [component-name] [depth]
-
-Options:
- --csv Output result in csv format
- --json Output result in json format
- --stacktrace Convert raw address to symbol names
- --list Lists components and their sizes
- --expand Show all stacktraces in the specified component
- of given depth with their sizes
- --pprof Format the profile file so it can be processed
- by pprof
-
-Examples:
- dmprof --csv Debug/chrome dmpolicy hprof.12345.0001.heap > result.csv
- dmprof --json Debug/chrome dmpolicy hprof.12345.0001.heap > result.json
- dmprof --list Debug/chrome dmpolicy hprof.12345.0012.heap
- dmprof --expand Debug/chrome dmpolicy hprof.12345.0012.heap tc-webkit 4
- dmprof --pprof Debug/chrome dmpolicy hprof.12345.0012.heap > for_pprof.txt
-""" % (sys.argv[0]))
- sys.exit(1)
-
- action = sys.argv[1]
- chrome_path = sys.argv[2]
- policy_path = sys.argv[3]
- log_path = sys.argv[4]
-
- sys.stderr.write('parsing a policy file\n')
- policy_list = parse_policy(policy_path)
-
- p = re.compile('\.[0-9][0-9][0-9][0-9]\.heap')
- prefix = p.sub('', log_path)
- symbol_path = prefix + '.symbols'
-
- sys.stderr.write('parsing the maps file\n')
- maps_path = prefix + '.maps'
- with open(maps_path, 'r') as maps_f:
- maps_lines = maps_f.readlines()
-
- # Reading buckets
- sys.stderr.write('parsing the bucket file\n')
- buckets = {}
- bucket_count = 0
- n = 0
- while True:
- buckets_path = '%s.%04d.buckets' % (prefix, n)
- if not os.path.exists(buckets_path):
- if n > 10:
- break
- n += 1
- continue
- sys.stderr.write('reading buckets from %s\n' % (buckets_path))
- with open(buckets_path, 'r') as buckets_f:
- for l in buckets_f:
- words = l.split()
- buckets[int(words[0])] = Bucket(words[1:])
- n += 1
-
- sys.stderr.write('the number buckets: %d\n' % (bucket_count))
-
- log_path_list = [log_path]
-
- if action in ('--csv', '--json'):
- # search for the sequence of files
- n = int(log_path[len(log_path) - 9 : len(log_path) - 5])
- n += 1 # skip current file
- while True:
- p = '%s.%04d.heap' % (prefix, n)
- if os.path.exists(p):
- log_path_list.append(p)
- else:
- break
- n += 1
-
- logs = [Log(path, buckets) for path in log_path_list]
-
- sys.stderr.write('getting symbols\n')
- update_symbols(symbol_path, maps_lines, chrome_path)
-
- # TODO(dmikurube): Many modes now. Split them into separete functions.
- if action == '--stacktrace':
- logs[0].dump_stacktrace(buckets)
-
- elif action == '--csv':
- sys.stdout.write(','.join(components))
- sys.stdout.write('\n')
-
- for log in logs:
- component_sizes = log.apply_policy(policy_list, buckets, logs[0].log_time)
- s = []
- for c in components:
- if c in ('hour', 'minute', 'second'):
- s.append('%05.5f' % (component_sizes[c]))
- else:
- s.append('%05.5f' % (component_sizes[c] / 1024.0 / 1024.0))
- sys.stdout.write(','.join(s))
- sys.stdout.write('\n')
-
- elif action == '--json':
- json_base = {
- 'version': 'JSON_DEEP_1',
- 'legends': components,
- 'snapshots': [],
- }
- for log in logs:
- component_sizes = log.apply_policy(policy_list, buckets, logs[0].log_time)
- component_sizes['log_path'] = log.log_path
- component_sizes['log_time'] = datetime.fromtimestamp(
- log.log_time).strftime('%Y-%m-%d %H:%M:%S')
- json_base['snapshots'].append(component_sizes)
- json.dump(json_base, sys.stdout, indent=2, sort_keys=True)
-
- elif action == '--list':
- component_sizes = logs[0].apply_policy(
- policy_list, buckets, logs[0].log_time)
- for c in components:
- if c in ['hour', 'minute', 'second']:
- sys.stdout.write('%30s %10.3f\n' % (c, component_sizes[c]))
- else:
- sys.stdout.write('%30s %10.3f\n' % (
- c, component_sizes[c] / 1024.0 / 1024.0))
-
- elif action == '--expand':
- component_name = sys.argv[5]
- depth = sys.argv[6]
- logs[0].expand(policy_list, buckets, component_name, int(depth))
-
- elif action == '--pprof':
- if len(sys.argv) > 5:
- logs[0].dump_for_pprof(policy_list, buckets, maps_lines, sys.argv[5])
- else:
- logs[0].dump_for_pprof(policy_list, buckets, maps_lines, None)
-
-
-if __name__ == '__main__':
- sys.exit(main())
« no previous file with comments | « tools/deep_memory_profiler/dmprof ('k') | tools/deep_memory_profiler/policy.l0.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698