Index: tracing/tracing/extras/importer/trace_event_importer.html |
diff --git a/tracing/tracing/extras/importer/trace_event_importer.html b/tracing/tracing/extras/importer/trace_event_importer.html |
index 6e24d4ac0866eb3fad6c2f5bbdfea7075e3e0f15..07acd2b894d5e2b7d19672b0168ec4c6d3ff8e49 100644 |
--- a/tracing/tracing/extras/importer/trace_event_importer.html |
+++ b/tracing/tracing/extras/importer/trace_event_importer.html |
@@ -5,11 +5,12 @@ Use of this source code is governed by a BSD-style license that can be |
found in the LICENSE file. |
--> |
-<link rel="import" href="/tracing/ui/base/color_scheme.html"> |
<link rel="import" href="/tracing/base/quad.html"> |
<link rel="import" href="/tracing/base/range.html"> |
<link rel="import" href="/tracing/base/utils.html"> |
<link rel="import" href="/tracing/base/units/time.html"> |
+<link rel="import" href="/tracing/extras/importer/trace_code_entry.html"> |
+<link rel="import" href="/tracing/extras/importer/v8/codemap.html"> |
<link rel="import" href="/tracing/importer/importer.html"> |
<link rel="import" href="/tracing/model/attribute.html"> |
<link rel="import" href="/tracing/model/comment_box_annotation.html"> |
@@ -23,6 +24,7 @@ found in the LICENSE file. |
<link rel="import" href="/tracing/model/rect_annotation.html"> |
<link rel="import" href="/tracing/model/x_marker_annotation.html"> |
<link rel="import" href="/tracing/model/model.html"> |
+<link rel="import" href="/tracing/ui/base/color_scheme.html"> |
<script> |
'use strict'; |
@@ -32,9 +34,7 @@ found in the LICENSE file. |
* into the provided model. |
*/ |
tr.exportTo('tr.e.importer', function() { |
- |
var Importer = tr.importer.Importer; |
- |
var deepCopy = tr.b.deepCopy; |
function getEventColor(event, opt_customName) { |
@@ -59,11 +59,16 @@ tr.exportTo('tr.e.importer', function() { |
this.battorData_ = undefined; |
this.eventsWereFromString_ = false; |
this.softwareMeasuredCpuCount_ = undefined; |
+ |
this.allAsyncEvents_ = []; |
this.allFlowEvents_ = []; |
this.allObjectEvents_ = []; |
+ |
this.traceEventSampleStackFramesByName_ = {}; |
+ this.v8ProcessCodeMaps_ = {}; |
+ this.v8ProcessRootStackFrame_ = {}; |
+ |
// Dump ID -> {global: (event | undefined), process: [events]} |
this.allMemoryDumpEvents_ = {}; |
@@ -401,7 +406,37 @@ tr.exportTo('tr.e.importer', function() { |
} |
}, |
+ processJitCodeEvent: function(event) { |
+ if (this.v8ProcessCodeMaps_[event.pid] === undefined) |
+ this.v8ProcessCodeMaps_[event.pid] = new tr.e.importer.v8.CodeMap(); |
+ var map = this.v8ProcessCodeMaps_[event.pid]; |
+ |
+ var data = event.args.data; |
+ var startAddr = parseInt(data.code_start, 16); |
+ if (event.name === 'JitCodeMoved') { |
+ try { |
+ map.moveCode(startAddr, parseInt(data.new_code_start, 16)); |
+ } catch (err) { |
+ // Ignore moved error. Means we didn't find the original block. |
+ // We won't know the name if we try to insert the code here. |
+ } |
+ } else { |
+ map.addCode(startAddr, |
+ new tr.e.importer.TraceCodeEntry(data.code_len, data.name)); |
+ } |
+ }, |
+ |
processInstantEvent: function(event) { |
+ // V8 JIT events are logged as phase 'I' so we need to separate them out |
+ // and handle specially. |
+ // |
+ // TODO(dsinclair): There are _a lot_ of JitCode events so I'm skipping |
+ // the display for now. Can revisit later if we want to show them. |
+ if (event.name === 'JitCodeAdded' || event.name === 'JitCodeMoved') { |
+ this.processJitCodeEvent(event); |
+ return; |
+ } |
+ |
// Thread-level instant events are treated as zero-duration slices. |
if (event.s == 't' || event.s === undefined) { |
this.processDurationEvent(event); |
@@ -443,10 +478,95 @@ tr.exportTo('tr.e.importer', function() { |
} |
}, |
- processTraceSampleEvent: function(event) { |
+ processV8Sample: function(event) { |
+ var data = event.args.data; |
+ |
+ var rootStackFrame = this.v8ProcessRootStackFrame_[event.pid]; |
+ if (!rootStackFrame) { |
+ rootStackFrame = new tr.model.StackFrame( |
+ undefined /* parent */, 'v8-root-stack-frame' /* id */, |
+ 'v8' /* category */, 'v8-root-stack-frame' /* title */, |
+ 0 /* colorId */); |
+ this.v8ProcessRootStackFrame_[event.pid] = rootStackFrame; |
+ } |
+ |
+ function findChildWithEntryID(stackFrame, entryID) { |
+ return tr.b.findFirstInArray(stackFrame.children, function(child) { |
+ return child.entryID === entryID; |
+ }); |
+ } |
+ |
+ var model = this.model_; |
+ function addStackFrame(lastStackFrame, entry) { |
+ var childFrame = findChildWithEntryID(lastStackFrame, entry.id); |
+ if (childFrame) |
+ return childFrame; |
+ |
+ var frame = new tr.model.StackFrame( |
+ lastStackFrame, tr.b.GUID.allocate(), |
+ 'v8', entry.name, |
+ tr.ui.b.getColorIdForGeneralPurposeString(entry.name), |
+ entry.sourceInfo); |
+ |
+ frame.entryID = entry.id; |
+ model.addStackFrame(frame); |
+ return frame; |
+ } |
+ |
+ var lastStackFrame = rootStackFrame; |
+ |
+ // There are several types of v8 sample events, gc, native, compiler, etc. |
+ // Some of these types have stacks and some don't, we handle those two |
+ // cases differently. For types that don't have any stack frames attached |
+ // we synthesize one based on the type of thing that's happening so when |
+ // we view all the samples we'll see something like 'external' or 'gc' |
+ // as a fraction of the time spent. |
+ if (data.stack.length > 0 && this.v8ProcessCodeMaps_[event.pid]) { |
+ var map = this.v8ProcessCodeMaps_[event.pid]; |
+ |
+ // Stacks have the leaf node first, flip them around so the root |
+ // comes first. |
+ data.stack.reverse(); |
+ |
+ for (var i = 0; i < data.stack.length; i++) { |
+ var addr = parseInt(data.stack[i], 16); |
+ var entry = map.findEntry(addr); |
+ |
+ if (entry === null) { |
+ entry = { |
+ id: 'unknown', |
+ name: 'unknown', |
+ sourceInfo: undefined |
+ }; |
+ } |
+ |
+ lastStackFrame = addStackFrame(lastStackFrame, entry); |
+ } |
+ } else { |
+ var entry = { |
+ id: data.vm_state, |
+ name: data.vm_state, |
+ sourceInfo: undefined |
+ }; |
+ lastStackFrame = addStackFrame(lastStackFrame, entry); |
+ } |
+ |
var thread = this.model_.getOrCreateProcess(event.pid) |
.getOrCreateThread(event.tid); |
+ var sample = new tr.model.Sample( |
+ undefined /* cpu */, thread, 'V8 Sample', |
+ timestampFromUs(event.ts), lastStackFrame, 1 /* weight */, |
+ this.deepCopyIfNeeded_(event.args)); |
+ this.model_.samples.push(sample); |
+ }, |
+ |
+ processTraceSampleEvent: function(event) { |
+ if (event.name === 'V8Sample') { |
+ this.processV8Sample(event); |
+ return; |
+ } |
+ |
var stackFrame = this.getStackFrameForEvent_(event); |
if (stackFrame === undefined) { |
stackFrame = this.traceEventSampleStackFramesByName_[ |
@@ -462,8 +582,11 @@ tr.exportTo('tr.e.importer', function() { |
this.traceEventSampleStackFramesByName_[event.name] = stackFrame; |
} |
+ var thread = this.model_.getOrCreateProcess(event.pid) |
+ .getOrCreateThread(event.tid); |
+ |
var sample = new tr.model.Sample( |
- undefined, thread, 'TRACE_EVENT_SAMPLE', |
+ undefined, thread, 'Trace Event Sample', |
timestampFromUs(event.ts), stackFrame, 1, |
this.deepCopyIfNeeded_(event.args)); |
this.model_.samples.push(sample); |
@@ -570,6 +693,12 @@ tr.exportTo('tr.e.importer', function() { |
}); |
} |
} |
+ |
+ // Remove all the root stack frame children as they should |
+ // already be added. |
+ tr.b.iterItems(this.v8ProcessRootStackFrame_, function(name, frame) { |
+ frame.removeAllChildren(); |
+ }); |
}, |
importStackFrames_: function() { |
@@ -860,7 +989,7 @@ tr.exportTo('tr.e.importer', function() { |
}); |
} else { |
// Include args for both END and BEGIN for a matched pair. |
- var concatenateArguments = function(args1, args2) { |
+ function concatenateArguments(args1, args2) { |
if (args1.params === undefined || args2.params === undefined) |
return tr.b.concatenateObjects(args1, args2); |
// Make an argument object to hold the combined params. |