| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 | 61 |
| 62 # Print flat profile with annotated disassembly for all used symbols. | 62 # Print flat profile with annotated disassembly for all used symbols. |
| 63 # Use default log names and include kernel symbols into analysis. | 63 # Use default log names and include kernel symbols into analysis. |
| 64 $ %prog --disasm-all --kernel | 64 $ %prog --disasm-all --kernel |
| 65 | 65 |
| 66 # Print flat profile. Use custom log names. | 66 # Print flat profile. Use custom log names. |
| 67 $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot | 67 $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot |
| 68 """ | 68 """ |
| 69 | 69 |
| 70 | 70 |
| 71 # Must match kGcFakeMmap. | |
| 72 V8_GC_FAKE_MMAP = "/tmp/__v8_gc__" | |
| 73 | |
| 74 JS_ORIGIN = "js" | 71 JS_ORIGIN = "js" |
| 75 JS_SNAPSHOT_ORIGIN = "js-snapshot" | 72 JS_SNAPSHOT_ORIGIN = "js-snapshot" |
| 76 | 73 |
| 77 OBJDUMP_BIN = disasm.OBJDUMP_BIN | |
| 78 | |
| 79 | |
| 80 class Code(object): | 74 class Code(object): |
| 81 """Code object.""" | 75 """Code object.""" |
| 82 | 76 |
| 83 _id = 0 | 77 _id = 0 |
| 84 | 78 |
| 85 def __init__(self, name, start_address, end_address, origin, origin_offset): | 79 def __init__(self, name, start_address, end_address, origin, origin_offset): |
| 86 self.id = Code._id | 80 self.id = Code._id |
| 87 Code._id += 1 | 81 Code._id += 1 |
| 88 self.name = name | 82 self.name = name |
| 89 self.other_names = None | 83 self.other_names = None |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset) | 626 header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset) |
| 633 self.offset += header.size | 627 self.offset += header.size |
| 634 return header, offset | 628 return header, offset |
| 635 | 629 |
| 636 def ReadMmap(self, header, offset): | 630 def ReadMmap(self, header, offset): |
| 637 mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace, | 631 mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace, |
| 638 offset + self.header_size) | 632 offset + self.header_size) |
| 639 # Read null-terminated filename. | 633 # Read null-terminated filename. |
| 640 filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): | 634 filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): |
| 641 offset + header.size] | 635 offset + header.size] |
| 642 mmap_info.filename = filename[:filename.find(chr(0))] | 636 mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))] |
| 643 return mmap_info | 637 return mmap_info |
| 644 | 638 |
| 645 def ReadSample(self, header, offset): | 639 def ReadSample(self, header, offset): |
| 646 sample = self.sample_event_body_desc.Read(self.trace, | 640 sample = self.sample_event_body_desc.Read(self.trace, |
| 647 offset + self.header_size) | 641 offset + self.header_size) |
| 648 if not self.callchain_supported: | 642 if not self.callchain_supported: |
| 649 return sample | 643 return sample |
| 650 sample.ips = [] | 644 sample.ips = [] |
| 651 offset += self.header_size + ctypes.sizeof(sample) | 645 offset += self.header_size + ctypes.sizeof(sample) |
| 652 for _ in xrange(sample.nr): | 646 for _ in xrange(sample.nr): |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 help=("disassemble and annotate all used symbols " | 845 help=("disassemble and annotate all used symbols " |
| 852 "[default: %default]")) | 846 "[default: %default]")) |
| 853 parser.add_option("--dot", | 847 parser.add_option("--dot", |
| 854 default=False, | 848 default=False, |
| 855 action="store_true", | 849 action="store_true", |
| 856 help="produce dot output (WIP) [default: %default]") | 850 help="produce dot output (WIP) [default: %default]") |
| 857 parser.add_option("--quiet", "-q", | 851 parser.add_option("--quiet", "-q", |
| 858 default=False, | 852 default=False, |
| 859 action="store_true", | 853 action="store_true", |
| 860 help="no auxiliary messages [default: %default]") | 854 help="no auxiliary messages [default: %default]") |
| 855 parser.add_option("--gc-fake-mmap", |
| 856 default="/tmp/__v8_gc__", |
| 857 help="gc fake mmap file [default: %default]") |
| 858 parser.add_option("--objdump", |
| 859 default="/usr/bin/objdump", |
| 860 help="objdump tool to use [default: %default]") |
| 861 parser.add_option("--host-root", |
| 862 default="", |
| 863 help="Path to the host root [default: %default]") |
| 861 options, args = parser.parse_args() | 864 options, args = parser.parse_args() |
| 862 | 865 |
| 863 if not options.quiet: | 866 if not options.quiet: |
| 864 if options.snapshot: | 867 if options.snapshot: |
| 865 print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log, | 868 print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log, |
| 866 options.log, | 869 options.log, |
| 867 options.log) | 870 options.log) |
| 868 else: | 871 else: |
| 869 print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log) | 872 print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log) |
| 870 print "Perf trace file: %s" % options.trace | 873 print "Perf trace file: %s" % options.trace |
| 871 | 874 |
| 875 V8_GC_FAKE_MMAP = options.gc_fake_mmap |
| 876 HOST_ROOT = options.host_root |
| 877 if os.path.exists(options.objdump): |
| 878 disasm.OBJDUMP_BIN = options.objdump |
| 879 OBJDUMP_BIN = options.objdump |
| 880 else: |
| 881 print "Cannot find %s, falling back to default objdump" % options.objdump |
| 882 |
| 872 # Stats. | 883 # Stats. |
| 873 events = 0 | 884 events = 0 |
| 874 ticks = 0 | 885 ticks = 0 |
| 875 missed_ticks = 0 | 886 missed_ticks = 0 |
| 876 really_missed_ticks = 0 | 887 really_missed_ticks = 0 |
| 877 mmap_time = 0 | 888 mmap_time = 0 |
| 878 sample_time = 0 | 889 sample_time = 0 |
| 879 | 890 |
| 880 # Process the snapshot log to fill the snapshot name map. | 891 # Process the snapshot log to fill the snapshot name map. |
| 881 snapshot_name_map = {} | 892 snapshot_name_map = {} |
| (...skipping 16 matching lines...) Expand all Loading... |
| 898 log_reader.ReadUpToGC() | 909 log_reader.ReadUpToGC() |
| 899 trace_reader = TraceReader(options.trace) | 910 trace_reader = TraceReader(options.trace) |
| 900 while True: | 911 while True: |
| 901 header, offset = trace_reader.ReadEventHeader() | 912 header, offset = trace_reader.ReadEventHeader() |
| 902 if not header: | 913 if not header: |
| 903 break | 914 break |
| 904 events += 1 | 915 events += 1 |
| 905 if header.type == PERF_RECORD_MMAP: | 916 if header.type == PERF_RECORD_MMAP: |
| 906 start = time.time() | 917 start = time.time() |
| 907 mmap_info = trace_reader.ReadMmap(header, offset) | 918 mmap_info = trace_reader.ReadMmap(header, offset) |
| 908 if mmap_info.filename == V8_GC_FAKE_MMAP: | 919 if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP: |
| 909 log_reader.ReadUpToGC() | 920 log_reader.ReadUpToGC() |
| 910 else: | 921 else: |
| 911 library_repo.Load(mmap_info, code_map, options) | 922 library_repo.Load(mmap_info, code_map, options) |
| 912 mmap_time += time.time() - start | 923 mmap_time += time.time() - start |
| 913 elif header.type == PERF_RECORD_SAMPLE: | 924 elif header.type == PERF_RECORD_SAMPLE: |
| 914 ticks += 1 | 925 ticks += 1 |
| 915 start = time.time() | 926 start = time.time() |
| 916 sample = trace_reader.ReadSample(header, offset) | 927 sample = trace_reader.ReadSample(header, offset) |
| 917 code = code_map.Find(sample.ip) | 928 code = code_map.Find(sample.ip) |
| 918 if code: | 929 if code: |
| (...skipping 23 matching lines...) Expand all Loading... |
| 942 print "%10d total ticks" % ticks | 953 print "%10d total ticks" % ticks |
| 943 print "%10d ticks not in symbols" % missed_ticks | 954 print "%10d ticks not in symbols" % missed_ticks |
| 944 print "%10d unaccounted ticks" % really_missed_ticks | 955 print "%10d unaccounted ticks" % really_missed_ticks |
| 945 print "%10d total symbols" % len([c for c in code_map.AllCode()]) | 956 print "%10d total symbols" % len([c for c in code_map.AllCode()]) |
| 946 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) | 957 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) |
| 947 print "%9.2fs library processing time" % mmap_time | 958 print "%9.2fs library processing time" % mmap_time |
| 948 print "%9.2fs tick processing time" % sample_time | 959 print "%9.2fs tick processing time" % sample_time |
| 949 | 960 |
| 950 log_reader.Dispose() | 961 log_reader.Dispose() |
| 951 trace_reader.Dispose() | 962 trace_reader.Dispose() |
| OLD | NEW |