| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
| 4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
| 6 # met: | 6 # met: |
| 7 # | 7 # |
| 8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 import subprocess | 38 import subprocess |
| 39 import sys | 39 import sys |
| 40 import time | 40 import time |
| 41 | 41 |
| 42 | 42 |
| 43 USAGE="""usage: %prog [OPTION]... | 43 USAGE="""usage: %prog [OPTION]... |
| 44 | 44 |
| 45 Analyses V8 and perf logs to produce profiles. | 45 Analyses V8 and perf logs to produce profiles. |
| 46 | 46 |
| 47 Perf logs can be collected using a command like: | 47 Perf logs can be collected using a command like: |
| 48 $ perf record -R -e cycles -c 10000 -f -i ./shell bench.js --ll-prof | 48 $ perf record -R -e cycles -c 10000 -f -i ./d8 bench.js --ll-prof |
| 49 # -R: collect all data | 49 # -R: collect all data |
| 50 # -e cycles: use cpu-cycles event (run "perf list" for details) | 50 # -e cycles: use cpu-cycles event (run "perf list" for details) |
| 51 # -c 10000: write a sample after each 10000 events | 51 # -c 10000: write a sample after each 10000 events |
| 52 # -f: force output file overwrite | 52 # -f: force output file overwrite |
| 53 # -i: limit profiling to our process and the kernel | 53 # -i: limit profiling to our process and the kernel |
| 54 # --ll-prof shell flag enables the right V8 logs | 54 # --ll-prof shell flag enables the right V8 logs |
| 55 This will produce a binary trace file (perf.data) that %prog can analyse. | 55 This will produce a binary trace file (perf.data) that %prog can analyse. |
| 56 | 56 |
| 57 IMPORTANT: |
| 58 The kernel has an internal maximum for events per second, it is 100K by |
| 59 default. That's not enough for "-c 10000". Set it to some higher value: |
| 60 $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate |
| 61 You can also make the warning about kernel address maps go away: |
| 62 $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict |
| 63 |
| 64 We have a convenience script that handles all of the above for you: |
| 65 $ tools/run-llprof.sh ./d8 bench.js |
| 66 |
| 57 Examples: | 67 Examples: |
| 58 # Print flat profile with annotated disassembly for the 10 top | 68 # Print flat profile with annotated disassembly for the 10 top |
| 59 # symbols. Use default log names and include the snapshot log. | 69 # symbols. Use default log names and include the snapshot log. |
| 60 $ %prog --snapshot --disasm-top=10 | 70 $ %prog --snapshot --disasm-top=10 |
| 61 | 71 |
| 62 # Print flat profile with annotated disassembly for all used symbols. | 72 # Print flat profile with annotated disassembly for all used symbols. |
| 63 # Use default log names and include kernel symbols into analysis. | 73 # Use default log names and include kernel symbols into analysis. |
| 64 $ %prog --disasm-all --kernel | 74 $ %prog --disasm-all --kernel |
| 65 | 75 |
| 66 # Print flat profile. Use custom log names. | 76 # Print flat profile. Use custom log names. |
| 67 $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot | 77 $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot |
| 68 """ | 78 """ |
| 69 | 79 |
| 70 | 80 |
| 71 JS_ORIGIN = "js" | 81 JS_ORIGIN = "js" |
| 72 JS_SNAPSHOT_ORIGIN = "js-snapshot" | 82 JS_SNAPSHOT_ORIGIN = "js-snapshot" |
| 73 | 83 |
| 74 class Code(object): | 84 class Code(object): |
| 75 """Code object.""" | 85 """Code object.""" |
| 76 | 86 |
| 77 _id = 0 | 87 _id = 0 |
| 88 UNKNOWN = 0 |
| 89 V8INTERNAL = 1 |
| 90 FULL_CODEGEN = 2 |
| 91 OPTIMIZED = 3 |
| 78 | 92 |
| 79 def __init__(self, name, start_address, end_address, origin, origin_offset): | 93 def __init__(self, name, start_address, end_address, origin, origin_offset): |
| 80 self.id = Code._id | 94 self.id = Code._id |
| 81 Code._id += 1 | 95 Code._id += 1 |
| 82 self.name = name | 96 self.name = name |
| 83 self.other_names = None | 97 self.other_names = None |
| 84 self.start_address = start_address | 98 self.start_address = start_address |
| 85 self.end_address = end_address | 99 self.end_address = end_address |
| 86 self.origin = origin | 100 self.origin = origin |
| 87 self.origin_offset = origin_offset | 101 self.origin_offset = origin_offset |
| 88 self.self_ticks = 0 | 102 self.self_ticks = 0 |
| 89 self.self_ticks_map = None | 103 self.self_ticks_map = None |
| 90 self.callee_ticks = None | 104 self.callee_ticks = None |
| 105 if name.startswith("LazyCompile:*"): |
| 106 self.codetype = Code.OPTIMIZED |
| 107 elif name.startswith("LazyCompile:"): |
| 108 self.codetype = Code.FULL_CODEGEN |
| 109 elif name.startswith("v8::internal::"): |
| 110 self.codetype = Code.V8INTERNAL |
| 111 else: |
| 112 self.codetype = Code.UNKNOWN |
| 91 | 113 |
| 92 def AddName(self, name): | 114 def AddName(self, name): |
| 93 assert self.name != name | 115 assert self.name != name |
| 94 if self.other_names is None: | 116 if self.other_names is None: |
| 95 self.other_names = [name] | 117 self.other_names = [name] |
| 96 return | 118 return |
| 97 if not name in self.other_names: | 119 if not name in self.other_names: |
| 98 self.other_names.append(name) | 120 self.other_names.append(name) |
| 99 | 121 |
| 100 def FullName(self): | 122 def FullName(self): |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 return disasm.GetDisasmLines(filename, | 200 return disasm.GetDisasmLines(filename, |
| 179 self.origin_offset, | 201 self.origin_offset, |
| 180 self.end_address - self.start_address, | 202 self.end_address - self.start_address, |
| 181 arch, | 203 arch, |
| 182 inplace) | 204 inplace) |
| 183 | 205 |
| 184 | 206 |
| 185 class CodePage(object): | 207 class CodePage(object): |
| 186 """Group of adjacent code objects.""" | 208 """Group of adjacent code objects.""" |
| 187 | 209 |
| 188 SHIFT = 12 # 4K pages | 210 SHIFT = 20 # 1M pages |
| 189 SIZE = (1 << SHIFT) | 211 SIZE = (1 << SHIFT) |
| 190 MASK = ~(SIZE - 1) | 212 MASK = ~(SIZE - 1) |
| 191 | 213 |
| 192 @staticmethod | 214 @staticmethod |
| 193 def PageAddress(address): | 215 def PageAddress(address): |
| 194 return address & CodePage.MASK | 216 return address & CodePage.MASK |
| 195 | 217 |
| 196 @staticmethod | 218 @staticmethod |
| 197 def PageId(address): | 219 def PageId(address): |
| 198 return address >> CodePage.SHIFT | 220 return address >> CodePage.SHIFT |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 | 522 |
| 501 @staticmethod | 523 @staticmethod |
| 502 def CtypesFields(fields): | 524 def CtypesFields(fields): |
| 503 return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields] | 525 return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields] |
| 504 | 526 |
| 505 | 527 |
| 506 # Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=
tree;f=tools/perf | 528 # Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=
tree;f=tools/perf |
| 507 # for the gory details. | 529 # for the gory details. |
| 508 | 530 |
| 509 | 531 |
| 532 # Reference: struct perf_file_header in kernel/tools/perf/util/header.h |
| 510 TRACE_HEADER_DESC = Descriptor([ | 533 TRACE_HEADER_DESC = Descriptor([ |
| 511 ("magic", "u64"), | 534 ("magic", "u64"), |
| 512 ("size", "u64"), | 535 ("size", "u64"), |
| 513 ("attr_size", "u64"), | 536 ("attr_size", "u64"), |
| 514 ("attrs_offset", "u64"), | 537 ("attrs_offset", "u64"), |
| 515 ("attrs_size", "u64"), | 538 ("attrs_size", "u64"), |
| 516 ("data_offset", "u64"), | 539 ("data_offset", "u64"), |
| 517 ("data_size", "u64"), | 540 ("data_size", "u64"), |
| 518 ("event_types_offset", "u64"), | 541 ("event_types_offset", "u64"), |
| 519 ("event_types_size", "u64") | 542 ("event_types_size", "u64") |
| 520 ]) | 543 ]) |
| 521 | 544 |
| 522 | 545 |
| 546 # Reference: /usr/include/linux/perf_event.h |
| 523 PERF_EVENT_ATTR_DESC = Descriptor([ | 547 PERF_EVENT_ATTR_DESC = Descriptor([ |
| 524 ("type", "u32"), | 548 ("type", "u32"), |
| 525 ("size", "u32"), | 549 ("size", "u32"), |
| 526 ("config", "u64"), | 550 ("config", "u64"), |
| 527 ("sample_period_or_freq", "u64"), | 551 ("sample_period_or_freq", "u64"), |
| 528 ("sample_type", "u64"), | 552 ("sample_type", "u64"), |
| 529 ("read_format", "u64"), | 553 ("read_format", "u64"), |
| 530 ("flags", "u64"), | 554 ("flags", "u64"), |
| 531 ("wakeup_events_or_watermark", "u32"), | 555 ("wakeup_events_or_watermark", "u32"), |
| 532 ("bt_type", "u32"), | 556 ("bp_type", "u32"), |
| 533 ("bp_addr", "u64"), | 557 ("bp_addr", "u64"), |
| 534 ("bp_len", "u64"), | 558 ("bp_len", "u64") |
| 535 ]) | 559 ]) |
| 536 | 560 |
| 537 | 561 |
| 562 # Reference: /usr/include/linux/perf_event.h |
| 538 PERF_EVENT_HEADER_DESC = Descriptor([ | 563 PERF_EVENT_HEADER_DESC = Descriptor([ |
| 539 ("type", "u32"), | 564 ("type", "u32"), |
| 540 ("misc", "u16"), | 565 ("misc", "u16"), |
| 541 ("size", "u16") | 566 ("size", "u16") |
| 542 ]) | 567 ]) |
| 543 | 568 |
| 544 | 569 |
| 570 # Reference: kernel/events/core.c |
| 545 PERF_MMAP_EVENT_BODY_DESC = Descriptor([ | 571 PERF_MMAP_EVENT_BODY_DESC = Descriptor([ |
| 546 ("pid", "u32"), | 572 ("pid", "u32"), |
| 547 ("tid", "u32"), | 573 ("tid", "u32"), |
| 548 ("addr", "u64"), | 574 ("addr", "u64"), |
| 549 ("len", "u64"), | 575 ("len", "u64"), |
| 550 ("pgoff", "u64") | 576 ("pgoff", "u64") |
| 551 ]) | 577 ]) |
| 552 | 578 |
| 553 | 579 |
| 554 # perf_event_attr.sample_type bits control the set of | 580 # perf_event_attr.sample_type bits control the set of |
| 555 # perf_sample_event fields. | 581 # perf_sample_event fields. |
| 556 PERF_SAMPLE_IP = 1 << 0 | 582 PERF_SAMPLE_IP = 1 << 0 |
| 557 PERF_SAMPLE_TID = 1 << 1 | 583 PERF_SAMPLE_TID = 1 << 1 |
| 558 PERF_SAMPLE_TIME = 1 << 2 | 584 PERF_SAMPLE_TIME = 1 << 2 |
| 559 PERF_SAMPLE_ADDR = 1 << 3 | 585 PERF_SAMPLE_ADDR = 1 << 3 |
| 560 PERF_SAMPLE_READ = 1 << 4 | 586 PERF_SAMPLE_READ = 1 << 4 |
| 561 PERF_SAMPLE_CALLCHAIN = 1 << 5 | 587 PERF_SAMPLE_CALLCHAIN = 1 << 5 |
| 562 PERF_SAMPLE_ID = 1 << 6 | 588 PERF_SAMPLE_ID = 1 << 6 |
| 563 PERF_SAMPLE_CPU = 1 << 7 | 589 PERF_SAMPLE_CPU = 1 << 7 |
| 564 PERF_SAMPLE_PERIOD = 1 << 8 | 590 PERF_SAMPLE_PERIOD = 1 << 8 |
| 565 PERF_SAMPLE_STREAM_ID = 1 << 9 | 591 PERF_SAMPLE_STREAM_ID = 1 << 9 |
| 566 PERF_SAMPLE_RAW = 1 << 10 | 592 PERF_SAMPLE_RAW = 1 << 10 |
| 567 | 593 |
| 568 | 594 |
| 595 # Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE. |
| 569 PERF_SAMPLE_EVENT_BODY_FIELDS = [ | 596 PERF_SAMPLE_EVENT_BODY_FIELDS = [ |
| 570 ("ip", "u64", PERF_SAMPLE_IP), | 597 ("ip", "u64", PERF_SAMPLE_IP), |
| 571 ("pid", "u32", PERF_SAMPLE_TID), | 598 ("pid", "u32", PERF_SAMPLE_TID), |
| 572 ("tid", "u32", PERF_SAMPLE_TID), | 599 ("tid", "u32", PERF_SAMPLE_TID), |
| 573 ("time", "u64", PERF_SAMPLE_TIME), | 600 ("time", "u64", PERF_SAMPLE_TIME), |
| 574 ("addr", "u64", PERF_SAMPLE_ADDR), | 601 ("addr", "u64", PERF_SAMPLE_ADDR), |
| 575 ("id", "u64", PERF_SAMPLE_ID), | 602 ("id", "u64", PERF_SAMPLE_ID), |
| 576 ("stream_id", "u64", PERF_SAMPLE_STREAM_ID), | 603 ("stream_id", "u64", PERF_SAMPLE_STREAM_ID), |
| 577 ("cpu", "u32", PERF_SAMPLE_CPU), | 604 ("cpu", "u32", PERF_SAMPLE_CPU), |
| 578 ("res", "u32", PERF_SAMPLE_CPU), | 605 ("res", "u32", PERF_SAMPLE_CPU), |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 self.infos.append(mmap_info) | 722 self.infos.append(mmap_info) |
| 696 mmap_info.ticks = 0 | 723 mmap_info.ticks = 0 |
| 697 mmap_info.unique_name = self._UniqueMmapName(mmap_info) | 724 mmap_info.unique_name = self._UniqueMmapName(mmap_info) |
| 698 if not os.path.exists(mmap_info.filename): | 725 if not os.path.exists(mmap_info.filename): |
| 699 return True | 726 return True |
| 700 # Request section headers (-h), symbols (-t), and dynamic symbols | 727 # Request section headers (-h), symbols (-t), and dynamic symbols |
| 701 # (-T) from objdump. | 728 # (-T) from objdump. |
| 702 # Unfortunately, section headers span two lines, so we have to | 729 # Unfortunately, section headers span two lines, so we have to |
| 703 # keep the just seen section name (from the first line in each | 730 # keep the just seen section name (from the first line in each |
| 704 # section header) in the after_section variable. | 731 # section header) in the after_section variable. |
| 732 if mmap_info.filename.endswith(".ko"): |
| 733 dynamic_symbols = "" |
| 734 else: |
| 735 dynamic_symbols = "-T" |
| 705 process = subprocess.Popen( | 736 process = subprocess.Popen( |
| 706 "%s -h -t -T -C %s" % (OBJDUMP_BIN, mmap_info.filename), | 737 "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename), |
| 707 shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 738 shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
| 708 pipe = process.stdout | 739 pipe = process.stdout |
| 709 after_section = None | 740 after_section = None |
| 710 code_sections = set() | 741 code_sections = set() |
| 711 reloc_sections = set() | 742 reloc_sections = set() |
| 712 dynamic = False | 743 dynamic = False |
| 713 try: | 744 try: |
| 714 for line in pipe: | 745 for line in pipe: |
| 715 if after_section: | 746 if after_section: |
| 716 if line.find("CODE") != -1: | 747 if line.find("CODE") != -1: |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 used_code = [code for code in code_map.UsedCode()] | 819 used_code = [code for code in code_map.UsedCode()] |
| 789 used_code.sort(key=lambda x: x.self_ticks, reverse=True) | 820 used_code.sort(key=lambda x: x.self_ticks, reverse=True) |
| 790 for i, code in enumerate(used_code): | 821 for i, code in enumerate(used_code): |
| 791 code_ticks = code.self_ticks | 822 code_ticks = code.self_ticks |
| 792 print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks, | 823 print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks, |
| 793 code.FullName(), code.origin) | 824 code.FullName(), code.origin) |
| 794 if options.disasm_all or i < options.disasm_top: | 825 if options.disasm_all or i < options.disasm_top: |
| 795 code.PrintAnnotated(arch, options) | 826 code.PrintAnnotated(arch, options) |
| 796 print | 827 print |
| 797 print "Ticks per library:" | 828 print "Ticks per library:" |
| 798 mmap_infos = [m for m in library_repo.infos] | 829 mmap_infos = [m for m in library_repo.infos if m.ticks > 0] |
| 799 mmap_infos.sort(key=lambda m: m.ticks, reverse=True) | 830 mmap_infos.sort(key=lambda m: m.ticks, reverse=True) |
| 800 for mmap_info in mmap_infos: | 831 for mmap_info in mmap_infos: |
| 801 mmap_ticks = mmap_info.ticks | 832 mmap_ticks = mmap_info.ticks |
| 802 print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks, | 833 print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks, |
| 803 mmap_info.unique_name) | 834 mmap_info.unique_name) |
| 804 | 835 |
| 805 | 836 |
| 806 def PrintDot(code_map, options): | 837 def PrintDot(code_map, options): |
| 807 print "digraph G {" | 838 print "digraph G {" |
| 808 for code in code_map.UsedCode(): | 839 for code in code_map.UsedCode(): |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 878 disasm.OBJDUMP_BIN = options.objdump | 909 disasm.OBJDUMP_BIN = options.objdump |
| 879 OBJDUMP_BIN = options.objdump | 910 OBJDUMP_BIN = options.objdump |
| 880 else: | 911 else: |
| 881 print "Cannot find %s, falling back to default objdump" % options.objdump | 912 print "Cannot find %s, falling back to default objdump" % options.objdump |
| 882 | 913 |
| 883 # Stats. | 914 # Stats. |
| 884 events = 0 | 915 events = 0 |
| 885 ticks = 0 | 916 ticks = 0 |
| 886 missed_ticks = 0 | 917 missed_ticks = 0 |
| 887 really_missed_ticks = 0 | 918 really_missed_ticks = 0 |
| 919 optimized_ticks = 0 |
| 920 generated_ticks = 0 |
| 921 v8_internal_ticks = 0 |
| 888 mmap_time = 0 | 922 mmap_time = 0 |
| 889 sample_time = 0 | 923 sample_time = 0 |
| 890 | 924 |
| 891 # Process the snapshot log to fill the snapshot name map. | 925 # Process the snapshot log to fill the snapshot name map. |
| 892 snapshot_name_map = {} | 926 snapshot_name_map = {} |
| 893 if options.snapshot: | 927 if options.snapshot: |
| 894 snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log) | 928 snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log) |
| 895 snapshot_name_map = snapshot_log_reader.ReadNameMap() | 929 snapshot_name_map = snapshot_log_reader.ReadNameMap() |
| 896 | 930 |
| 897 # Initialize the log reader. | 931 # Initialize the log reader. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 921 else: | 955 else: |
| 922 library_repo.Load(mmap_info, code_map, options) | 956 library_repo.Load(mmap_info, code_map, options) |
| 923 mmap_time += time.time() - start | 957 mmap_time += time.time() - start |
| 924 elif header.type == PERF_RECORD_SAMPLE: | 958 elif header.type == PERF_RECORD_SAMPLE: |
| 925 ticks += 1 | 959 ticks += 1 |
| 926 start = time.time() | 960 start = time.time() |
| 927 sample = trace_reader.ReadSample(header, offset) | 961 sample = trace_reader.ReadSample(header, offset) |
| 928 code = code_map.Find(sample.ip) | 962 code = code_map.Find(sample.ip) |
| 929 if code: | 963 if code: |
| 930 code.Tick(sample.ip) | 964 code.Tick(sample.ip) |
| 965 if code.codetype == Code.OPTIMIZED: |
| 966 optimized_ticks += 1 |
| 967 elif code.codetype == Code.FULL_CODEGEN: |
| 968 generated_ticks += 1 |
| 969 elif code.codetype == Code.V8INTERNAL: |
| 970 v8_internal_ticks += 1 |
| 931 else: | 971 else: |
| 932 missed_ticks += 1 | 972 missed_ticks += 1 |
| 933 if not library_repo.Tick(sample.ip) and not code: | 973 if not library_repo.Tick(sample.ip) and not code: |
| 934 really_missed_ticks += 1 | 974 really_missed_ticks += 1 |
| 935 if trace_reader.callchain_supported: | 975 if trace_reader.callchain_supported: |
| 936 for ip in sample.ips: | 976 for ip in sample.ips: |
| 937 caller_code = code_map.Find(ip) | 977 caller_code = code_map.Find(ip) |
| 938 if caller_code: | 978 if caller_code: |
| 939 if code: | 979 if code: |
| 940 caller_code.CalleeTick(code) | 980 caller_code.CalleeTick(code) |
| 941 code = caller_code | 981 code = caller_code |
| 942 sample_time += time.time() - start | 982 sample_time += time.time() - start |
| 943 | 983 |
| 944 if options.dot: | 984 if options.dot: |
| 945 PrintDot(code_map, options) | 985 PrintDot(code_map, options) |
| 946 else: | 986 else: |
| 947 PrintReport(code_map, library_repo, log_reader.arch, ticks, options) | 987 PrintReport(code_map, library_repo, log_reader.arch, ticks, options) |
| 948 | 988 |
| 949 if not options.quiet: | 989 if not options.quiet: |
| 990 def PrintTicks(number, total, description): |
| 991 print("%10d %5.1f%% ticks in %s" % |
| 992 (number, 100.0*number/total, description)) |
| 950 print | 993 print |
| 951 print "Stats:" | 994 print "Stats:" |
| 952 print "%10d total trace events" % events | 995 print "%10d total trace events" % events |
| 953 print "%10d total ticks" % ticks | 996 print "%10d total ticks" % ticks |
| 954 print "%10d ticks not in symbols" % missed_ticks | 997 print "%10d ticks not in symbols" % missed_ticks |
| 955 print "%10d unaccounted ticks" % really_missed_ticks | 998 unaccounted = "unaccounted ticks" |
| 999 if really_missed_ticks > 0: |
| 1000 unaccounted += " (probably in the kernel, try --kernel)" |
| 1001 PrintTicks(really_missed_ticks, ticks, unaccounted) |
| 1002 PrintTicks(optimized_ticks, ticks, "ticks in optimized code") |
| 1003 PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code") |
| 1004 PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*") |
| 956 print "%10d total symbols" % len([c for c in code_map.AllCode()]) | 1005 print "%10d total symbols" % len([c for c in code_map.AllCode()]) |
| 957 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) | 1006 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) |
| 958 print "%9.2fs library processing time" % mmap_time | 1007 print "%9.2fs library processing time" % mmap_time |
| 959 print "%9.2fs tick processing time" % sample_time | 1008 print "%9.2fs tick processing time" % sample_time |
| 960 | 1009 |
| 961 log_reader.Dispose() | 1010 log_reader.Dispose() |
| 962 trace_reader.Dispose() | 1011 trace_reader.Dispose() |
| OLD | NEW |