3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
8 <link rel="import" href="/tracing/color_scheme.html">
9 <link rel="import" href="/tracing/importer/v8/log_reader.html">
10 <link rel="import" href="/tracing/importer/v8/codemap.html">
11 <link rel="import" href="/tracing/importer/importer.html">
12 <link rel="import" href="/tracing/trace_model.html">
13 <link rel="import" href="/tracing/trace_model/slice.html">
20 * @fileoverview V8LogImporter imports v8.log files into the provided model.
22 tvcm.exportTo('tracing.importer', function() {
23 var Importer = tracing.importer.Importer;
25 function V8LogImporter(model, eventData) {
26 this.importPriority = 3;
29 this.logData_ = eventData;
31 this.code_map_ = new tracing.importer.v8.CodeMap();
32 this.v8_timer_thread_ = undefined;
33 this.v8_thread_ = undefined;
35 this.root_stack_frame_ = new tracing.trace_model.StackFrame(
36 undefined, 'v8-root-stack-frame',
37 'v8-root-stack-frame', 'v8-root-stack-frame', 0);
39 // We reconstruct the stack timeline from ticks.
40 this.v8_stack_timeline_ = new Array();
43 var kV8BinarySuffixes = ['/d8', '/libv8.so'];
46 var TimerEventDefaultArgs = {
47 'V8.Execute': { pause: false, no_execution: false},
48 'V8.External': { pause: false, no_execution: true},
49 'V8.CompileFullCode': { pause: true, no_execution: true},
50 'V8.RecompileSynchronous': { pause: true, no_execution: true},
51 'V8.RecompileParallel': { pause: false, no_execution: false},
52 'V8.CompileEval': { pause: true, no_execution: true},
53 'V8.Parse': { pause: true, no_execution: true},
54 'V8.PreParse': { pause: true, no_execution: true},
55 'V8.ParseLazy': { pause: true, no_execution: true},
56 'V8.GCScavenger': { pause: true, no_execution: true},
57 'V8.GCCompactor': { pause: true, no_execution: true},
58 'V8.GCContext': { pause: true, no_execution: true}
62 * @return {boolean} Whether obj is a V8 log string.
64 V8LogImporter.canImport = function(eventData) {
65 if (typeof(eventData) !== 'string' && !(eventData instanceof String))
68 return eventData.substring(0, 12) == 'timer-event,' ||
69 eventData.substring(0, 5) == 'tick,' ||
70 eventData.substring(0, 15) == 'shared-library,' ||
71 eventData.substring(0, 9) == 'profiler,' ||
72 eventData.substring(0, 14) == 'code-creation,';
75 V8LogImporter.prototype = {
77 __proto__: Importer.prototype,
79 processTimerEvent_: function(name, start, length) {
80 var args = TimerEventDefaultArgs[name];
81 if (args === undefined) return;
82 start /= 1000; // Convert to milliseconds.
84 var colorId = tvcm.ui.getStringColorId(name);
85 var slice = new tracing.trace_model.Slice('v8', name, colorId, start,
87 this.v8_timer_thread_.sliceGroup.pushSlice(slice);
90 processTimerEventStart_: function(name, start) {
91 var args = TimerEventDefaultArgs[name];
92 if (args === undefined) return;
93 start /= 1000; // Convert to milliseconds.
94 this.v8_timer_thread_.sliceGroup.beginSlice('v8', name, start, args);
97 processTimerEventEnd_: function(name, end) {
98 end /= 1000; // Convert to milliseconds.
99 this.v8_timer_thread_.sliceGroup.endSlice(end);
102 processCodeCreateEvent_: function(type, kind, address, size, name) {
103 var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(size, name);
104 code_entry.kind = kind;
105 this.code_map_.addCode(address, code_entry);
108 processCodeMoveEvent_: function(from, to) {
109 this.code_map_.moveCode(from, to);
112 processCodeDeleteEvent_: function(address) {
113 this.code_map_.deleteCode(address);
116 processSharedLibrary_: function(name, start, end) {
117 var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(
119 code_entry.kind = -3; // External code kind.
120 for (var i = 0; i < kV8BinarySuffixes.length; i++) {
121 var suffix = kV8BinarySuffixes[i];
122 if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
123 code_entry.kind = -1; // V8 runtime code kind.
127 this.code_map_.addLibrary(start, code_entry);
130 findCodeKind_: function(kind) {
131 for (name in CodeKinds) {
132 if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
133 return CodeKinds[name];
138 processTickEvent_: function(pc, start, unused_x, unused_y, vmstate, stack) {
141 function findChildWithEntryID(stackFrame, entryID) {
142 for (var i = 0; i < stackFrame.children.length; i++) {
143 if (stackFrame.children[i].entryID == entryID)
144 return stackFrame.children[i];
150 if (stack && stack.length) {
152 lastStackFrame = this.root_stack_frame_;
153 // v8 log stacks are inverted, leaf first and the root at the end.
154 stack = stack.reverse();
155 for (var i = 0; i < stack.length; i++) {
158 var entry = this.code_map_.findEntry(stack[i]);
160 var entryID = entry ? entry.id : 'Unknown';
161 var childFrame = findChildWithEntryID(lastStackFrame, entryID);
162 if (childFrame === undefined) {
163 var entryName = entry ? entry.name : 'Unknown';
164 lastStackFrame = new tracing.trace_model.StackFrame(
165 lastStackFrame, 'v8sf-' + tvcm.GUID.allocate(),
167 tvcm.ui.getStringColorId(entryName));
168 lastStackFrame.entryID = entryID;
169 this.model_.addStackFrame(lastStackFrame);
171 lastStackFrame = childFrame;
175 var pcEntry = this.code_map_.findEntry(pc);
176 var pcEntryID = 'v8pc-' + (pcEntry ? pcEntry.id : 'Unknown');
177 if (this.model_.stackFrames[pcEntryID] === undefined) {
178 var pcEntryName = pcEntry ? pcEntry.name : 'Unknown';
179 lastStackFrame = new tracing.trace_model.StackFrame(
180 undefined, pcEntryID,
182 tvcm.ui.getStringColorId(pcEntryName));
183 this.model_.addStackFrame(lastStackFrame);
185 lastStackFrame = this.model_.stackFrames[pcEntryID];
188 var sample = new tracing.trace_model.Sample(
189 undefined, this.v8_thread_, 'V8 PC',
190 start, lastStackFrame, 1);
191 this.model_.samples.push(sample);
194 processDistortion_: function(distortion_in_picoseconds) {
195 distortion_per_entry = distortion_in_picoseconds / 1000000;
198 processPlotRange_: function(start, end) {
199 xrange_start_override = start;
200 xrange_end_override = end;
204 * Walks through the events_ list and outputs the structures discovered to
207 importEvents: function() {
208 var logreader = new tracing.importer.v8.LogReader(
210 parsers: [null, parseInt, parseInt],
211 processor: this.processTimerEvent_.bind(this)
214 parsers: [null, parseInt, parseInt],
215 processor: this.processSharedLibrary_.bind(this)
217 'timer-event-start' : {
218 parsers: [null, parseInt],
219 processor: this.processTimerEventStart_.bind(this)
221 'timer-event-end' : {
222 parsers: [null, parseInt],
223 processor: this.processTimerEventEnd_.bind(this)
226 parsers: [null, parseInt, parseInt, parseInt, null],
227 processor: this.processCodeCreateEvent_.bind(this)
230 parsers: [parseInt, parseInt],
231 processor: this.processCodeMoveEvent_.bind(this)
235 processor: this.processCodeDeleteEvent_.bind(this)
238 parsers: [parseInt, parseInt, null, null, parseInt, 'var-args'],
239 processor: this.processTickEvent_.bind(this)
243 processor: this.processDistortion_.bind(this)
246 parsers: [parseInt, parseInt],
247 processor: this.processPlotRange_.bind(this)
251 this.v8_timer_thread_ =
252 this.model_.getOrCreateProcess(-32).getOrCreateThread(1);
253 this.v8_timer_thread_.name = 'V8 Timers';
255 this.model_.getOrCreateProcess(-32).getOrCreateThread(2);
256 this.v8_thread_.name = 'V8';
258 var lines = this.logData_.split('\n');
259 for (var i = 0; i < lines.length; i++) {
260 logreader.processLogLine(lines[i]);
263 // The processing of samples adds all the root stack frame to
264 // this.root_stack_frame_. But, we don't want that stack frame in the real
265 // model. So get rid of it.
266 this.root_stack_frame_.removeAllChildren();
268 function addSlices(slices, thread) {
269 for (var i = 0; i < slices.length; i++) {
270 var duration = slices[i].end - slices[i].start;
271 var slice = new tracing.trace_model.Slice('v8', slices[i].name,
272 tvcm.ui.getStringColorId(slices[i].name),
273 slices[i].start, {}, duration);
274 thread.sliceGroup.pushSlice(slice);
275 addSlices(slices[i].children, thread);
278 addSlices(this.v8_stack_timeline_, this.v8_thread_);
282 tracing.TraceModel.registerImporter(V8LogImporter);
285 V8LogImporter: V8LogImporter