OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2010 the V8 project authors. All rights reserved. | 3 # Copyright 2010 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 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 if self.self_ticks_map is None: | 117 if self.self_ticks_map is None: |
118 self.self_ticks_map = collections.defaultdict(lambda: 0) | 118 self.self_ticks_map = collections.defaultdict(lambda: 0) |
119 offset = pc - self.start_address | 119 offset = pc - self.start_address |
120 self.self_ticks_map[offset] += 1 | 120 self.self_ticks_map[offset] += 1 |
121 | 121 |
122 def CalleeTick(self, callee): | 122 def CalleeTick(self, callee): |
123 if self.callee_ticks is None: | 123 if self.callee_ticks is None: |
124 self.callee_ticks = collections.defaultdict(lambda: 0) | 124 self.callee_ticks = collections.defaultdict(lambda: 0) |
125 self.callee_ticks[callee] += 1 | 125 self.callee_ticks[callee] += 1 |
126 | 126 |
127 def PrintAnnotated(self, code_info, options): | 127 def PrintAnnotated(self, arch, options): |
128 if self.self_ticks_map is None: | 128 if self.self_ticks_map is None: |
129 ticks_map = [] | 129 ticks_map = [] |
130 else: | 130 else: |
131 ticks_map = self.self_ticks_map.items() | 131 ticks_map = self.self_ticks_map.items() |
132 # Convert the ticks map to offsets and counts arrays so that later | 132 # Convert the ticks map to offsets and counts arrays so that later |
133 # we can do binary search in the offsets array. | 133 # we can do binary search in the offsets array. |
134 ticks_map.sort(key=lambda t: t[0]) | 134 ticks_map.sort(key=lambda t: t[0]) |
135 ticks_offsets = [t[0] for t in ticks_map] | 135 ticks_offsets = [t[0] for t in ticks_map] |
136 ticks_counts = [t[1] for t in ticks_map] | 136 ticks_counts = [t[1] for t in ticks_map] |
137 # Get a list of disassembled lines and their addresses. | 137 # Get a list of disassembled lines and their addresses. |
138 lines = self._GetDisasmLines(code_info, options) | 138 lines = self._GetDisasmLines(arch, options) |
139 if len(lines) == 0: | 139 if len(lines) == 0: |
140 return | 140 return |
141 # Print annotated lines. | 141 # Print annotated lines. |
142 address = lines[0][0] | 142 address = lines[0][0] |
143 total_count = 0 | 143 total_count = 0 |
144 for i in xrange(len(lines)): | 144 for i in xrange(len(lines)): |
145 start_offset = lines[i][0] - address | 145 start_offset = lines[i][0] - address |
146 if i == len(lines) - 1: | 146 if i == len(lines) - 1: |
147 end_offset = self.end_address - self.start_address | 147 end_offset = self.end_address - self.start_address |
148 else: | 148 else: |
(...skipping 18 matching lines...) Expand all Loading... |
167 "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self) | 167 "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self) |
168 | 168 |
169 def __str__(self): | 169 def __str__(self): |
170 return "%s [0x%x, 0x%x) size: %d origin: %s" % ( | 170 return "%s [0x%x, 0x%x) size: %d origin: %s" % ( |
171 self.name, | 171 self.name, |
172 self.start_address, | 172 self.start_address, |
173 self.end_address, | 173 self.end_address, |
174 self.end_address - self.start_address, | 174 self.end_address - self.start_address, |
175 self.origin) | 175 self.origin) |
176 | 176 |
177 def _GetDisasmLines(self, code_info, options): | 177 def _GetDisasmLines(self, arch, options): |
178 if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN: | 178 if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN: |
179 inplace = False | 179 inplace = False |
180 filename = options.log + ".code" | 180 filename = options.log + ".ll" |
181 else: | 181 else: |
182 inplace = True | 182 inplace = True |
183 filename = self.origin | 183 filename = self.origin |
184 return disasm.GetDisasmLines(filename, | 184 return disasm.GetDisasmLines(filename, |
185 self.origin_offset, | 185 self.origin_offset, |
186 self.end_address - self.start_address, | 186 self.end_address - self.start_address, |
187 code_info.arch, | 187 arch, |
188 inplace) | 188 inplace) |
189 | 189 |
190 | 190 |
191 class CodePage(object): | 191 class CodePage(object): |
192 """Group of adjacent code objects.""" | 192 """Group of adjacent code objects.""" |
193 | 193 |
194 SHIFT = 12 # 4K pages | 194 SHIFT = 12 # 4K pages |
195 SIZE = (1 << SHIFT) | 195 SIZE = (1 << SHIFT) |
196 MASK = ~(SIZE - 1) | 196 MASK = ~(SIZE - 1) |
197 | 197 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 | 297 |
298 | 298 |
299 class CodeInfo(object): | 299 class CodeInfo(object): |
300 """Generic info about generated code objects.""" | 300 """Generic info about generated code objects.""" |
301 | 301 |
302 def __init__(self, arch, header_size): | 302 def __init__(self, arch, header_size): |
303 self.arch = arch | 303 self.arch = arch |
304 self.header_size = header_size | 304 self.header_size = header_size |
305 | 305 |
306 | 306 |
307 class CodeLogReader(object): | 307 class SnapshotLogReader(object): |
308 """V8 code event log reader.""" | 308 """V8 snapshot log reader.""" |
309 | 309 |
310 _CODE_INFO_RE = re.compile( | 310 _SNAPSHOT_CODE_NAME_RE = re.compile( |
311 r"code-info,([^,]+),(\d+)") | 311 r"snapshot-code-name,(\d+),\"(.*)\"") |
312 | 312 |
313 _CODE_CREATE_RE = re.compile( | 313 def __init__(self, log_name): |
314 r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(0x[a-f0-9]+),([~*])
?)?(?:,(\d+))?") | 314 self.log_name = log_name |
315 | 315 |
316 _CODE_MOVE_RE = re.compile( | 316 def ReadNameMap(self): |
317 r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)") | 317 log = open(self.log_name, "r") |
| 318 try: |
| 319 snapshot_pos_to_name = {} |
| 320 for line in log: |
| 321 match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line) |
| 322 if match: |
| 323 pos = int(match.group(1)) |
| 324 name = match.group(2) |
| 325 snapshot_pos_to_name[pos] = name |
| 326 finally: |
| 327 log.close() |
| 328 return snapshot_pos_to_name |
318 | 329 |
319 _CODE_DELETE_RE = re.compile( | |
320 r"code-delete,(0x[a-f0-9]+)") | |
321 | 330 |
322 _SNAPSHOT_POS_RE = re.compile( | 331 class LogReader(object): |
323 r"snapshot-pos,(0x[a-f0-9]+),(\d+)") | 332 """V8 low-level (binary) log reader.""" |
324 | 333 |
325 _CODE_MOVING_GC = "code-moving-gc" | 334 _ARCH_TO_POINTER_TYPE_MAP = { |
| 335 "ia32": ctypes.c_uint32, |
| 336 "arm": ctypes.c_uint32, |
| 337 "x64": ctypes.c_uint64 |
| 338 } |
326 | 339 |
327 def __init__(self, log_name, code_map, is_snapshot, snapshot_pos_to_name): | 340 _CODE_CREATE_TAG = "C" |
328 self.log = open(log_name, "r") | 341 _CODE_MOVE_TAG = "M" |
| 342 _CODE_DELETE_TAG = "D" |
| 343 _SNAPSHOT_POSITION_TAG = "P" |
| 344 _CODE_MOVING_GC_TAG = "G" |
| 345 |
| 346 def __init__(self, log_name, code_map, snapshot_pos_to_name): |
| 347 self.log_file = open(log_name, "r") |
| 348 self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE) |
| 349 self.log_pos = 0 |
329 self.code_map = code_map | 350 self.code_map = code_map |
330 self.is_snapshot = is_snapshot | |
331 self.snapshot_pos_to_name = snapshot_pos_to_name | 351 self.snapshot_pos_to_name = snapshot_pos_to_name |
332 self.address_to_snapshot_name = {} | 352 self.address_to_snapshot_name = {} |
333 | 353 |
334 def ReadCodeInfo(self): | 354 self.arch = self.log[:self.log.find("\0")] |
335 line = self.log.readline() or "" | 355 self.log_pos += len(self.arch) + 1 |
336 match = CodeLogReader._CODE_INFO_RE.match(line) | 356 assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \ |
337 assert match, "No code info in log" | 357 "Unsupported architecture %s" % self.arch |
338 return CodeInfo(arch=match.group(1), header_size=int(match.group(2))) | 358 pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch] |
339 | 359 |
340 def ReadUpToGC(self, code_info): | 360 self.code_create_struct = LogReader._DefineStruct([ |
341 made_progress = False | 361 ("name_size", ctypes.c_int32), |
342 code_header_size = code_info.header_size | 362 ("code_address", pointer_type), |
343 while True: | 363 ("code_size", ctypes.c_int32)]) |
344 line = self.log.readline() | |
345 if not line: | |
346 return made_progress | |
347 made_progress = True | |
348 | 364 |
349 if line.startswith(CodeLogReader._CODE_MOVING_GC): | 365 self.code_move_struct = LogReader._DefineStruct([ |
| 366 ("from_address", pointer_type), |
| 367 ("to_address", pointer_type)]) |
| 368 |
| 369 self.code_delete_struct = LogReader._DefineStruct([ |
| 370 ("address", pointer_type)]) |
| 371 |
| 372 self.snapshot_position_struct = LogReader._DefineStruct([ |
| 373 ("address", pointer_type), |
| 374 ("position", ctypes.c_int32)]) |
| 375 |
| 376 def ReadUpToGC(self): |
| 377 while self.log_pos < self.log.size(): |
| 378 tag = self.log[self.log_pos] |
| 379 self.log_pos += 1 |
| 380 |
| 381 if tag == LogReader._CODE_MOVING_GC_TAG: |
350 self.address_to_snapshot_name.clear() | 382 self.address_to_snapshot_name.clear() |
351 return made_progress | 383 return |
352 | 384 |
353 match = CodeLogReader._CODE_CREATE_RE.match(line) | 385 if tag == LogReader._CODE_CREATE_TAG: |
354 if match: | 386 event = self.code_create_struct.from_buffer(self.log, self.log_pos) |
355 start_address = int(match.group(2), 16) + code_header_size | 387 self.log_pos += ctypes.sizeof(event) |
356 end_address = start_address + int(match.group(3)) - code_header_size | 388 start_address = event.code_address |
| 389 end_address = start_address + event.code_size |
357 if start_address in self.address_to_snapshot_name: | 390 if start_address in self.address_to_snapshot_name: |
358 name = self.address_to_snapshot_name[start_address] | 391 name = self.address_to_snapshot_name[start_address] |
359 origin = JS_SNAPSHOT_ORIGIN | 392 origin = JS_SNAPSHOT_ORIGIN |
360 else: | 393 else: |
361 tag = match.group(1) | 394 name = self.log[self.log_pos:self.log_pos + event.name_size] |
362 optimization_status = match.group(6) | |
363 func_name = match.group(4) | |
364 if optimization_status: | |
365 name = "%s:%s%s" % (tag, optimization_status, func_name) | |
366 else: | |
367 name = "%s:%s" % (tag, func_name) | |
368 origin = JS_ORIGIN | 395 origin = JS_ORIGIN |
369 if self.is_snapshot: | 396 self.log_pos += event.name_size |
370 origin_offset = 0 | 397 origin_offset = self.log_pos |
371 else: | 398 self.log_pos += event.code_size |
372 origin_offset = int(match.group(7)) | |
373 code = Code(name, start_address, end_address, origin, origin_offset) | 399 code = Code(name, start_address, end_address, origin, origin_offset) |
374 conficting_code = self.code_map.Find(start_address) | 400 conficting_code = self.code_map.Find(start_address) |
375 if conficting_code: | 401 if conficting_code: |
376 CodeLogReader._HandleCodeConflict(conficting_code, code) | 402 LogReader._HandleCodeConflict(conficting_code, code) |
377 # TODO(vitalyr): this warning is too noisy because of our | 403 # TODO(vitalyr): this warning is too noisy because of our |
378 # attempts to reconstruct code log from the snapshot. | 404 # attempts to reconstruct code log from the snapshot. |
379 # print >>sys.stderr, \ | 405 # print >>sys.stderr, \ |
380 # "Warning: Skipping duplicate code log entry %s" % code | 406 # "Warning: Skipping duplicate code log entry %s" % code |
381 continue | 407 continue |
382 self.code_map.Add(code) | 408 self.code_map.Add(code) |
383 continue | 409 continue |
384 | 410 |
385 match = CodeLogReader._CODE_MOVE_RE.match(line) | 411 if tag == LogReader._CODE_MOVE_TAG: |
386 if match: | 412 event = self.code_move_struct.from_buffer(self.log, self.log_pos) |
387 old_start_address = int(match.group(1), 16) + code_header_size | 413 self.log_pos += ctypes.sizeof(event) |
388 new_start_address = int(match.group(2), 16) + code_header_size | 414 old_start_address = event.from_address |
| 415 new_start_address = event.to_address |
389 if old_start_address == new_start_address: | 416 if old_start_address == new_start_address: |
390 # Skip useless code move entries. | 417 # Skip useless code move entries. |
391 continue | 418 continue |
392 code = self.code_map.Find(old_start_address) | 419 code = self.code_map.Find(old_start_address) |
393 if not code: | 420 if not code: |
394 print >>sys.stderr, "Warning: Not found %x" % old_start_address | 421 print >>sys.stderr, "Warning: Not found %x" % old_start_address |
395 continue | 422 continue |
396 assert code.start_address == old_start_address, \ | 423 assert code.start_address == old_start_address, \ |
397 "Inexact move address %x for %s" % (old_start_address, code) | 424 "Inexact move address %x for %s" % (old_start_address, code) |
398 self.code_map.Remove(code) | 425 self.code_map.Remove(code) |
399 size = code.end_address - code.start_address | 426 size = code.end_address - code.start_address |
400 code.start_address = new_start_address | 427 code.start_address = new_start_address |
401 code.end_address = new_start_address + size | 428 code.end_address = new_start_address + size |
402 self.code_map.Add(code) | 429 self.code_map.Add(code) |
403 continue | 430 continue |
404 | 431 |
405 match = CodeLogReader._CODE_DELETE_RE.match(line) | 432 if tag == LogReader._CODE_DELETE_TAG: |
406 if match: | 433 event = self.code_delete_struct.from_buffer(self.log, self.log_pos) |
407 old_start_address = int(match.group(1), 16) + code_header_size | 434 self.log_pos += ctypes.sizeof(event) |
| 435 old_start_address = event.address |
408 code = self.code_map.Find(old_start_address) | 436 code = self.code_map.Find(old_start_address) |
409 if not code: | 437 if not code: |
410 print >>sys.stderr, "Warning: Not found %x" % old_start_address | 438 print >>sys.stderr, "Warning: Not found %x" % old_start_address |
411 continue | 439 continue |
412 assert code.start_address == old_start_address, \ | 440 assert code.start_address == old_start_address, \ |
413 "Inexact delete address %x for %s" % (old_start_address, code) | 441 "Inexact delete address %x for %s" % (old_start_address, code) |
414 self.code_map.Remove(code) | 442 self.code_map.Remove(code) |
415 continue | 443 continue |
416 | 444 |
417 match = CodeLogReader._SNAPSHOT_POS_RE.match(line) | 445 if tag == LogReader._SNAPSHOT_POSITION_TAG: |
418 if match: | 446 event = self.snapshot_position_struct.from_buffer(self.log, |
419 start_address = int(match.group(1), 16) + code_header_size | 447 self.log_pos) |
420 snapshot_pos = int(match.group(2)) | 448 self.log_pos += ctypes.sizeof(event) |
421 if self.is_snapshot: | 449 start_address = event.address |
422 code = self.code_map.Find(start_address) | 450 snapshot_pos = event.position |
423 if code: | 451 if snapshot_pos in self.snapshot_pos_to_name: |
424 assert code.start_address == start_address, \ | 452 self.address_to_snapshot_name[start_address] = \ |
425 "Inexact snapshot address %x for %s" % (start_address, code) | 453 self.snapshot_pos_to_name[snapshot_pos] |
426 self.snapshot_pos_to_name[snapshot_pos] = code.name | 454 continue |
427 else: | 455 |
428 if snapshot_pos in self.snapshot_pos_to_name: | 456 assert False, "Unknown tag %s" % tag |
429 self.address_to_snapshot_name[start_address] = \ | |
430 self.snapshot_pos_to_name[snapshot_pos] | |
431 | 457 |
432 def Dispose(self): | 458 def Dispose(self): |
433 self.log.close() | 459 self.log.close() |
| 460 self.log_file.close() |
| 461 |
| 462 @staticmethod |
| 463 def _DefineStruct(fields): |
| 464 class Struct(ctypes.Structure): |
| 465 _fields_ = fields |
| 466 return Struct |
434 | 467 |
435 @staticmethod | 468 @staticmethod |
436 def _HandleCodeConflict(old_code, new_code): | 469 def _HandleCodeConflict(old_code, new_code): |
437 assert (old_code.start_address == new_code.start_address and | 470 assert (old_code.start_address == new_code.start_address and |
438 old_code.end_address == new_code.end_address), \ | 471 old_code.end_address == new_code.end_address), \ |
439 "Conficting code log entries %s and %s" % (old_code, new_code) | 472 "Conficting code log entries %s and %s" % (old_code, new_code) |
440 CodeLogReader._UpdateNames(old_code, new_code) | |
441 | |
442 @staticmethod | |
443 def _UpdateNames(old_code, new_code): | |
444 if old_code.name == new_code.name: | 473 if old_code.name == new_code.name: |
445 return | 474 return |
446 # Kludge: there are code objects with custom names that don't | |
447 # match their flags. | |
448 misnamed_code = set(["Builtin:CpuFeatures::Probe"]) | |
449 if old_code.name in misnamed_code: | |
450 return | |
451 # Code object may be shared by a few functions. Collect the full | 475 # Code object may be shared by a few functions. Collect the full |
452 # set of names. | 476 # set of names. |
453 old_code.AddName(new_code.name) | 477 old_code.AddName(new_code.name) |
454 | 478 |
455 | 479 |
456 class Descriptor(object): | 480 class Descriptor(object): |
457 """Descriptor of a structure in the binary trace log.""" | 481 """Descriptor of a structure in the binary trace log.""" |
458 | 482 |
459 CTYPE_MAP = { | 483 CTYPE_MAP = { |
460 "u16": ctypes.c_uint16, | 484 "u16": ctypes.c_uint16, |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 start_address = int(match.group(1), 16) | 773 start_address = int(match.group(1), 16) |
750 end_address = start_address | 774 end_address = start_address |
751 name = match.group(2) | 775 name = match.group(2) |
752 if code: | 776 if code: |
753 code.end_address = start_address | 777 code.end_address = start_address |
754 code_map.Add(code, 16) | 778 code_map.Add(code, 16) |
755 code = Code(name, start_address, end_address, "kernel", 0) | 779 code = Code(name, start_address, end_address, "kernel", 0) |
756 return True | 780 return True |
757 | 781 |
758 | 782 |
759 def PrintReport(code_map, library_repo, code_info, options): | 783 def PrintReport(code_map, library_repo, arch, options): |
760 print "Ticks per symbol:" | 784 print "Ticks per symbol:" |
761 used_code = [code for code in code_map.UsedCode()] | 785 used_code = [code for code in code_map.UsedCode()] |
762 used_code.sort(key=lambda x: x.self_ticks, reverse=True) | 786 used_code.sort(key=lambda x: x.self_ticks, reverse=True) |
763 for i, code in enumerate(used_code): | 787 for i, code in enumerate(used_code): |
764 print "%10d %s [%s]" % (code.self_ticks, code.FullName(), code.origin) | 788 print "%10d %s [%s]" % (code.self_ticks, code.FullName(), code.origin) |
765 if options.disasm_all or i < options.disasm_top: | 789 if options.disasm_all or i < options.disasm_top: |
766 code.PrintAnnotated(code_info, options) | 790 code.PrintAnnotated(arch, options) |
767 print | 791 print |
768 print "Ticks per library:" | 792 print "Ticks per library:" |
769 mmap_infos = [m for m in library_repo.infos] | 793 mmap_infos = [m for m in library_repo.infos] |
770 mmap_infos.sort(key=lambda m: m.ticks, reverse=True) | 794 mmap_infos.sort(key=lambda m: m.ticks, reverse=True) |
771 for mmap_info in mmap_infos: | 795 for mmap_info in mmap_infos: |
772 print "%10d %s" % (mmap_info.ticks, mmap_info.unique_name) | 796 print "%10d %s" % (mmap_info.ticks, mmap_info.unique_name) |
773 | 797 |
774 | 798 |
775 def PrintDot(code_map, options): | 799 def PrintDot(code_map, options): |
776 print "digraph G {" | 800 print "digraph G {" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
818 action="store_true", | 842 action="store_true", |
819 help="produce dot output (WIP) [default: %default]") | 843 help="produce dot output (WIP) [default: %default]") |
820 parser.add_option("--quiet", "-q", | 844 parser.add_option("--quiet", "-q", |
821 default=False, | 845 default=False, |
822 action="store_true", | 846 action="store_true", |
823 help="no auxiliary messages [default: %default]") | 847 help="no auxiliary messages [default: %default]") |
824 options, args = parser.parse_args() | 848 options, args = parser.parse_args() |
825 | 849 |
826 if not options.quiet: | 850 if not options.quiet: |
827 if options.snapshot: | 851 if options.snapshot: |
828 print "V8 logs: %s, %s, %s.code" % (options.snapshot_log, | 852 print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log, |
829 options.log, | 853 options.log, |
830 options.log) | 854 options.log) |
831 else: | 855 else: |
832 print "V8 log: %s, %s.code (no snapshot)" % (options.log, options.log) | 856 print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log) |
833 print "Perf trace file: %s" % options.trace | 857 print "Perf trace file: %s" % options.trace |
834 | 858 |
835 # Stats. | 859 # Stats. |
836 events = 0 | 860 events = 0 |
837 ticks = 0 | 861 ticks = 0 |
838 missed_ticks = 0 | 862 missed_ticks = 0 |
839 really_missed_ticks = 0 | 863 really_missed_ticks = 0 |
840 mmap_time = 0 | 864 mmap_time = 0 |
841 sample_time = 0 | 865 sample_time = 0 |
842 | 866 |
843 # Initialize the log reader and get the code info. | 867 # Process the snapshot log to fill the snapshot name map. |
| 868 snapshot_name_map = {} |
| 869 if options.snapshot: |
| 870 snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log) |
| 871 snapshot_name_map = snapshot_log_reader.ReadNameMap() |
| 872 |
| 873 # Initialize the log reader. |
844 code_map = CodeMap() | 874 code_map = CodeMap() |
845 snapshot_name_map = {} | 875 log_reader = LogReader(log_name=options.log + ".ll", |
846 log_reader = CodeLogReader(log_name=options.log, | 876 code_map=code_map, |
847 code_map=code_map, | 877 snapshot_pos_to_name=snapshot_name_map) |
848 is_snapshot=False, | |
849 snapshot_pos_to_name=snapshot_name_map) | |
850 code_info = log_reader.ReadCodeInfo() | |
851 if not options.quiet: | 878 if not options.quiet: |
852 print "Generated code architecture: %s" % code_info.arch | 879 print "Generated code architecture: %s" % log_reader.arch |
853 print | 880 print |
854 | 881 |
855 # Process the snapshot log to fill the snapshot name map. | |
856 if options.snapshot: | |
857 snapshot_log_reader = CodeLogReader(log_name=options.snapshot_log, | |
858 code_map=CodeMap(), | |
859 is_snapshot=True, | |
860 snapshot_pos_to_name=snapshot_name_map) | |
861 while snapshot_log_reader.ReadUpToGC(code_info): | |
862 pass | |
863 | |
864 # Process the code and trace logs. | 882 # Process the code and trace logs. |
865 library_repo = LibraryRepo() | 883 library_repo = LibraryRepo() |
866 log_reader.ReadUpToGC(code_info) | 884 log_reader.ReadUpToGC() |
867 trace_reader = TraceReader(options.trace) | 885 trace_reader = TraceReader(options.trace) |
868 while True: | 886 while True: |
869 header, offset = trace_reader.ReadEventHeader() | 887 header, offset = trace_reader.ReadEventHeader() |
870 if not header: | 888 if not header: |
871 break | 889 break |
872 events += 1 | 890 events += 1 |
873 if header.type == PERF_RECORD_MMAP: | 891 if header.type == PERF_RECORD_MMAP: |
874 start = time.time() | 892 start = time.time() |
875 mmap_info = trace_reader.ReadMmap(header, offset) | 893 mmap_info = trace_reader.ReadMmap(header, offset) |
876 if mmap_info.filename == V8_GC_FAKE_MMAP: | 894 if mmap_info.filename == V8_GC_FAKE_MMAP: |
877 log_reader.ReadUpToGC(code_info) | 895 log_reader.ReadUpToGC() |
878 else: | 896 else: |
879 library_repo.Load(mmap_info, code_map, options) | 897 library_repo.Load(mmap_info, code_map, options) |
880 mmap_time += time.time() - start | 898 mmap_time += time.time() - start |
881 elif header.type == PERF_RECORD_SAMPLE: | 899 elif header.type == PERF_RECORD_SAMPLE: |
882 ticks += 1 | 900 ticks += 1 |
883 start = time.time() | 901 start = time.time() |
884 sample = trace_reader.ReadSample(header, offset) | 902 sample = trace_reader.ReadSample(header, offset) |
885 code = code_map.Find(sample.ip) | 903 code = code_map.Find(sample.ip) |
886 if code: | 904 if code: |
887 code.Tick(sample.ip) | 905 code.Tick(sample.ip) |
888 else: | 906 else: |
889 missed_ticks += 1 | 907 missed_ticks += 1 |
890 if not library_repo.Tick(sample.ip) and not code: | 908 if not library_repo.Tick(sample.ip) and not code: |
891 really_missed_ticks += 1 | 909 really_missed_ticks += 1 |
892 if trace_reader.callchain_supported: | 910 if trace_reader.callchain_supported: |
893 for ip in sample.ips: | 911 for ip in sample.ips: |
894 caller_code = code_map.Find(ip) | 912 caller_code = code_map.Find(ip) |
895 if caller_code: | 913 if caller_code: |
896 if code: | 914 if code: |
897 caller_code.CalleeTick(code) | 915 caller_code.CalleeTick(code) |
898 code = caller_code | 916 code = caller_code |
899 sample_time += time.time() - start | 917 sample_time += time.time() - start |
900 | 918 |
901 if options.dot: | 919 if options.dot: |
902 PrintDot(code_map, options) | 920 PrintDot(code_map, options) |
903 else: | 921 else: |
904 PrintReport(code_map, library_repo, code_info, options) | 922 PrintReport(code_map, library_repo, log_reader.arch, options) |
905 | 923 |
906 if not options.quiet: | 924 if not options.quiet: |
907 print | 925 print |
908 print "Stats:" | 926 print "Stats:" |
909 print "%10d total trace events" % events | 927 print "%10d total trace events" % events |
910 print "%10d total ticks" % ticks | 928 print "%10d total ticks" % ticks |
911 print "%10d ticks not in symbols" % missed_ticks | 929 print "%10d ticks not in symbols" % missed_ticks |
912 print "%10d unaccounted ticks" % really_missed_ticks | 930 print "%10d unaccounted ticks" % really_missed_ticks |
913 print "%10d total symbols" % len([c for c in code_map.AllCode()]) | 931 print "%10d total symbols" % len([c for c in code_map.AllCode()]) |
914 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) | 932 print "%10d used symbols" % len([c for c in code_map.UsedCode()]) |
915 print "%9.2fs library processing time" % mmap_time | 933 print "%9.2fs library processing time" % mmap_time |
916 print "%9.2fs tick processing time" % sample_time | 934 print "%9.2fs tick processing time" % sample_time |
917 | 935 |
918 log_reader.Dispose() | 936 log_reader.Dispose() |
919 trace_reader.Dispose() | 937 trace_reader.Dispose() |
OLD | NEW |