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 |