Chromium Code Reviews| 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 |
| 11 import os | 11 import os |
| 12 import re | 12 import re |
| 13 import shutil | 13 import shutil |
| 14 import subprocess | 14 import subprocess |
| 15 import sys | 15 import sys |
| 16 import tempfile | 16 import tempfile |
| 17 | 17 |
| 18 FIND_RUNTIME_SYMBOLS_PATH = os.path.join( | 18 FIND_RUNTIME_SYMBOLS_PATH = os.path.join( |
| 19 os.path.dirname(os.path.abspath(__file__)), | 19 os.path.dirname(os.path.abspath(__file__)), |
| 20 os.pardir, | 20 os.pardir, |
| 21 'find_runtime_symbols') | 21 'find_runtime_symbols') |
| 22 sys.path.append(FIND_RUNTIME_SYMBOLS_PATH) | 22 sys.path.append(FIND_RUNTIME_SYMBOLS_PATH) |
| 23 | 23 |
| 24 from find_runtime_symbols import find_runtime_symbols_list | 24 from find_runtime_symbols import find_runtime_symbols_list |
| 25 from find_runtime_symbols import find_runtime_typeinfo_symbols_list | |
| 26 from find_runtime_symbols import RuntimeSymbolsInProcess | |
| 25 from prepare_symbol_info import prepare_symbol_info | 27 from prepare_symbol_info import prepare_symbol_info |
| 26 from static_symbols import StaticSymbols | |
| 27 | 28 |
| 28 BUCKET_ID = 5 | 29 BUCKET_ID = 5 |
| 29 VIRTUAL = 0 | 30 VIRTUAL = 0 |
| 30 COMMITTED = 1 | 31 COMMITTED = 1 |
| 31 ALLOC_COUNT = 2 | 32 ALLOC_COUNT = 2 |
| 32 FREE_COUNT = 3 | 33 FREE_COUNT = 3 |
| 33 NULL_REGEX = re.compile('') | 34 NULL_REGEX = re.compile('') |
| 34 | 35 |
| 35 POLICIES_JSON_PATH = os.path.join( | 36 POLICIES_JSON_PATH = os.path.join( |
| 36 os.path.dirname(os.path.abspath(__file__)), | 37 os.path.dirname(os.path.abspath(__file__)), |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 # mmap regions are distincted w/ mmap frames in the pattern column. | 75 # mmap regions are distincted w/ mmap frames in the pattern column. |
| 75 POLICY_DEEP_1 = 'POLICY_DEEP_1' | 76 POLICY_DEEP_1 = 'POLICY_DEEP_1' |
| 76 | 77 |
| 77 # POLICY_DEEP_2 DOES include allocation_type columns. | 78 # POLICY_DEEP_2 DOES include allocation_type columns. |
| 78 # mmap regions are distincted w/ the allocation_type column. | 79 # mmap regions are distincted w/ the allocation_type column. |
| 79 POLICY_DEEP_2 = 'POLICY_DEEP_2' | 80 POLICY_DEEP_2 = 'POLICY_DEEP_2' |
| 80 | 81 |
| 81 # POLICY_DEEP_3 is in JSON format. | 82 # POLICY_DEEP_3 is in JSON format. |
| 82 POLICY_DEEP_3 = 'POLICY_DEEP_3' | 83 POLICY_DEEP_3 = 'POLICY_DEEP_3' |
| 83 | 84 |
| 85 # POLICY_DEEP_3 contains typeinfo. | |
| 86 POLICY_DEEP_4 = 'POLICY_DEEP_4' | |
| 87 | |
| 84 | 88 |
| 85 class EmptyDumpException(Exception): | 89 class EmptyDumpException(Exception): |
| 86 def __init__(self, value): | 90 def __init__(self, value): |
| 87 self.value = value | 91 self.value = value |
| 88 def __str__(self): | 92 def __str__(self): |
| 89 return repr(self.value) | 93 return repr(self.value) |
| 90 | 94 |
| 91 | 95 |
| 92 class ParsingException(Exception): | 96 class ParsingException(Exception): |
| 93 def __init__(self, value): | 97 def __init__(self, value): |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 112 | 116 |
| 113 class DelayedStaticSymbols(object): | 117 class DelayedStaticSymbols(object): |
| 114 """Represents static symbol information loaded lazily.""" | 118 """Represents static symbol information loaded lazily.""" |
| 115 | 119 |
| 116 def __init__(self, prefix, keep=False): | 120 def __init__(self, prefix, keep=False): |
| 117 self.maps_path = prefix + '.maps' | 121 self.maps_path = prefix + '.maps' |
| 118 self.keep = keep | 122 self.keep = keep |
| 119 if keep: | 123 if keep: |
| 120 self.prepared_data_dir = prefix + '.pre' | 124 self.prepared_data_dir = prefix + '.pre' |
| 121 self.loaded_static_symbols = None | 125 self.loaded_static_symbols = None |
| 126 self.loaded_symbols_in_process = None | |
| 122 | 127 |
| 123 def get(self): | 128 def get(self): |
| 124 if not self.loaded_static_symbols: | 129 if not self.loaded_symbols_in_process: |
| 125 if not self.keep: | 130 if not self.keep: |
| 126 self.prepared_data_dir = tempfile.mkdtemp() | 131 self.prepared_data_dir = tempfile.mkdtemp() |
| 127 try: | 132 try: |
| 128 prepare_symbol_info(self.maps_path, self.prepared_data_dir) | 133 prepare_symbol_info(self.maps_path, self.prepared_data_dir) |
| 129 self.loaded_static_symbols = StaticSymbols.load(self.prepared_data_dir) | 134 self.loaded_symbols_in_process = RuntimeSymbolsInProcess.load( |
| 135 self.prepared_data_dir) | |
| 130 finally: | 136 finally: |
| 131 if not self.keep: | 137 if not self.keep: |
| 132 shutil.rmtree(self.prepared_data_dir) | 138 shutil.rmtree(self.prepared_data_dir) |
| 133 return self.loaded_static_symbols | 139 return self.loaded_symbols_in_process |
| 134 | 140 |
| 135 | 141 |
| 136 class Rule(object): | 142 class Rule(object): |
| 137 """Represents one matching rule in a policy file.""" | 143 """Represents one matching rule in a policy file.""" |
| 138 | 144 |
| 139 def __init__(self, name, mmap, stacktrace_pattern): | 145 def __init__(self, name, mmap, stacktrace_pattern, typeinfo_pattern=None): |
| 140 self.name = name | 146 self.name = name |
| 141 self.mmap = mmap | 147 self.mmap = mmap |
| 142 self.stacktrace_pattern = re.compile(stacktrace_pattern + r'\Z') | 148 self.stacktrace_pattern = re.compile(stacktrace_pattern + r'\Z') |
| 149 if typeinfo_pattern: | |
| 150 self.typeinfo_pattern = re.compile(typeinfo_pattern + r'\Z') | |
| 151 else: | |
| 152 self.typeinfo_pattern = None | |
| 143 | 153 |
| 144 | 154 |
| 145 class Policy(object): | 155 class Policy(object): |
| 146 """Represents a policy, a content of a policy file.""" | 156 """Represents a policy, a content of a policy file.""" |
| 147 | 157 |
| 148 def __init__(self, rules, version, components): | 158 def __init__(self, rules, version, components): |
| 149 self.rules = rules | 159 self.rules = rules |
| 150 self.version = version | 160 self.version = version |
| 151 self.components = components | 161 self.components = components |
| 152 | 162 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 164 | 174 |
| 165 Returns: | 175 Returns: |
| 166 A string representing a component name. | 176 A string representing a component name. |
| 167 """ | 177 """ |
| 168 if not bucket: | 178 if not bucket: |
| 169 return 'no-bucket' | 179 return 'no-bucket' |
| 170 if bucket.component_cache: | 180 if bucket.component_cache: |
| 171 return bucket.component_cache | 181 return bucket.component_cache |
| 172 | 182 |
| 173 stacktrace = ''.join(symbols[a] + ' ' for a in bucket.stacktrace).strip() | 183 stacktrace = ''.join(symbols[a] + ' ' for a in bucket.stacktrace).strip() |
| 184 typeinfo = bucket.typeinfo_symbol | |
| 185 if typeinfo.startswith('0x'): | |
| 186 typeinfo = bucket.typename | |
| 174 | 187 |
| 175 for rule in rule_list: | 188 for rule in rule_list: |
| 176 if bucket.mmap == rule.mmap and rule.stacktrace_pattern.match(stacktrace): | 189 if (bucket.mmap == rule.mmap and |
| 190 rule.stacktrace_pattern.match(stacktrace) and | |
| 191 (not rule.typeinfo_pattern or rule.typeinfo_pattern.match(typeinfo))): | |
| 177 bucket.component_cache = rule.name | 192 bucket.component_cache = rule.name |
| 178 return rule.name | 193 return rule.name |
| 179 | 194 |
| 180 assert False | 195 assert False |
| 181 | 196 |
| 182 | 197 |
| 183 class Bucket(object): | 198 class Bucket(object): |
| 184 """Represents a bucket, which is a unit of memory classification.""" | 199 """Represents a bucket, which is a unit of memory classification.""" |
| 185 | 200 |
| 186 def __init__(self, stacktrace, mmap): | 201 def __init__(self, stacktrace, mmap, typeinfo=0, typename=''): |
| 187 self.stacktrace = stacktrace | 202 self.stacktrace = stacktrace |
| 188 self.mmap = mmap | 203 self.mmap = mmap |
| 204 self.typeinfo = typeinfo | |
| 205 self.typeinfo_symbol = typename | |
| 206 self.typename = typename | |
| 189 self.component_cache = '' | 207 self.component_cache = '' |
| 190 | 208 |
| 191 def clear_component_cache(self): | 209 def clear_component_cache(self): |
| 192 self.component_cache = '' | 210 self.component_cache = '' |
| 193 | 211 |
| 194 | 212 |
| 195 class Dump(object): | 213 class Dump(object): |
| 196 """Represents one heap profile dump.""" | 214 """Represents one heap profile dump.""" |
| 197 | 215 |
| 198 def __init__(self, dump_path): | 216 def __init__(self, dump_path): |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 556 sizes['hour'] = (self.dump_time - first_dump_time) / 60.0 / 60.0 | 574 sizes['hour'] = (self.dump_time - first_dump_time) / 60.0 / 60.0 |
| 557 if 'minute' in sizes: | 575 if 'minute' in sizes: |
| 558 sizes['minute'] = (self.dump_time - first_dump_time) / 60.0 | 576 sizes['minute'] = (self.dump_time - first_dump_time) / 60.0 |
| 559 if 'second' in sizes: | 577 if 'second' in sizes: |
| 560 sizes['second'] = self.dump_time - first_dump_time | 578 sizes['second'] = self.dump_time - first_dump_time |
| 561 | 579 |
| 562 return sizes | 580 return sizes |
| 563 | 581 |
| 564 @staticmethod | 582 @staticmethod |
| 565 def accumulate_size_for_expand(stacktrace_lines, rule_list, buckets, | 583 def accumulate_size_for_expand(stacktrace_lines, rule_list, buckets, |
| 566 component_name, depth, sizes, symbols): | 584 component_name, depth, sizes, symbols, |
| 585 typeinfo_symbols): | |
| 567 for line in stacktrace_lines: | 586 for line in stacktrace_lines: |
| 568 words = line.split() | 587 words = line.split() |
| 569 bucket = buckets.get(int(words[BUCKET_ID])) | 588 bucket = buckets.get(int(words[BUCKET_ID])) |
| 570 component_match = get_component(rule_list, bucket, symbols) | 589 component_match = get_component(rule_list, bucket, symbols) |
| 571 if component_match == component_name: | 590 if component_match == component_name: |
| 572 stacktrace_sequence = '' | 591 stacktrace_sequence = '(type=%s) ' % typeinfo_symbols[bucket.typeinfo] |
| 592 stacktrace_sequence +='(type.name=%s) ' % bucket.typename | |
| 573 for address in bucket.stacktrace[0 : min(len(bucket.stacktrace), | 593 for address in bucket.stacktrace[0 : min(len(bucket.stacktrace), |
| 574 1 + depth)]: | 594 1 + depth)]: |
| 575 stacktrace_sequence += symbols[address] + ' ' | 595 stacktrace_sequence += symbols[address] + ' ' |
| 576 if not stacktrace_sequence in sizes: | 596 if not stacktrace_sequence in sizes: |
| 577 sizes[stacktrace_sequence] = 0 | 597 sizes[stacktrace_sequence] = 0 |
| 578 sizes[stacktrace_sequence] += int(words[COMMITTED]) | 598 sizes[stacktrace_sequence] += int(words[COMMITTED]) |
| 579 | 599 |
| 580 def expand(self, rule_list, buckets, component_name, depth, symbols): | 600 def expand( |
| 601 self, rule_list, buckets, component_name, depth, symbols, | |
| 602 typeinfo_symbols): | |
| 581 """Prints all stacktraces in a given component of given depth. | 603 """Prints all stacktraces in a given component of given depth. |
| 582 | 604 |
| 583 Args: | 605 Args: |
| 584 rule_list: A list of Rule objects. | 606 rule_list: A list of Rule objects. |
| 585 buckets: A dict mapping bucket ids to Bucket objects. | 607 buckets: A dict mapping bucket ids to Bucket objects. |
| 586 component_name: A name of component for filtering. | 608 component_name: A name of component for filtering. |
| 587 depth: An integer representing depth to be printed. | 609 depth: An integer representing depth to be printed. |
| 588 symbols: A dict mapping runtime addresses to symbol names. | 610 symbols: A dict mapping runtime addresses to symbol names. |
| 589 """ | 611 """ |
| 590 sizes = {} | 612 sizes = {} |
| 591 | 613 |
| 592 self.accumulate_size_for_expand( | 614 self.accumulate_size_for_expand( |
| 593 self.stacktrace_lines, rule_list, buckets, component_name, | 615 self.stacktrace_lines, rule_list, buckets, component_name, |
| 594 depth, sizes, symbols) | 616 depth, sizes, symbols, typeinfo_symbols) |
| 595 | 617 |
| 596 sorted_sizes_list = sorted( | 618 sorted_sizes_list = sorted( |
| 597 sizes.iteritems(), key=(lambda x: x[1]), reverse=True) | 619 sizes.iteritems(), key=(lambda x: x[1]), reverse=True) |
| 598 total = 0 | 620 total = 0 |
| 599 for size_pair in sorted_sizes_list: | 621 for size_pair in sorted_sizes_list: |
| 600 sys.stdout.write('%10d %s\n' % (size_pair[1], size_pair[0])) | 622 sys.stdout.write('%10d %s\n' % (size_pair[1], size_pair[0])) |
| 601 total += size_pair[1] | 623 total += size_pair[1] |
| 602 sys.stderr.write('total: %d\n' % (total)) | 624 sys.stderr.write('total: %d\n' % (total)) |
| 603 | 625 |
| 604 | 626 |
| 605 def update_symbols( | 627 def update_symbols( |
| 606 symbol_path, delayed_static_symbols, appeared_addresses, symbols): | 628 symbol_path, delayed_static_symbols, appeared_addresses, |
| 629 parameter_find_runtime_symbols_list, symbols): | |
| 607 """Updates address/symbol mapping on memory and in a .symbol cache file. | 630 """Updates address/symbol mapping on memory and in a .symbol cache file. |
| 608 | 631 |
| 609 It reads cached address/symbol mapping from a .symbol file if it exists. | 632 It reads cached address/symbol mapping from a .symbol file if it exists. |
| 610 Then, it resolves unresolved addresses from a Chrome binary with pprof. | 633 Then, it resolves unresolved addresses from a Chrome binary with pprof. |
| 611 Both mappings on memory and in a .symbol cache file are updated. | 634 Both mappings on memory and in a .symbol cache file are updated. |
| 612 | 635 |
| 613 Symbol files are formatted as follows: | 636 Symbol files are formatted as follows: |
| 614 <Address> <Symbol> | 637 <Address> <Symbol> |
| 615 <Address> <Symbol> | 638 <Address> <Symbol> |
| 616 <Address> <Symbol> | 639 <Address> <Symbol> |
| 617 ... | 640 ... |
| 618 | 641 |
| 619 Args: | 642 Args: |
| 620 symbol_path: A string representing a path for a .symbol file. | 643 symbol_path: A string representing a path for a .symbol file. |
| 621 delayed_static_symbols: A DelayedStaticSymbols object. | 644 delayed_static_symbols: A DelayedStaticSymbols object. |
| 622 appeared_addresses: A list of known addresses. | 645 appeared_addresses: A list of known addresses. |
| 646 parameter_find_runtime_symbols_list: A function to find symbols. | |
| 623 symbols: A dict mapping runtime addresses to symbol names. | 647 symbols: A dict mapping runtime addresses to symbol names. |
| 624 """ | 648 """ |
| 625 with open(symbol_path, mode='a+') as symbol_f: | 649 with open(symbol_path, mode='a+') as symbol_f: |
| 626 symbol_lines = symbol_f.readlines() | 650 symbol_lines = symbol_f.readlines() |
| 627 if symbol_lines: | 651 if symbol_lines: |
| 628 for line in symbol_lines: | 652 for line in symbol_lines: |
| 629 items = line.split(None, 1) | 653 items = line.split(None, 1) |
| 630 if len(items) == 1: | 654 if len(items) == 1: |
| 631 items.append('??') | 655 items.append('??') |
| 632 symbols[int(items[0], 16)] = items[1].rstrip() | 656 symbols[int(items[0], 16)] = items[1].rstrip() |
| 633 if symbols: | 657 if symbols: |
| 634 sys.stderr.write(' Found %d symbols in cache.\n' % len(symbols)) | 658 sys.stderr.write(' Found %d symbols in cache.\n' % len(symbols)) |
| 635 else: | 659 else: |
| 636 sys.stderr.write(' No symbols found in cache.\n') | 660 sys.stderr.write(' No symbols found in cache.\n') |
| 637 | 661 |
| 638 unresolved_addresses = sorted( | 662 unresolved_addresses = sorted( |
| 639 a for a in appeared_addresses if a not in symbols) | 663 a for a in appeared_addresses if a not in symbols) |
| 640 | 664 |
| 641 if not unresolved_addresses: | 665 if not unresolved_addresses: |
| 642 sys.stderr.write(' No need to resolve any more addresses.\n') | 666 sys.stderr.write(' No need to resolve any more addresses.\n') |
| 643 else: | 667 else: |
| 644 sys.stderr.write(' %d addresses unresolved.\n' % | 668 sys.stderr.write(' %d addresses unresolved.\n' % |
| 645 len(unresolved_addresses)) | 669 len(unresolved_addresses)) |
| 646 static_symbols = delayed_static_symbols.get() | 670 |
| 647 symbol_list = find_runtime_symbols_list( | 671 sys.stderr.write(' Loading symbols\n') |
| 648 static_symbols, unresolved_addresses) | 672 symbols_in_process = delayed_static_symbols.get() |
| 673 symbol_list = parameter_find_runtime_symbols_list( | |
| 674 symbols_in_process, unresolved_addresses) | |
| 675 sys.stderr.write(' Loaded\n') | |
| 649 | 676 |
| 650 for address, symbol in zip(unresolved_addresses, symbol_list): | 677 for address, symbol in zip(unresolved_addresses, symbol_list): |
| 651 if not symbol: | 678 if not symbol: |
| 652 symbol = '??' | 679 symbol = '??' |
| 653 stripped_symbol = symbol.strip() | 680 stripped_symbol = symbol.strip() |
| 654 symbols[address] = stripped_symbol | 681 symbols[address] = stripped_symbol |
| 655 symbol_f.write('%x %s\n' % (address, stripped_symbol)) | 682 symbol_f.write('%x %s\n' % (address, stripped_symbol)) |
| 656 | 683 |
| 657 sys.stderr.write(' All symbols resolved.\n') | 684 sys.stderr.write(' All symbols resolved.\n') |
| 658 | 685 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 720 Args: | 747 Args: |
| 721 policy_path: A path for a policy file. | 748 policy_path: A path for a policy file. |
| 722 Returns: | 749 Returns: |
| 723 A loaded policy object. | 750 A loaded policy object. |
| 724 """ | 751 """ |
| 725 with open(policy_path, mode='r') as f: | 752 with open(policy_path, mode='r') as f: |
| 726 policy = json.load(f) | 753 policy = json.load(f) |
| 727 | 754 |
| 728 rules = [] | 755 rules = [] |
| 729 for rule in policy['rules']: | 756 for rule in policy['rules']: |
| 730 rules.append(Rule( | 757 if 'typeinfo' in rule: |
| 731 rule['name'], rule['allocator'] == 'mmap', rule['stacktrace'])) | 758 rules.append(Rule( |
| 759 rule['name'], rule['allocator'] == 'mmap', rule['stacktrace'], | |
| 760 rule['typeinfo'])) | |
| 761 else: | |
| 762 rules.append(Rule( | |
| 763 rule['name'], rule['allocator'] == 'mmap', rule['stacktrace'])) | |
| 732 return Policy(rules, policy['version'], policy['components']) | 764 return Policy(rules, policy['version'], policy['components']) |
| 733 | 765 |
| 734 | 766 |
| 735 def find_prefix(path): | 767 def find_prefix(path): |
| 736 return re.sub('\.[0-9][0-9][0-9][0-9]\.heap', '', path) | 768 return re.sub('\.[0-9][0-9][0-9][0-9]\.heap', '', path) |
| 737 | 769 |
| 738 | 770 |
| 739 def load_buckets(prefix): | 771 def load_buckets(prefix): |
| 740 # Reading buckets | 772 # Reading buckets |
| 741 sys.stderr.write('Loading bucket files.\n') | 773 sys.stderr.write('Loading bucket files.\n') |
| 774 appeared_typeinfo_addresses = set() | |
| 742 buckets = {} | 775 buckets = {} |
| 743 bucket_count = 0 | 776 bucket_count = 0 |
| 744 n = 0 | 777 n = 0 |
| 745 while True: | 778 while True: |
| 746 buckets_path = '%s.%04d.buckets' % (prefix, n) | 779 buckets_path = '%s.%04d.buckets' % (prefix, n) |
| 747 if not os.path.exists(buckets_path): | 780 if not os.path.exists(buckets_path): |
| 748 if n > 10: | 781 if n > 10: |
| 749 break | 782 break |
| 750 n += 1 | 783 n += 1 |
| 751 continue | 784 continue |
| 752 sys.stderr.write(' %s\n' % buckets_path) | 785 sys.stderr.write(' %s\n' % buckets_path) |
| 753 with open(buckets_path, 'r') as buckets_f: | 786 with open(buckets_path, 'r') as buckets_f: |
| 754 for line in buckets_f: | 787 for line in buckets_f: |
| 755 words = line.split() | 788 words = line.split() |
| 756 stacktrace = [int(address, 16) for address in words[2:]] | 789 typeinfo = 0 |
| 757 buckets[int(words[0])] = Bucket(stacktrace, words[1] == 'mmap') | 790 typename = '' |
| 791 stacktrace_begin = 2 | |
| 792 for index, word in enumerate(words): | |
| 793 if index < 2: | |
| 794 continue | |
| 795 if word[0] == 't': | |
| 796 typeinfo = int(word[1:], 16) | |
| 797 appeared_typeinfo_addresses.add(typeinfo) | |
| 798 elif word[0] == 'n': | |
| 799 typename = word[1:] | |
| 800 else: | |
| 801 stacktrace_begin = index | |
| 802 break | |
| 803 stacktrace = [int(address, 16) for address in words[stacktrace_begin:]] | |
| 804 buckets[int(words[0])] = Bucket( | |
| 805 stacktrace, words[1] == 'mmap', typeinfo, typename) | |
| 758 n += 1 | 806 n += 1 |
| 759 | 807 |
| 760 return buckets | 808 return buckets, appeared_typeinfo_addresses |
| 761 | 809 |
| 762 | 810 |
| 763 def determine_dump_path_list(dump_path, prefix): | 811 def determine_dump_path_list(dump_path, prefix): |
| 764 dump_path_list = [dump_path] | 812 dump_path_list = [dump_path] |
| 765 | 813 |
| 766 # search for the sequence of files | 814 # search for the sequence of files |
| 767 n = int(dump_path[len(dump_path) - 9 : len(dump_path) - 5]) | 815 n = int(dump_path[len(dump_path) - 9 : len(dump_path) - 5]) |
| 768 n += 1 # skip current file | 816 n += 1 # skip current file |
| 769 while True: | 817 while True: |
| 770 p = '%s.%04d.heap' % (prefix, n) | 818 p = '%s.%04d.heap' % (prefix, n) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 805 appeared_addresses = set() | 853 appeared_addresses = set() |
| 806 dumps = [] | 854 dumps = [] |
| 807 for path in dump_path_list: | 855 for path in dump_path_list: |
| 808 sys.stderr.write(' %s' % path) | 856 sys.stderr.write(' %s' % path) |
| 809 dumps.append(load_single_dump(path, buckets, appeared_addresses)) | 857 dumps.append(load_single_dump(path, buckets, appeared_addresses)) |
| 810 sys.stderr.write('\n') | 858 sys.stderr.write('\n') |
| 811 return dumps, appeared_addresses | 859 return dumps, appeared_addresses |
| 812 | 860 |
| 813 | 861 |
| 814 def load_and_update_symbol_cache( | 862 def load_and_update_symbol_cache( |
| 815 prefix, appeared_addresses, delayed_static_symbols): | 863 prefix, appeared_addresses, appeared_typeinfo_addresses, |
| 864 delayed_static_symbols): | |
| 816 symbol_path = prefix + '.symbols' | 865 symbol_path = prefix + '.symbols' |
| 817 sys.stderr.write('Loading and updating symbol cache: "%s".\n' % symbol_path) | 866 sys.stderr.write('Loading and updating symbol cache: "%s".\n' % symbol_path) |
| 818 symbols = {} | 867 symbols = {} |
| 819 update_symbols( | 868 update_symbols( |
| 820 symbol_path, delayed_static_symbols, appeared_addresses, symbols) | 869 symbol_path, delayed_static_symbols, appeared_addresses, |
| 821 return symbols | 870 find_runtime_symbols_list, symbols) |
| 871 | |
| 872 typeinfo_symbol_path = prefix + '.tsymbols' | |
| 873 sys.stderr.write('Loading and updating typeinfo symbol cache: "%s".\n' % | |
| 874 typeinfo_symbol_path) | |
| 875 typeinfo_symbols = {} | |
| 876 update_symbols( | |
| 877 typeinfo_symbol_path, delayed_static_symbols, appeared_typeinfo_addresses, | |
| 878 find_runtime_typeinfo_symbols_list, typeinfo_symbols) | |
| 879 | |
| 880 return symbols, typeinfo_symbols | |
| 822 | 881 |
| 823 | 882 |
| 824 def load_default_policies(): | 883 def load_default_policies(): |
| 825 with open(POLICIES_JSON_PATH, mode='r') as policies_f: | 884 with open(POLICIES_JSON_PATH, mode='r') as policies_f: |
| 826 default_policies = json.load(policies_f) | 885 default_policies = json.load(policies_f) |
| 827 return default_policies | 886 return default_policies |
| 828 | 887 |
| 829 | 888 |
| 830 def load_policy(policies_dict, policy_label): | 889 def load_policy(policies_dict, policy_label): |
| 831 policy_file = policies_dict[policy_label]['file'] | 890 policy_file = policies_dict[policy_label]['file'] |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 863 specified_policies[specified_policy] = ( | 922 specified_policies[specified_policy] = ( |
| 864 default_policies[specified_policy]) | 923 default_policies[specified_policy]) |
| 865 policies = load_policies_dict(specified_policies) | 924 policies = load_policies_dict(specified_policies) |
| 866 else: | 925 else: |
| 867 policies = load_policies_dict(default_policies) | 926 policies = load_policies_dict(default_policies) |
| 868 return policies | 927 return policies |
| 869 | 928 |
| 870 | 929 |
| 871 def load_basic_files_with_multiple_dumps(dump_path, keep): | 930 def load_basic_files_with_multiple_dumps(dump_path, keep): |
| 872 prefix = find_prefix(dump_path) | 931 prefix = find_prefix(dump_path) |
| 873 buckets = load_buckets(prefix) | 932 buckets, appeared_typeinfo_addresses = load_buckets(prefix) |
| 874 dumps, appeared_addresses = load_dumps( | 933 dumps, appeared_addresses = load_dumps( |
| 875 determine_dump_path_list(dump_path, prefix), buckets) | 934 determine_dump_path_list(dump_path, prefix), buckets) |
| 876 delayed_static_symbols = DelayedStaticSymbols(prefix, keep) | 935 delayed_static_symbols = DelayedStaticSymbols(prefix, keep) |
| 877 symbols = load_and_update_symbol_cache( | 936 symbols, typeinfo_symbols = load_and_update_symbol_cache( |
| 878 prefix, appeared_addresses, delayed_static_symbols) | 937 prefix, appeared_addresses, appeared_typeinfo_addresses, |
| 879 return buckets, dumps, appeared_addresses, delayed_static_symbols, symbols | 938 delayed_static_symbols) |
| 939 for bucket in buckets: | |
| 940 if buckets[bucket].typeinfo != None: | |
|
M-A Ruel
2012/08/19 02:40:00
if buckets[bucket].typeinfo:
?
Dai Mikurube (NOT FULLTIME)
2012/08/20 10:35:27
Actually, buckets[bucket].typeinfo can be 0, but i
M-A Ruel
2012/08/20 18:12:13
Ok
| |
| 941 buckets[bucket].typeinfo_symbol = typeinfo_symbols[ | |
| 942 buckets[bucket].typeinfo] | |
| 943 | |
| 944 return (buckets, dumps, appeared_addresses, appeared_typeinfo_addresses, | |
| 945 delayed_static_symbols, symbols, typeinfo_symbols) | |
| 880 | 946 |
| 881 | 947 |
| 882 def load_basic_files_with_single_dump(dump_path, keep): | 948 def load_basic_files_with_single_dump(dump_path, keep): |
| 883 prefix = find_prefix(dump_path) | 949 prefix = find_prefix(dump_path) |
| 884 buckets = load_buckets(prefix) | 950 buckets, appeared_typeinfo_addresses = load_buckets(prefix) |
| 885 dump, appeared_addresses = load_dump(dump_path, buckets) | 951 dump, appeared_addresses = load_dump(dump_path, buckets) |
| 886 delayed_static_symbols = DelayedStaticSymbols(prefix, keep) | 952 delayed_static_symbols = DelayedStaticSymbols(prefix, keep) |
| 887 symbols = load_and_update_symbol_cache( | 953 symbols, typeinfo_symbols = load_and_update_symbol_cache( |
| 888 prefix, appeared_addresses, delayed_static_symbols) | 954 prefix, appeared_addresses, appeared_typeinfo_addresses, |
| 889 return buckets, dump, appeared_addresses, delayed_static_symbols, symbols | 955 delayed_static_symbols) |
| 956 for bucket in buckets: | |
| 957 if buckets[bucket].typeinfo != None: | |
| 958 buckets[bucket].typeinfo_symbol = typeinfo_symbols[ | |
| 959 buckets[bucket].typeinfo] | |
| 960 | |
| 961 return (buckets, dump, appeared_addresses, appeared_typeinfo_addresses, | |
| 962 delayed_static_symbols, symbols, typeinfo_symbols) | |
| 890 | 963 |
| 891 | 964 |
| 892 def do_stacktrace(sys_argv): | 965 def do_stacktrace(sys_argv): |
| 893 parser = optparse.OptionParser( | 966 parser = optparse.OptionParser( |
| 894 'Usage: %prog stacktrace [--keep] <dump>') | 967 'Usage: %prog stacktrace [--keep] <dump>') |
| 895 parser.add_option('--keep', dest='keep', action='store_true') | 968 parser.add_option('--keep', dest='keep', action='store_true') |
| 896 options, args = parser.parse_args(sys_argv) | 969 options, args = parser.parse_args(sys_argv) |
| 897 | 970 |
| 898 if len(args) != 2: | 971 if len(args) != 2: |
| 899 parser.error('needs 1 argument.') | 972 parser.error('needs 1 argument.') |
| 900 return 1 | 973 return 1 |
| 901 | 974 |
| 902 dump_path = args[1] | 975 dump_path = args[1] |
| 903 | 976 |
| 904 buckets, dump, appeared_addresses, delayed_static_symbols, symbols = ( | 977 (buckets, dump, appeared_addresses, appeared_typeinfo_addresses, |
| 905 load_basic_files_with_single_dump(dump_path, options.keep)) | 978 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 979 load_basic_files_with_single_dump(dump_path, options.keep)) | |
| 906 | 980 |
| 907 dump.print_stacktrace(buckets, symbols) | 981 dump.print_stacktrace(buckets, symbols) |
| 908 | 982 |
| 909 return 0 | 983 return 0 |
| 910 | 984 |
| 911 | 985 |
| 912 def do_csv(sys_argv): | 986 def do_csv(sys_argv): |
| 913 parser = optparse.OptionParser( | 987 parser = optparse.OptionParser( |
| 914 'Usage: %prog csv [-p POLICY] [--keep] <first-dump>') | 988 'Usage: %prog csv [-p POLICY] [--keep] <first-dump>') |
| 915 parser.add_option('-p', '--policy', type='string', dest='policy', | 989 parser.add_option('-p', '--policy', type='string', dest='policy', |
| 916 help='profile with POLICY', metavar='POLICY') | 990 help='profile with POLICY', metavar='POLICY') |
| 917 parser.add_option('--keep', dest='keep', action='store_true') | 991 parser.add_option('--keep', dest='keep', action='store_true') |
| 918 options, args = parser.parse_args(sys_argv) | 992 options, args = parser.parse_args(sys_argv) |
| 919 | 993 |
| 920 if len(args) != 2: | 994 if len(args) != 2: |
| 921 parser.error('needs 1 argument.') | 995 parser.error('needs 1 argument.') |
| 922 return 1 | 996 return 1 |
| 923 | 997 |
| 924 dump_path = args[1] | 998 dump_path = args[1] |
| 925 | 999 |
| 926 buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = ( | 1000 (buckets, dumps, appeared_addresses, appeared_typeinfo_addresses, |
| 927 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | 1001 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 1002 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | |
| 1003 | |
| 928 policies = load_policies(options.policy) | 1004 policies = load_policies(options.policy) |
| 929 | 1005 |
| 930 max_components = 0 | 1006 max_components = 0 |
| 931 for policy in policies: | 1007 for policy in policies: |
| 932 max_components = max(max_components, len(policies[policy].components)) | 1008 max_components = max(max_components, len(policies[policy].components)) |
| 933 | 1009 |
| 934 for policy in sorted(policies): | 1010 for policy in sorted(policies): |
| 935 rule_list = policies[policy].rules | 1011 rule_list = policies[policy].rules |
| 936 components = policies[policy].components | 1012 components = policies[policy].components |
| 937 | 1013 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 965 help='profile with POLICY', metavar='POLICY') | 1041 help='profile with POLICY', metavar='POLICY') |
| 966 parser.add_option('--keep', dest='keep', action='store_true') | 1042 parser.add_option('--keep', dest='keep', action='store_true') |
| 967 options, args = parser.parse_args(sys_argv) | 1043 options, args = parser.parse_args(sys_argv) |
| 968 | 1044 |
| 969 if len(args) != 2: | 1045 if len(args) != 2: |
| 970 parser.error('needs 1 argument.') | 1046 parser.error('needs 1 argument.') |
| 971 return 1 | 1047 return 1 |
| 972 | 1048 |
| 973 dump_path = args[1] | 1049 dump_path = args[1] |
| 974 | 1050 |
| 975 buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = ( | 1051 (buckets, dumps, appeared_addresses, appeared_typeinfo_addresses, |
| 976 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | 1052 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 1053 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | |
| 977 policies = load_policies(options.policy) | 1054 policies = load_policies(options.policy) |
| 978 | 1055 |
| 979 json_base = { | 1056 json_base = { |
| 980 'version': 'JSON_DEEP_2', | 1057 'version': 'JSON_DEEP_2', |
| 981 'policies': {}, | 1058 'policies': {}, |
| 982 } | 1059 } |
| 983 | 1060 |
| 984 for policy in sorted(policies): | 1061 for policy in sorted(policies): |
| 985 rule_list = policies[policy].rules | 1062 rule_list = policies[policy].rules |
| 986 components = policies[policy].components | 1063 components = policies[policy].components |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1013 help='profile with POLICY', metavar='POLICY') | 1090 help='profile with POLICY', metavar='POLICY') |
| 1014 parser.add_option('--keep', dest='keep', action='store_true') | 1091 parser.add_option('--keep', dest='keep', action='store_true') |
| 1015 options, args = parser.parse_args(sys_argv) | 1092 options, args = parser.parse_args(sys_argv) |
| 1016 | 1093 |
| 1017 if len(args) != 2: | 1094 if len(args) != 2: |
| 1018 parser.error('needs 1 argument.') | 1095 parser.error('needs 1 argument.') |
| 1019 return 1 | 1096 return 1 |
| 1020 | 1097 |
| 1021 dump_path = args[1] | 1098 dump_path = args[1] |
| 1022 | 1099 |
| 1023 buckets, dumps, appeared_addresses, delayed_static_symbols, symbols = ( | 1100 (buckets, dumps, appeared_addresses, appeared_typeinfo_addresses, |
| 1024 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | 1101 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 1102 load_basic_files_with_multiple_dumps(dump_path, options.keep)) | |
| 1025 policies = load_policies(options.policy) | 1103 policies = load_policies(options.policy) |
| 1026 | 1104 |
| 1027 for policy in sorted(policies): | 1105 for policy in sorted(policies): |
| 1028 rule_list = policies[policy].rules | 1106 rule_list = policies[policy].rules |
| 1029 components = policies[policy].components | 1107 components = policies[policy].components |
| 1030 | 1108 |
| 1031 component_sizes = dumps[0].apply_policy( | 1109 component_sizes = dumps[0].apply_policy( |
| 1032 rule_list, buckets, dumps[0].dump_time, components, symbols) | 1110 rule_list, buckets, dumps[0].dump_time, components, symbols) |
| 1033 sys.stdout.write('%s:\n' % policy) | 1111 sys.stdout.write('%s:\n' % policy) |
| 1034 for c in components: | 1112 for c in components: |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1052 | 1130 |
| 1053 if len(args) != 5: | 1131 if len(args) != 5: |
| 1054 parser.error('needs 4 arguments.') | 1132 parser.error('needs 4 arguments.') |
| 1055 return 1 | 1133 return 1 |
| 1056 | 1134 |
| 1057 dump_path = args[1] | 1135 dump_path = args[1] |
| 1058 target_policy = args[2] | 1136 target_policy = args[2] |
| 1059 component_name = args[3] | 1137 component_name = args[3] |
| 1060 depth = args[4] | 1138 depth = args[4] |
| 1061 | 1139 |
| 1062 buckets, dump, appeared_addresses, delayed_static_symbols, symbols = ( | 1140 (buckets, dump, appeared_addresses, appeared_typeinfo_addresses, |
| 1063 load_basic_files_with_single_dump(dump_path, options.keep)) | 1141 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 1142 load_basic_files_with_single_dump(dump_path, options.keep)) | |
| 1064 policies = load_policies(target_policy) | 1143 policies = load_policies(target_policy) |
| 1065 | 1144 |
| 1066 rule_list = policies[target_policy].rules | 1145 rule_list = policies[target_policy].rules |
| 1067 | 1146 |
| 1068 dump.expand(rule_list, buckets, component_name, int(depth), symbols) | 1147 dump.expand(rule_list, buckets, component_name, int(depth), symbols, |
| 1148 typeinfo_symbols) | |
| 1069 | 1149 |
| 1070 return 0 | 1150 return 0 |
| 1071 | 1151 |
| 1072 | 1152 |
| 1073 def do_pprof(sys_argv): | 1153 def do_pprof(sys_argv): |
| 1074 parser = optparse.OptionParser( | 1154 parser = optparse.OptionParser( |
| 1075 'Usage: %prog pprof [-c COMPONENT] [--keep] <dump> <policy>') | 1155 'Usage: %prog pprof [-c COMPONENT] [--keep] <dump> <policy>') |
| 1076 parser.add_option('-c', '--component', type='string', dest='component', | 1156 parser.add_option('-c', '--component', type='string', dest='component', |
| 1077 help='restrict to COMPONENT', metavar='COMPONENT') | 1157 help='restrict to COMPONENT', metavar='COMPONENT') |
| 1078 parser.add_option('--keep', dest='keep', action='store_true') | 1158 parser.add_option('--keep', dest='keep', action='store_true') |
| 1079 options, args = parser.parse_args(sys_argv) | 1159 options, args = parser.parse_args(sys_argv) |
| 1080 | 1160 |
| 1081 if len(args) != 3: | 1161 if len(args) != 3: |
| 1082 parser.error('needs 2 arguments.') | 1162 parser.error('needs 2 arguments.') |
| 1083 return 1 | 1163 return 1 |
| 1084 | 1164 |
| 1085 dump_path = args[1] | 1165 dump_path = args[1] |
| 1086 target_policy = args[2] | 1166 target_policy = args[2] |
| 1087 component = options.component | 1167 component = options.component |
| 1088 | 1168 |
| 1089 buckets, dump, appeared_addresses, delayed_static_symbols, symbols = ( | 1169 (buckets, dump, appeared_addresses, appeared_typeinfo_addresses, |
| 1090 load_basic_files_with_single_dump(dump_path, options.keep)) | 1170 delayed_static_symbols, symbols, typeinfo_symbols) = ( |
| 1171 load_basic_files_with_single_dump(dump_path, options.keep)) | |
| 1091 policies = load_policies(target_policy) | 1172 policies = load_policies(target_policy) |
| 1092 | 1173 |
| 1093 rule_list = policies[target_policy].rules | 1174 rule_list = policies[target_policy].rules |
| 1094 | 1175 |
| 1095 with open(find_prefix(dump_path) + '.maps', 'r') as maps_f: | 1176 with open(find_prefix(dump_path) + '.maps', 'r') as maps_f: |
| 1096 maps_lines = maps_f.readlines() | 1177 maps_lines = maps_f.readlines() |
| 1097 dump.print_for_pprof(rule_list, buckets, maps_lines, component, symbols) | 1178 dump.print_for_pprof(rule_list, buckets, maps_lines, component, symbols) |
| 1098 | 1179 |
| 1099 return 0 | 1180 return 0 |
| 1100 | 1181 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1139 dmprof stacktrace [--keep] <dump> | 1220 dmprof stacktrace [--keep] <dump> |
| 1140 """ % (sys.argv[0])) | 1221 """ % (sys.argv[0])) |
| 1141 sys.exit(1) | 1222 sys.exit(1) |
| 1142 action = sys.argv.pop(1) | 1223 action = sys.argv.pop(1) |
| 1143 | 1224 |
| 1144 return COMMANDS[action](sys.argv) | 1225 return COMMANDS[action](sys.argv) |
| 1145 | 1226 |
| 1146 | 1227 |
| 1147 if __name__ == '__main__': | 1228 if __name__ == '__main__': |
| 1148 sys.exit(main()) | 1229 sys.exit(main()) |
| OLD | NEW |