| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """The deep heap profiler script for Chrome.""" | 6 """The deep heap profiler script for Chrome.""" |
| 7 | 7 |
| 8 from datetime import datetime | 8 from datetime import datetime |
| 9 import json | 9 import json |
| 10 import optparse | 10 import optparse |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 # Heap Profile Policy versions | 71 # Heap Profile Policy versions |
| 72 | 72 |
| 73 # POLICY_DEEP_1 DOES NOT include allocation_type columns. | 73 # POLICY_DEEP_1 DOES NOT include allocation_type columns. |
| 74 # mmap regions are distincted w/ mmap frames in the pattern column. | 74 # mmap regions are distincted w/ mmap frames in the pattern column. |
| 75 POLICY_DEEP_1 = 'POLICY_DEEP_1' | 75 POLICY_DEEP_1 = 'POLICY_DEEP_1' |
| 76 | 76 |
| 77 # POLICY_DEEP_2 DOES include allocation_type columns. | 77 # POLICY_DEEP_2 DOES include allocation_type columns. |
| 78 # mmap regions are distincted w/ the allocation_type column. | 78 # mmap regions are distincted w/ the allocation_type column. |
| 79 POLICY_DEEP_2 = 'POLICY_DEEP_2' | 79 POLICY_DEEP_2 = 'POLICY_DEEP_2' |
| 80 | 80 |
| 81 # POLICY_DEEP_3 is in JSON format. |
| 82 POLICY_DEEP_3 = 'POLICY_DEEP_3' |
| 83 |
| 81 | 84 |
| 82 class EmptyDumpException(Exception): | 85 class EmptyDumpException(Exception): |
| 83 def __init__(self, value): | 86 def __init__(self, value): |
| 84 self.value = value | 87 self.value = value |
| 85 def __str__(self): | 88 def __str__(self): |
| 86 return repr(self.value) | 89 return repr(self.value) |
| 87 | 90 |
| 88 | 91 |
| 89 class ParsingException(Exception): | 92 class ParsingException(Exception): |
| 90 def __init__(self, value): | 93 def __init__(self, value): |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 self.loaded_static_symbols = StaticSymbols.load(self.prepared_data_dir) | 129 self.loaded_static_symbols = StaticSymbols.load(self.prepared_data_dir) |
| 127 finally: | 130 finally: |
| 128 if not self.keep: | 131 if not self.keep: |
| 129 shutil.rmtree(self.prepared_data_dir) | 132 shutil.rmtree(self.prepared_data_dir) |
| 130 return self.loaded_static_symbols | 133 return self.loaded_static_symbols |
| 131 | 134 |
| 132 | 135 |
| 133 class Rule(object): | 136 class Rule(object): |
| 134 """Represents one matching rule in a policy file.""" | 137 """Represents one matching rule in a policy file.""" |
| 135 | 138 |
| 136 def __init__(self, name, mmap, pattern): | 139 def __init__(self, name, mmap, stacktrace_pattern): |
| 137 self.name = name | 140 self.name = name |
| 138 self.mmap = mmap | 141 self.mmap = mmap |
| 139 self.condition = re.compile(pattern + r'\Z') | 142 self.stacktrace_pattern = re.compile(stacktrace_pattern + r'\Z') |
| 140 | 143 |
| 141 | 144 |
| 142 class Policy(object): | 145 class Policy(object): |
| 143 """Represents a policy, a content of a policy file.""" | 146 """Represents a policy, a content of a policy file.""" |
| 144 | 147 |
| 145 def __init__(self, rules, version, components): | 148 def __init__(self, rules, version, components): |
| 146 self.rules = rules | 149 self.rules = rules |
| 147 self.version = version | 150 self.version = version |
| 148 self.components = components | 151 self.components = components |
| 149 | 152 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 163 A string representing a component name. | 166 A string representing a component name. |
| 164 """ | 167 """ |
| 165 if not bucket: | 168 if not bucket: |
| 166 return 'no-bucket' | 169 return 'no-bucket' |
| 167 if bucket.component_cache: | 170 if bucket.component_cache: |
| 168 return bucket.component_cache | 171 return bucket.component_cache |
| 169 | 172 |
| 170 stacktrace = ''.join(symbols[a] + ' ' for a in bucket.stacktrace).strip() | 173 stacktrace = ''.join(symbols[a] + ' ' for a in bucket.stacktrace).strip() |
| 171 | 174 |
| 172 for rule in rule_list: | 175 for rule in rule_list: |
| 173 if bucket.mmap == rule.mmap and rule.condition.match(stacktrace): | 176 if bucket.mmap == rule.mmap and rule.stacktrace_pattern.match(stacktrace): |
| 174 bucket.component_cache = rule.name | 177 bucket.component_cache = rule.name |
| 175 return rule.name | 178 return rule.name |
| 176 | 179 |
| 177 assert False | 180 assert False |
| 178 | 181 |
| 179 | 182 |
| 180 class Bucket(object): | 183 class Bucket(object): |
| 181 """Represents a bucket, which is a unit of memory classification.""" | 184 """Represents a bucket, which is a unit of memory classification.""" |
| 182 | 185 |
| 183 def __init__(self, stacktrace, mmap): | 186 def __init__(self, stacktrace, mmap): |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 for address, symbol in zip(unresolved_addresses, symbol_list): | 649 for address, symbol in zip(unresolved_addresses, symbol_list): |
| 647 if not symbol: | 650 if not symbol: |
| 648 symbol = '??' | 651 symbol = '??' |
| 649 stripped_symbol = symbol.strip() | 652 stripped_symbol = symbol.strip() |
| 650 symbols[address] = stripped_symbol | 653 symbols[address] = stripped_symbol |
| 651 symbol_f.write('%x %s\n' % (address, stripped_symbol)) | 654 symbol_f.write('%x %s\n' % (address, stripped_symbol)) |
| 652 | 655 |
| 653 sys.stderr.write(' All symbols resolved.\n') | 656 sys.stderr.write(' All symbols resolved.\n') |
| 654 | 657 |
| 655 | 658 |
| 656 def parse_policy(policy_path): | 659 def parse_policy_text(policy_path): |
| 657 """Parses policy file. | 660 """Parses policy file in text format. |
| 658 | 661 |
| 659 A policy file contains component's names and their | 662 A policy file contains component's names and their |
| 660 stacktrace pattern written in regular expression. | 663 stacktrace pattern written in regular expression. |
| 661 Those patterns are matched against each symbols of | 664 Those patterns are matched against each symbols of |
| 662 each stacktraces in the order written in the policy file | 665 each stacktraces in the order written in the policy file |
| 663 | 666 |
| 667 TODO(dmikurube): Deprecate this function after a while. |
| 668 |
| 664 Args: | 669 Args: |
| 665 policy_path: A path for a policy file. | 670 policy_path: A path for a policy file. |
| 666 Returns: | 671 Returns: |
| 667 A list containing component's name and its regex object | 672 A loaded policy object. |
| 668 """ | 673 """ |
| 669 with open(policy_path, mode='r') as policy_f: | 674 with open(policy_path, mode='r') as policy_f: |
| 670 policy_lines = policy_f.readlines() | 675 policy_lines = policy_f.readlines() |
| 671 | 676 |
| 672 policy_version = POLICY_DEEP_1 | 677 policy_version = POLICY_DEEP_1 |
| 673 if policy_lines[0].startswith('heap profile policy: '): | 678 if policy_lines[0].startswith('heap profile policy: '): |
| 674 policy_version = policy_lines[0][21:].strip() | 679 policy_version = policy_lines[0][21:].strip() |
| 675 policy_lines.pop(0) | 680 policy_lines.pop(0) |
| 676 rule_list = [] | 681 rule_list = [] |
| 677 components = [] | 682 components = [] |
| (...skipping 15 matching lines...) Expand all Loading... |
| 693 | 698 |
| 694 if pattern != 'default': | 699 if pattern != 'default': |
| 695 rule_list.append(Rule(name, mmap, pattern)) | 700 rule_list.append(Rule(name, mmap, pattern)) |
| 696 if components.count(name) == 0: | 701 if components.count(name) == 0: |
| 697 components.append(name) | 702 components.append(name) |
| 698 | 703 |
| 699 else: | 704 else: |
| 700 sys.stderr.write(' invalid heap profile policy version: %s\n' % ( | 705 sys.stderr.write(' invalid heap profile policy version: %s\n' % ( |
| 701 policy_version)) | 706 policy_version)) |
| 702 | 707 |
| 703 return rule_list, policy_version, components | 708 return Policy(rule_list, policy_version, components) |
| 709 |
| 710 |
| 711 def parse_policy_json(policy_path): |
| 712 """Parses policy file in json format. |
| 713 |
| 714 A policy file contains component's names and their |
| 715 stacktrace pattern written in regular expression. |
| 716 Those patterns are matched against each symbols of |
| 717 each stacktraces in the order written in the policy file |
| 718 |
| 719 Args: |
| 720 policy_path: A path for a policy file. |
| 721 Returns: |
| 722 A loaded policy object. |
| 723 """ |
| 724 with open(policy_path, mode='r') as f: |
| 725 policy = json.load(f) |
| 726 |
| 727 rules = [] |
| 728 for rule in policy['rules']: |
| 729 rules.append(Rule( |
| 730 rule['name'], rule['allocator'] == 'mmap', rule['stacktrace'])) |
| 731 return Policy(rules, policy['version'], policy['components']) |
| 704 | 732 |
| 705 | 733 |
| 706 def find_prefix(path): | 734 def find_prefix(path): |
| 707 return re.sub('\.[0-9][0-9][0-9][0-9]\.heap', '', path) | 735 return re.sub('\.[0-9][0-9][0-9][0-9]\.heap', '', path) |
| 708 | 736 |
| 709 | 737 |
| 710 def load_buckets(prefix): | 738 def load_buckets(prefix): |
| 711 # Reading buckets | 739 # Reading buckets |
| 712 sys.stderr.write('Loading bucket files.\n') | 740 sys.stderr.write('Loading bucket files.\n') |
| 713 buckets = {} | 741 buckets = {} |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 | 821 |
| 794 | 822 |
| 795 def load_default_policies(): | 823 def load_default_policies(): |
| 796 with open(POLICIES_JSON_PATH, mode='r') as policies_f: | 824 with open(POLICIES_JSON_PATH, mode='r') as policies_f: |
| 797 default_policies = json.load(policies_f) | 825 default_policies = json.load(policies_f) |
| 798 return default_policies | 826 return default_policies |
| 799 | 827 |
| 800 | 828 |
| 801 def load_policy(policies_dict, policy_label): | 829 def load_policy(policies_dict, policy_label): |
| 802 policy_file = policies_dict[policy_label]['file'] | 830 policy_file = policies_dict[policy_label]['file'] |
| 831 policy_format = policies_dict[policy_label]['format'] |
| 803 policy_path = os.path.join(os.path.dirname(__file__), policy_file) | 832 policy_path = os.path.join(os.path.dirname(__file__), policy_file) |
| 804 rule_list, policy_version, components = parse_policy(policy_path) | 833 policy = None |
| 834 if policy_format == 'json': |
| 835 policy = parse_policy_json(policy_path) |
| 836 elif policy_format == 'text': |
| 837 policy = parse_policy_text(policy_path) |
| 838 else: |
| 839 return None |
| 805 sys.stderr.write(' %s: %s (version: %s)\n' % | 840 sys.stderr.write(' %s: %s (version: %s)\n' % |
| 806 (policy_label, policy_path, policy_version)) | 841 (policy_label, policy_path, policy.version)) |
| 807 return Policy(rule_list, policy_version, components) | 842 return policy |
| 808 | 843 |
| 809 | 844 |
| 810 def load_policies_dict(policies_dict): | 845 def load_policies_dict(policies_dict): |
| 811 sys.stderr.write('Loading policy files.\n') | 846 sys.stderr.write('Loading policy files.\n') |
| 812 policies = {} | 847 policies = {} |
| 813 for policy_label in policies_dict: | 848 for policy_label in policies_dict: |
| 814 policies[policy_label] = load_policy(policies_dict, policy_label) | 849 loaded_policy = load_policy(policies_dict, policy_label) |
| 850 if loaded_policy: |
| 851 policies[policy_label] = loaded_policy |
| 815 return policies | 852 return policies |
| 816 | 853 |
| 817 | 854 |
| 818 def load_policies(options_policy): | 855 def load_policies(options_policy): |
| 819 default_policies = load_default_policies() | 856 default_policies = load_default_policies() |
| 820 if options_policy: | 857 if options_policy: |
| 821 policy_labels = options_policy.split(',') | 858 policy_labels = options_policy.split(',') |
| 822 specified_policies = {} | 859 specified_policies = {} |
| 823 for specified_policy in policy_labels: | 860 for specified_policy in policy_labels: |
| 824 if specified_policy in default_policies: | 861 if specified_policy in default_policies: |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 dmprof stacktrace [--keep] <dump> | 1138 dmprof stacktrace [--keep] <dump> |
| 1102 """ % (sys.argv[0])) | 1139 """ % (sys.argv[0])) |
| 1103 sys.exit(1) | 1140 sys.exit(1) |
| 1104 action = sys.argv.pop(1) | 1141 action = sys.argv.pop(1) |
| 1105 | 1142 |
| 1106 return COMMANDS[action](sys.argv) | 1143 return COMMANDS[action](sys.argv) |
| 1107 | 1144 |
| 1108 | 1145 |
| 1109 if __name__ == '__main__': | 1146 if __name__ == '__main__': |
| 1110 sys.exit(main()) | 1147 sys.exit(main()) |
| OLD | NEW |