Chromium Code Reviews| Index: tools/deep_memory_profiler/dmprof.py |
| diff --git a/tools/deep_memory_profiler/dmprof b/tools/deep_memory_profiler/dmprof.py |
| old mode 100755 |
| new mode 100644 |
| similarity index 94% |
| copy from tools/deep_memory_profiler/dmprof |
| copy to tools/deep_memory_profiler/dmprof.py |
| index 1951838c4f75571e8c5f5bb967f9f83c23bc2ed6..7c14b80a3b71b8e25e5b47cf199c61cdb20a77ff |
| --- a/tools/deep_memory_profiler/dmprof |
| +++ b/tools/deep_memory_profiler/dmprof.py |
| @@ -1,4 +1,3 @@ |
| -#!/usr/bin/env python |
|
M-A Ruel
2012/11/17 23:23:10
Why are you removing the shebang and removing the
Dai Mikurube (NOT FULLTIME)
2012/11/18 06:01:54
It's because now dmprof can be executed by the she
|
| # 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. |
| @@ -11,10 +10,7 @@ import logging |
| import optparse |
| import os |
| import re |
| -import shutil |
| -import subprocess |
| import sys |
| -import tempfile |
| BASE_PATH = os.path.dirname(os.path.abspath(__file__)) |
| FIND_RUNTIME_SYMBOLS_PATH = os.path.join( |
| @@ -79,6 +75,7 @@ POLICY_DEEP_4 = 'POLICY_DEEP_4' |
| class EmptyDumpException(Exception): |
| def __init__(self, value): |
| + super(EmptyDumpException, self).__init__() |
| self.value = value |
| def __str__(self): |
| return repr(self.value) |
| @@ -86,6 +83,7 @@ class EmptyDumpException(Exception): |
| class ParsingException(Exception): |
| def __init__(self, value): |
| + super(ParsingException, self).__init__() |
| self.value = value |
| def __str__(self): |
| return repr(self.value) |
| @@ -93,6 +91,7 @@ class ParsingException(Exception): |
| class InvalidDumpException(ParsingException): |
| def __init__(self, value): |
| + super(InvalidDumpException, self).__init__() |
| self.value = value |
| def __str__(self): |
| return "invalid heap profile dump: %s" % repr(self.value) |
| @@ -100,6 +99,7 @@ class InvalidDumpException(ParsingException): |
| class ObsoleteDumpVersionException(ParsingException): |
| def __init__(self, value): |
| + super(ObsoleteDumpVersionException, self).__init__() |
| self.value = value |
| def __str__(self): |
| return "obsolete heap profile dump version: %s" % repr(self.value) |
| @@ -268,7 +268,7 @@ class SymbolCache(object): |
| LOGGER.info('Loaded %d entries from symbol cache.' % |
| len(self._symbol_caches[address_type])) |
| except IOError as e: |
| - LOGGER.info('No valid symbol cache file is found.') |
| + LOGGER.info('No valid symbol cache file is found: %s' % e) |
| class Rule(object): |
| @@ -349,33 +349,33 @@ class Policy(object): |
| assert False |
| @staticmethod |
| - def load(filename, format): |
| + def load(filename, filetype): |
| """Loads a policy file of |filename| in a |format|. |
| Args: |
| filename: A filename to be loaded. |
| - format: A string to specify a format of the file. Only 'json' is |
| + filetype: A string to specify a type of the file. Only 'json' is |
| supported for now. |
| Returns: |
| A loaded Policy object. |
| """ |
| with open(os.path.join(BASE_PATH, filename)) as policy_f: |
| - return Policy.parse(policy_f, format) |
| + return Policy.parse(policy_f, filetype) |
| @staticmethod |
| - def parse(policy_f, format): |
| + def parse(policy_f, filetype): |
| """Parses a policy file content in a |format|. |
| Args: |
| policy_f: An IO object to be loaded. |
| - format: A string to specify a format of the file. Only 'json' is |
| + filetype: A string to specify a type of the file. Only 'json' is |
| supported for now. |
| Returns: |
| A loaded Policy object. |
| """ |
| - if format == 'json': |
| + if filetype == 'json': |
| return Policy._parse_json(policy_f) |
| else: |
| return None |
| @@ -543,18 +543,13 @@ class BucketSet(object): |
| TYPEINFO_ADDRESS: set(), |
| } |
| - @staticmethod |
| - def load(prefix): |
| + def load(self, prefix): |
| """Loads all related bucket files. |
| Args: |
| prefix: A prefix string for bucket file names. |
| - |
| - Returns: |
| - A loaded BucketSet object. |
| """ |
| LOGGER.info('Loading bucket files.') |
| - bucket_set = BucketSet() |
| n = 0 |
| while True: |
| @@ -566,11 +561,9 @@ class BucketSet(object): |
| continue |
| LOGGER.info(' %s' % path) |
| with open(path, 'r') as f: |
| - bucket_set._load_file(f) |
| + self._load_file(f) |
| n += 1 |
| - return bucket_set |
| - |
| def _load_file(self, bucket_f): |
| for line in bucket_f: |
| words = line.split() |
| @@ -620,9 +613,9 @@ class BucketSet(object): |
| class Dump(object): |
| """Represents a heap profile dump.""" |
| - def __init__(self): |
| - self._path = '' |
| - self._time = None |
| + def __init__(self, path, time): |
| + self._path = path |
| + self._time = time |
| self._stacktrace_lines = [] |
| self._global_stats = {} # used only in apply_policy |
| @@ -659,27 +652,26 @@ class Dump(object): |
| Raises: |
| ParsingException for invalid heap profile dumps. |
| """ |
| - dump = Dump() |
| - dump._path = path |
| - dump._time = os.stat(dump._path).st_mtime |
| - dump._version = '' |
| + dump = Dump(path, os.stat(path).st_mtime) |
| + with open(path, 'r') as f: |
| + dump.load_file(f, log_header) |
| + return dump |
| - dump._lines = [line for line in open(dump._path, 'r') |
| + def load_file(self, f, log_header): |
| + self._lines = [line for line in f |
| if line and not line.startswith('#')] |
| try: |
| - dump._version, ln = dump._parse_version() |
| - dump._parse_global_stats() |
| - dump._extract_stacktrace_lines(ln) |
| + self._version, ln = self._parse_version() |
| + self._parse_global_stats() |
| + self._extract_stacktrace_lines(ln) |
| except EmptyDumpException: |
| - LOGGER.info('%s%s ...ignored an empty dump.' % (log_header, path)) |
| + LOGGER.info('%s%s ...ignored an empty dump.' % (log_header, self._path)) |
| except ParsingException, e: |
| - LOGGER.error('%s%s ...error %s' % (log_header, path, e)) |
| + LOGGER.error('%s%s ...error %s' % (log_header, self._path, e)) |
| raise |
| else: |
| - LOGGER.info('%s%s (version: %s)' % (log_header, path, dump._version)) |
| - |
| - return dump |
| + LOGGER.info('%s%s (version:%s)' % (log_header, self._path, self._version)) |
| def _parse_version(self): |
| """Parses a version string in self._lines. |
| @@ -825,7 +817,8 @@ class Command(object): |
| prefix = Command._find_prefix(dump_path) |
| symbol_mapping = SymbolMapping(prefix) |
| symbol_mapping.prepare() |
| - bucket_set = BucketSet.load(prefix) |
| + bucket_set = BucketSet() |
| + bucket_set.load(prefix) |
| if multiple: |
| dump_list = DumpList.load(Command._find_all_dumps(dump_path)) |
| else: |
| @@ -867,7 +860,8 @@ class Command(object): |
| return None |
| return (options, args) |
| - def _parse_policy_list(self, options_policy): |
| + @staticmethod |
| + def _parse_policy_list(options_policy): |
| if options_policy: |
| return options_policy.split(',') |
| else: |
| @@ -880,7 +874,7 @@ class StacktraceCommand(Command): |
| 'Usage: %prog stacktrace <dump>') |
| def do(self, sys_argv): |
| - options, args = self._parse_args(sys_argv, 1) |
| + _, args = self._parse_args(sys_argv, 1) |
| dump_path = args[1] |
| (bucket_set, dump) = Command.load_basic_files(dump_path, False) |
| @@ -919,10 +913,11 @@ class PolicyCommands(Command): |
| dump_path = args[1] |
| (bucket_set, dumps) = Command.load_basic_files(dump_path, True) |
| - policy_set = PolicySet.load(self._parse_policy_list(options.policy)) |
| + policy_set = PolicySet.load(Command._parse_policy_list(options.policy)) |
| return policy_set, dumps, bucket_set |
| - def _apply_policy(self, dump, policy, bucket_set, first_dump_time): |
| + @staticmethod |
| + def _apply_policy(dump, policy, bucket_set, first_dump_time): |
| """Aggregates the total memory size of each component. |
| Iterate through all stacktraces and attribute them to one of the components |
| @@ -1026,9 +1021,10 @@ class CSVCommand(PolicyCommands): |
| def do(self, sys_argv): |
| policy_set, dumps, bucket_set = self._set_up(sys_argv) |
| - return self._output(policy_set, dumps, bucket_set, sys.stdout) |
| + return CSVCommand._output(policy_set, dumps, bucket_set, sys.stdout) |
| - def _output(self, policy_set, dumps, bucket_set, out): |
| + @staticmethod |
| + def _output(policy_set, dumps, bucket_set, out): |
| max_components = 0 |
| for label in policy_set: |
| max_components = max(max_components, len(policy_set[label].components)) |
| @@ -1042,7 +1038,7 @@ class CSVCommand(PolicyCommands): |
| LOGGER.info('Applying a policy %s to...' % label) |
| for dump in dumps: |
| - component_sizes = self._apply_policy( |
| + component_sizes = PolicyCommands._apply_policy( |
| dump, policy_set[label], bucket_set, dumps[0].time) |
| s = [] |
| for c in components: |
| @@ -1064,9 +1060,10 @@ class JSONCommand(PolicyCommands): |
| def do(self, sys_argv): |
| policy_set, dumps, bucket_set = self._set_up(sys_argv) |
| - return self._output(policy_set, dumps, bucket_set, sys.stdout) |
| + return JSONCommand._output(policy_set, dumps, bucket_set, sys.stdout) |
| - def _output(self, policy_set, dumps, bucket_set, out): |
| + @staticmethod |
| + def _output(policy_set, dumps, bucket_set, out): |
| json_base = { |
| 'version': 'JSON_DEEP_2', |
| 'policies': {}, |
| @@ -1080,7 +1077,7 @@ class JSONCommand(PolicyCommands): |
| LOGGER.info('Applying a policy %s to...' % label) |
| for dump in dumps: |
| - component_sizes = self._apply_policy( |
| + component_sizes = PolicyCommands._apply_policy( |
| dump, policy_set[label], bucket_set, dumps[0].time) |
| component_sizes['dump_path'] = dump.path |
| component_sizes['dump_time'] = datetime.fromtimestamp( |
| @@ -1100,13 +1097,14 @@ class ListCommand(PolicyCommands): |
| def do(self, sys_argv): |
| policy_set, dumps, bucket_set = self._set_up(sys_argv) |
| - return self._output(policy_set, dumps, bucket_set, sys.stdout) |
| + return ListCommand._output(policy_set, dumps, bucket_set, sys.stdout) |
| - def _output(self, policy_set, dumps, bucket_set, out): |
| + @staticmethod |
| + def _output(policy_set, dumps, bucket_set, out): |
| for label in sorted(policy_set): |
| LOGGER.info('Applying a policy %s to...' % label) |
| for dump in dumps: |
| - component_sizes = self._apply_policy( |
| + component_sizes = PolicyCommands._apply_policy( |
| dump, policy_set[label], bucket_set, dump.time) |
| out.write('%s for %s:\n' % (label, dump.path)) |
| for c in policy_set[label].components: |
| @@ -1126,19 +1124,20 @@ class ExpandCommand(Command): |
| 'Usage: %prog expand <dump> <policy> <component> <depth>') |
| def do(self, sys_argv): |
| - options, args = self._parse_args(sys_argv, 4) |
| + _, args = self._parse_args(sys_argv, 4) |
| dump_path = args[1] |
| target_policy = args[2] |
| component_name = args[3] |
| depth = args[4] |
| (bucket_set, dump) = Command.load_basic_files(dump_path, False) |
| - policy_set = PolicySet.load(self._parse_policy_list(target_policy)) |
| + policy_set = PolicySet.load(Command._parse_policy_list(target_policy)) |
| - self._output(dump, policy_set[target_policy], bucket_set, |
| - component_name, int(depth), sys.stdout) |
| + ExpandCommand._output(dump, policy_set[target_policy], bucket_set, |
| + component_name, int(depth), sys.stdout) |
| return 0 |
| - def _output(self, dump, policy, bucket_set, component_name, depth, out): |
| + @staticmethod |
| + def _output(dump, policy, bucket_set, component_name, depth, out): |
| """Prints all stacktraces in a given component of given depth. |
| Args: |
| @@ -1197,7 +1196,7 @@ class PProfCommand(Command): |
| component = options.component |
| (bucket_set, dump) = Command.load_basic_files(dump_path, False) |
| - policy_set = PolicySet.load(self._parse_policy_list(target_policy)) |
| + policy_set = PolicySet.load(Command._parse_policy_list(target_policy)) |
| with open(Command._find_prefix(dump_path) + '.maps', 'r') as maps_f: |
| maps_lines = maps_f.readlines() |
| @@ -1300,7 +1299,7 @@ def main(): |
| } |
| if len(sys.argv) < 2 or (not sys.argv[1] in COMMANDS): |
| - sys.stderr.write("""Usage: %s <command> [options] [<args>] |
| + sys.stderr.write("""Usage: dmprof <command> [options] [<args>] |
| Commands: |
| csv Classify memory usage in CSV |
| @@ -1317,7 +1316,7 @@ Quick Reference: |
| dmprof list [-p POLICY] <first-dump> |
| dmprof pprof [-c COMPONENT] <dump> <policy> |
| dmprof stacktrace <dump> |
| -""" % (sys.argv[0])) |
| +""") |
| sys.exit(1) |
| action = sys.argv.pop(1) |