OLD | NEW |
---|---|
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <!-- | 2 <!-- |
3 Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
5 found in the LICENSE file. | 5 found in the LICENSE file. |
6 --> | 6 --> |
7 | 7 |
8 <link rel="import" href="/tracing/ui/base/color_scheme.html"> | |
9 <link rel="import" href="/tracing/base/quad.html"> | 8 <link rel="import" href="/tracing/base/quad.html"> |
10 <link rel="import" href="/tracing/base/range.html"> | 9 <link rel="import" href="/tracing/base/range.html"> |
11 <link rel="import" href="/tracing/base/utils.html"> | 10 <link rel="import" href="/tracing/base/utils.html"> |
12 <link rel="import" href="/tracing/base/units/time.html"> | 11 <link rel="import" href="/tracing/base/units/time.html"> |
12 <link rel="import" href="/tracing/extras/importer/trace_code_entry.html"> | |
13 <link rel="import" href="/tracing/extras/importer/v8/codemap.html"> | |
13 <link rel="import" href="/tracing/importer/importer.html"> | 14 <link rel="import" href="/tracing/importer/importer.html"> |
14 <link rel="import" href="/tracing/model/attribute.html"> | 15 <link rel="import" href="/tracing/model/attribute.html"> |
15 <link rel="import" href="/tracing/model/comment_box_annotation.html"> | 16 <link rel="import" href="/tracing/model/comment_box_annotation.html"> |
16 <link rel="import" href="/tracing/model/instant_event.html"> | 17 <link rel="import" href="/tracing/model/instant_event.html"> |
17 <link rel="import" href="/tracing/model/flow_event.html"> | 18 <link rel="import" href="/tracing/model/flow_event.html"> |
18 <link rel="import" href="/tracing/model/counter_series.html"> | 19 <link rel="import" href="/tracing/model/counter_series.html"> |
19 <link rel="import" href="/tracing/model/slice_group.html"> | 20 <link rel="import" href="/tracing/model/slice_group.html"> |
20 <link rel="import" href="/tracing/model/global_memory_dump.html"> | 21 <link rel="import" href="/tracing/model/global_memory_dump.html"> |
21 <link rel="import" href="/tracing/model/memory_allocator_dump.html"> | 22 <link rel="import" href="/tracing/model/memory_allocator_dump.html"> |
22 <link rel="import" href="/tracing/model/process_memory_dump.html"> | 23 <link rel="import" href="/tracing/model/process_memory_dump.html"> |
23 <link rel="import" href="/tracing/model/rect_annotation.html"> | 24 <link rel="import" href="/tracing/model/rect_annotation.html"> |
24 <link rel="import" href="/tracing/model/x_marker_annotation.html"> | 25 <link rel="import" href="/tracing/model/x_marker_annotation.html"> |
25 <link rel="import" href="/tracing/model/model.html"> | 26 <link rel="import" href="/tracing/model/model.html"> |
27 <link rel="import" href="/tracing/ui/base/color_scheme.html"> | |
26 | 28 |
27 <script> | 29 <script> |
28 'use strict'; | 30 'use strict'; |
29 | 31 |
30 /** | 32 /** |
31 * @fileoverview TraceEventImporter imports TraceEvent-formatted data | 33 * @fileoverview TraceEventImporter imports TraceEvent-formatted data |
32 * into the provided model. | 34 * into the provided model. |
33 */ | 35 */ |
34 tr.exportTo('tr.e.importer', function() { | 36 tr.exportTo('tr.e.importer', function() { |
35 | |
36 var Importer = tr.importer.Importer; | 37 var Importer = tr.importer.Importer; |
37 | |
38 var deepCopy = tr.b.deepCopy; | 38 var deepCopy = tr.b.deepCopy; |
39 | 39 |
40 function getEventColor(event, opt_customName) { | 40 function getEventColor(event, opt_customName) { |
41 if (event.cname) | 41 if (event.cname) |
42 return tr.ui.b.getColorIdForReservedName(event.cname); | 42 return tr.ui.b.getColorIdForReservedName(event.cname); |
43 else if (opt_customName || event.name) { | 43 else if (opt_customName || event.name) { |
44 return tr.ui.b.getColorIdForGeneralPurposeString( | 44 return tr.ui.b.getColorIdForGeneralPurposeString( |
45 opt_customName || event.name); | 45 opt_customName || event.name); |
46 } | 46 } |
47 } | 47 } |
48 | 48 |
49 var timestampFromUs = tr.b.units.Time.timestampFromUs; | 49 var timestampFromUs = tr.b.units.Time.timestampFromUs; |
50 var maybeTimestampFromUs = tr.b.units.Time.maybeTimestampFromUs; | 50 var maybeTimestampFromUs = tr.b.units.Time.maybeTimestampFromUs; |
51 | 51 |
52 function TraceEventImporter(model, eventData) { | 52 function TraceEventImporter(model, eventData) { |
53 this.importPriority = 1; | 53 this.importPriority = 1; |
54 this.model_ = model; | 54 this.model_ = model; |
55 this.events_ = undefined; | 55 this.events_ = undefined; |
56 this.sampleEvents_ = undefined; | 56 this.sampleEvents_ = undefined; |
57 this.stackFrameEvents_ = undefined; | 57 this.stackFrameEvents_ = undefined; |
58 this.systemTraceEvents_ = undefined; | 58 this.systemTraceEvents_ = undefined; |
59 this.battorData_ = undefined; | 59 this.battorData_ = undefined; |
60 this.eventsWereFromString_ = false; | 60 this.eventsWereFromString_ = false; |
61 this.softwareMeasuredCpuCount_ = undefined; | 61 this.softwareMeasuredCpuCount_ = undefined; |
62 | |
62 this.allAsyncEvents_ = []; | 63 this.allAsyncEvents_ = []; |
63 this.allFlowEvents_ = []; | 64 this.allFlowEvents_ = []; |
64 this.allObjectEvents_ = []; | 65 this.allObjectEvents_ = []; |
66 | |
65 this.traceEventSampleStackFramesByName_ = {}; | 67 this.traceEventSampleStackFramesByName_ = {}; |
66 | 68 |
69 this.v8ProcessCodeMaps_ = {}; | |
70 this.v8ProcessRootStackFrame_ = {}; | |
71 | |
67 // Dump ID -> {global: (event | undefined), process: [events]} | 72 // Dump ID -> {global: (event | undefined), process: [events]} |
68 this.allMemoryDumpEvents_ = {}; | 73 this.allMemoryDumpEvents_ = {}; |
69 | 74 |
70 if (typeof(eventData) === 'string' || eventData instanceof String) { | 75 if (typeof(eventData) === 'string' || eventData instanceof String) { |
71 eventData = eventData.trim(); | 76 eventData = eventData.trim(); |
72 // If the event data begins with a [, then we know it should end with a ]. | 77 // If the event data begins with a [, then we know it should end with a ]. |
73 // The reason we check for this is because some tracing implementations | 78 // The reason we check for this is because some tracing implementations |
74 // cannot guarantee that a ']' gets written to the trace file. So, we are | 79 // cannot guarantee that a ']' gets written to the trace file. So, we are |
75 // forgiving and if this is obviously the case, we fix it up before | 80 // forgiving and if this is obviously the case, we fix it up before |
76 // throwing the string at JSON.parse. | 81 // throwing the string at JSON.parse. |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
394 n = Math.max(n, this.softwareMeasuredCpuCount_); | 399 n = Math.max(n, this.softwareMeasuredCpuCount_); |
395 this.softwareMeasuredCpuCount_ = n; | 400 this.softwareMeasuredCpuCount_ = n; |
396 } else { | 401 } else { |
397 this.model_.importWarning({ | 402 this.model_.importWarning({ |
398 type: 'metadata_parse_error', | 403 type: 'metadata_parse_error', |
399 message: 'Unrecognized metadata name: ' + event.name | 404 message: 'Unrecognized metadata name: ' + event.name |
400 }); | 405 }); |
401 } | 406 } |
402 }, | 407 }, |
403 | 408 |
409 processJitCodeEvent: function(event) { | |
410 if (this.v8ProcessCodeMaps_[event.pid] === undefined) | |
411 this.v8ProcessCodeMaps_[event.pid] = new tr.e.importer.v8.CodeMap(); | |
412 var map = this.v8ProcessCodeMaps_[event.pid]; | |
413 | |
414 var data = event.args.data; | |
415 var startAddr = parseInt(data.code_start, 16); | |
416 if (event.name === 'JitCodeMoved') { | |
417 try { | |
418 map.moveCode(startAddr, parseInt(data.new_code_start, 16)); | |
419 } catch (err) { | |
420 // Ignore moved error. Means we didn't find the original block. | |
421 // We won't know the name if we try to insert the code here. | |
422 } | |
423 } else { | |
424 map.addCode(startAddr, | |
425 new tr.e.importer.TraceCodeEntry(data.code_len, data.name)); | |
426 } | |
427 }, | |
428 | |
404 processInstantEvent: function(event) { | 429 processInstantEvent: function(event) { |
430 // V8 JIT events are logged as phase 'I' so we need to separate them out | |
431 // and handle specially. | |
432 // | |
433 // TODO(dsinclair): There are _a lot_ of JitCode events so I'm skipping | |
434 // the display for now. Can revisit later if we want to show them. | |
435 if (event.name === 'JitCodeAdded' || event.name === 'JitCodeMoved') { | |
436 this.processJitCodeEvent(event); | |
437 return; | |
438 } | |
439 | |
405 // Thread-level instant events are treated as zero-duration slices. | 440 // Thread-level instant events are treated as zero-duration slices. |
406 if (event.s == 't' || event.s === undefined) { | 441 if (event.s == 't' || event.s === undefined) { |
407 this.processDurationEvent(event); | 442 this.processDurationEvent(event); |
408 return; | 443 return; |
409 } | 444 } |
410 | 445 |
411 var constructor; | 446 var constructor; |
412 switch (event.s) { | 447 switch (event.s) { |
413 case 'g': | 448 case 'g': |
414 constructor = tr.model.GlobalInstantEvent; | 449 constructor = tr.model.GlobalInstantEvent; |
(...skipping 21 matching lines...) Expand all Loading... | |
436 case tr.model.InstantEventType.PROCESS: | 471 case tr.model.InstantEventType.PROCESS: |
437 var process = this.model_.getOrCreateProcess(event.pid); | 472 var process = this.model_.getOrCreateProcess(event.pid); |
438 process.pushInstantEvent(instantEvent); | 473 process.pushInstantEvent(instantEvent); |
439 break; | 474 break; |
440 | 475 |
441 default: | 476 default: |
442 throw new Error('Unknown instant event type: ' + event.s); | 477 throw new Error('Unknown instant event type: ' + event.s); |
443 } | 478 } |
444 }, | 479 }, |
445 | 480 |
446 processTraceSampleEvent: function(event) { | 481 processV8Sample: function(event) { |
482 var stack = []; | |
petrcermak
2015/08/13 15:15:56
nit: It seems to me that there is no need to decla
dsinclair
2015/08/13 15:43:38
Actually, I don't need this at all anymore. I was
| |
483 var data = event.args.data; | |
484 | |
485 var rootStackFrame = this.v8ProcessRootStackFrame_[event.pid]; | |
486 if (!rootStackFrame) { | |
487 rootStackFrame = new tr.model.StackFrame( | |
488 undefined /* parent */, 'v8-root-stack-frame' /* id */, | |
489 'v8' /* category */, 'v8-root-stack-frame' /* title */, | |
490 0 /* colorId */); | |
491 this.v8ProcessRootStackFrame_[event.pid] = rootStackFrame; | |
492 } | |
493 | |
494 var findChildWithEntryID = function(stackFrame, entryID) { | |
petrcermak
2015/08/13 15:15:56
nit: I think that the following is preferred:
fun
dsinclair
2015/08/13 15:43:38
Done.
| |
495 return tr.b.findFirstInArray(stackFrame.children, function(child) { | |
496 return child.entryID === entryID; | |
497 }); | |
498 } | |
499 | |
500 var addStackFrame = function(lastStackFrame, entry) { | |
petrcermak
2015/08/13 15:15:56
ditto
dsinclair
2015/08/13 15:43:38
Acknowledged.
| |
501 var childFrame = findChildWithEntryID(lastStackFrame, entry.id); | |
502 if (childFrame) | |
503 return childFrame; | |
504 | |
505 var frame = new tr.model.StackFrame( | |
506 lastStackFrame, tr.b.GUID.allocate(), | |
507 'v8', entry.name, | |
508 tr.ui.b.getColorIdForGeneralPurposeString(entry.name), | |
509 entry.sourceInfo); | |
510 | |
511 frame.entryID = entry.id; | |
512 this.model_.addStackFrame(frame); | |
513 return frame; | |
514 }.bind(this); | |
515 | |
516 var lastStackFrame = rootStackFrame; | |
517 | |
518 // There are several types of v8 sample events, gc, native, compiler, etc. | |
519 // Some of these types have stacks and some dones, we handle those two | |
petrcermak
2015/08/13 15:15:56
s/dones/don't/ ?
dsinclair
2015/08/13 15:43:38
I .... don't know what that was supposed to be ...
| |
520 // cases differently. For types that don't have any stack frames attached | |
521 // we synthesize one base on the type of thing that's happening so when | |
petrcermak
2015/08/13 15:15:56
nit: s/base/based/
dsinclair
2015/08/13 15:43:38
Done.
| |
522 // we view all the samples we'll see something like 'external' or 'gc' | |
523 // as a fraction of the time spent. | |
524 if (data.stack.length > 0 && | |
525 this.v8ProcessCodeMaps_[event.pid]) { | |
petrcermak
2015/08/13 15:15:56
nit: I think that this will fit on the previous li
dsinclair
2015/08/13 15:43:38
Done.
| |
526 | |
527 var map = this.v8ProcessCodeMaps_[event.pid]; | |
528 | |
529 // Stacks have the leaf node first, flip them around so the root | |
530 // comes first. | |
531 data.stack.reverse(); | |
532 | |
533 for (var i = 0; i < data.stack.length; i++) { | |
petrcermak
2015/08/13 15:15:56
Observation: I've just realized that this function
dsinclair
2015/08/13 15:43:38
I actually removed the stack assignments.
| |
534 var addr = parseInt(data.stack[i], 16); | |
535 var entry = map.findEntry(addr); | |
536 | |
537 if (entry === null) { | |
538 entry = { | |
539 id: 'unknown', | |
540 name: 'unknown', | |
541 sourceInfo: undefined | |
542 }; | |
543 } | |
544 | |
545 lastStackFrame = addStackFrame(lastStackFrame, entry); | |
546 stack.push(entry); | |
547 } | |
548 } else { | |
549 var entry = { | |
550 id: data.vm_state, | |
551 name: data.vm_state, | |
552 sourceInfo: undefined | |
553 }; | |
554 lastStackFrame = addStackFrame(lastStackFrame, entry); | |
555 } | |
556 | |
447 var thread = this.model_.getOrCreateProcess(event.pid) | 557 var thread = this.model_.getOrCreateProcess(event.pid) |
448 .getOrCreateThread(event.tid); | 558 .getOrCreateThread(event.tid); |
449 | 559 |
560 var sample = new tr.model.Sample( | |
561 undefined /* cpu */, thread, 'V8 Sample', | |
562 timestampFromUs(event.ts), lastStackFrame, 1 /* weight */, | |
563 this.deepCopyIfNeeded_(event.args)); | |
564 this.model_.samples.push(sample); | |
565 }, | |
566 | |
567 processTraceSampleEvent: function(event) { | |
568 if (event.name === 'V8Sample') { | |
569 this.processV8Sample(event); | |
570 return; | |
571 } | |
572 | |
450 var stackFrame = this.getStackFrameForEvent_(event); | 573 var stackFrame = this.getStackFrameForEvent_(event); |
451 if (stackFrame === undefined) { | 574 if (stackFrame === undefined) { |
452 stackFrame = this.traceEventSampleStackFramesByName_[ | 575 stackFrame = this.traceEventSampleStackFramesByName_[ |
453 event.name]; | 576 event.name]; |
454 } | 577 } |
455 if (stackFrame === undefined) { | 578 if (stackFrame === undefined) { |
456 var id = 'te-' + tr.b.GUID.allocate(); | 579 var id = 'te-' + tr.b.GUID.allocate(); |
457 stackFrame = new tr.model.StackFrame( | 580 stackFrame = new tr.model.StackFrame( |
458 undefined, id, | 581 undefined, id, |
459 event.cat, event.name, | 582 event.cat, event.name, |
460 tr.ui.b.getColorIdForGeneralPurposeString(event.name)); | 583 tr.ui.b.getColorIdForGeneralPurposeString(event.name)); |
461 this.model_.addStackFrame(stackFrame); | 584 this.model_.addStackFrame(stackFrame); |
462 this.traceEventSampleStackFramesByName_[event.name] = stackFrame; | 585 this.traceEventSampleStackFramesByName_[event.name] = stackFrame; |
463 } | 586 } |
464 | 587 |
588 var thread = this.model_.getOrCreateProcess(event.pid) | |
589 .getOrCreateThread(event.tid); | |
590 | |
465 var sample = new tr.model.Sample( | 591 var sample = new tr.model.Sample( |
466 undefined, thread, 'TRACE_EVENT_SAMPLE', | 592 undefined, thread, 'Trace Event Sample', |
467 timestampFromUs(event.ts), stackFrame, 1, | 593 timestampFromUs(event.ts), stackFrame, 1, |
468 this.deepCopyIfNeeded_(event.args)); | 594 this.deepCopyIfNeeded_(event.args)); |
469 this.model_.samples.push(sample); | 595 this.model_.samples.push(sample); |
470 }, | 596 }, |
471 | 597 |
472 getOrCreateMemoryDumpEvents_: function(dumpId) { | 598 getOrCreateMemoryDumpEvents_: function(dumpId) { |
473 if (this.allMemoryDumpEvents_[dumpId] === undefined) { | 599 if (this.allMemoryDumpEvents_[dumpId] === undefined) { |
474 this.allMemoryDumpEvents_[dumpId] = { | 600 this.allMemoryDumpEvents_[dumpId] = { |
475 global: undefined, | 601 global: undefined, |
476 process: [] | 602 process: [] |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
563 this.processMemoryDumpEvent(event); | 689 this.processMemoryDumpEvent(event); |
564 | 690 |
565 } else { | 691 } else { |
566 this.model_.importWarning({ | 692 this.model_.importWarning({ |
567 type: 'parse_error', | 693 type: 'parse_error', |
568 message: 'Unrecognized event phase: ' + | 694 message: 'Unrecognized event phase: ' + |
569 event.ph + ' (' + event.name + ')' | 695 event.ph + ' (' + event.name + ')' |
570 }); | 696 }); |
571 } | 697 } |
572 } | 698 } |
699 | |
700 // Remove all the root stack frame children as they should | |
701 // already be added. | |
702 tr.b.iterItems(this.v8ProcessRootStackFrame_, function(name, frame) { | |
703 frame.removeAllChildren(); | |
704 }); | |
573 }, | 705 }, |
574 | 706 |
575 importStackFrames_: function() { | 707 importStackFrames_: function() { |
576 var m = this.model_; | 708 var m = this.model_; |
577 var events = this.stackFrameEvents_; | 709 var events = this.stackFrameEvents_; |
578 | 710 |
579 for (var id in events) { | 711 for (var id in events) { |
580 var event = events[id]; | 712 var event = events[id]; |
581 var textForColor = event.category ? event.category : event.name; | 713 var textForColor = event.category ? event.category : event.name; |
582 var frame = new tr.model.StackFrame( | 714 var frame = new tr.model.StackFrame( |
(...skipping 1363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1946 } | 2078 } |
1947 }; | 2079 }; |
1948 | 2080 |
1949 tr.importer.Importer.register(TraceEventImporter); | 2081 tr.importer.Importer.register(TraceEventImporter); |
1950 | 2082 |
1951 return { | 2083 return { |
1952 TraceEventImporter: TraceEventImporter | 2084 TraceEventImporter: TraceEventImporter |
1953 }; | 2085 }; |
1954 }); | 2086 }); |
1955 </script> | 2087 </script> |
OLD | NEW |