// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview V8LogImporter imports v8.log files into the provided model. */ base.require('model'); base.require('model.slice'); base.require('color_scheme'); base.require('importer.v8.log_reader'); base.require('importer.v8.codemap'); base.exportTo('tracing.importer', function() { function V8LogImporter(model, eventData) { this.importPriority = 3; this.model_ = model; this.logData_ = eventData; this.code_map_ = new tracing.importer.v8.CodeMap(); this.v8_timer_thread_ = undefined; this.v8_stack_thread_ = undefined; this.v8_samples_thread_ = undefined; } var kV8BinarySuffixes = ['/d8', '/libv8.so']; var kStackFrames = 8; var TimerEventDefaultArgs = { 'V8.Execute': { pause: false, no_execution: false}, 'V8.External': { pause: false, no_execution: true}, 'V8.CompileFullCode': { pause: true, no_execution: true}, 'V8.RecompileSynchronous': { pause: true, no_execution: true}, 'V8.RecompileParallel': { pause: false, no_execution: false}, 'V8.CompileEval': { pause: true, no_execution: true}, 'V8.Parse': { pause: true, no_execution: true}, 'V8.PreParse': { pause: true, no_execution: true}, 'V8.ParseLazy': { pause: true, no_execution: true}, 'V8.GCScavenger': { pause: true, no_execution: true}, 'V8.GCCompactor': { pause: true, no_execution: true}, 'V8.GCContext': { pause: true, no_execution: true}, }; /** * @return {boolean} Whether obj is a V8 log string. */ V8LogImporter.canImport = function(eventData) { if (typeof(eventData) !== 'string' && !(eventData instanceof String)) return false; return eventData.substring(0, 12) == 'timer-event,' || eventData.substring(0, 5) == 'tick,' || eventData.substring(0, 15) == 'shared-library,' || eventData.substring(0, 9) == 'profiler,'; }; V8LogImporter.prototype = { __proto__: Object.prototype, processTimerEvent_: function(name, start, length) { var args = TimerEventDefaultArgs[name]; if (args === undefined) return; start /= 1000; // Convert to milliseconds. length /= 1000; var colorId = tracing.getStringColorId(name); var slice = new tracing.model.Slice('v8', name, colorId, start, args, length); this.v8_timer_thread_.pushSlice(slice); }, processTimerEventStart_: function(name, start) { debugger; var args = TimerEventDefaultArgs[name]; if (args === undefined) return; start /= 1000; // Convert to milliseconds. this.v8_timer_thread_.beginSlice('v8', name, start, args); }, processTimerEventEnd_: function(name, end) { debugger; end /= 1000; // Convert to milliseconds. this.v8_timer_thread_.endSlice(end); }, processCodeCreateEvent_: function(type, kind, address, size, name) { var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(size, name); code_entry.kind = kind; this.code_map_.addCode(address, code_entry); }, processCodeMoveEvent_: function(from, to) { this.code_map_.moveCode(from, to); }, processCodeDeleteEvent_: function(address) { this.code_map_.deleteCode(address); }, processSharedLibrary_: function(name, start, end) { var code_entry = new tracing.importer.v8.CodeMap.CodeEntry( end - start, name); code_entry.kind = -3; // External code kind. for (var i = 0; i < kV8BinarySuffixes.length; i++) { var suffix = kV8BinarySuffixes[i]; if (name.indexOf(suffix, name.length - suffix.length) >= 0) { code_entry.kind = -1; // V8 runtime code kind. break; } } this.code_map_.addLibrary(start, code_entry); }, findCodeKind_: function(kind) { for (name in CodeKinds) { if (CodeKinds[name].kinds.indexOf(kind) >= 0) { return CodeKinds[name]; } } }, nameForCodeEntry_: function(entry) { if (entry) return entry.name; return 'UnknownCode'; }, processTickEvent_: function(pc, sp, start, unused_x, unused_y, vmstate, stack) { var entry = this.code_map_.findEntry(pc); var name = this.nameForCodeEntry_(entry); start /= 1000; this.v8_samples_thread_.addSample('v8', name, start); if (stack && stack.length) { for (var i = 0; i < 8; i++) { if (!stack[i]) break; entry = this.code_map_.findEntry(stack[i]); name = this.nameForCodeEntry_(entry); var colorId = tracing.getStringColorId(name); var slice = new tracing.model.Slice('v8', name, colorId, start, {}, 0); this.v8_stack_thread_.pushSlice(slice); } } }, processDistortion_: function(distortion_in_picoseconds) { distortion_per_entry = distortion_in_picoseconds / 1000000; }, processPlotRange_: function(start, end) { xrange_start_override = start; xrange_end_override = end; }, /** * Walks through the events_ list and outputs the structures discovered to * model_. */ importEvents: function() { var logreader = new tracing.importer.v8.LogReader( { 'timer-event' : { parsers: [null, parseInt, parseInt], processor: this.processTimerEvent_.bind(this) }, 'shared-library': { parsers: [null, parseInt, parseInt], processor: this.processSharedLibrary_.bind(this) }, 'timer-event-start' : { parsers: [null, parseInt], processor: this.processTimerEventStart_.bind(this) }, 'timer-event-end' : { parsers: [null, parseInt], processor: this.processTimerEventEnd_.bind(this) }, 'code-creation': { parsers: [null, parseInt, parseInt, parseInt, null], processor: this.processCodeCreateEvent_.bind(this) }, 'code-move': { parsers: [parseInt, parseInt], processor: this.processCodeMoveEvent_.bind(this) }, 'code-delete': { parsers: [parseInt], processor: this.processCodeDeleteEvent_.bind(this) }, 'tick': { parsers: [parseInt, parseInt, parseInt, null, null, parseInt, 'var-args'], processor: this.processTickEvent_.bind(this) }, 'distortion': { parsers: [parseInt], processor: this.processDistortion_.bind(this) }, 'plot-range': { parsers: [parseInt, parseInt], processor: this.processPlotRange_.bind(this) }, }); this.v8_timer_thread_ = this.model_.getOrCreateProcess(-32).getOrCreateThread(1); this.v8_timer_thread_.name = 'V8 Timers'; this.v8_stack_thread_ = this.model_.getOrCreateProcess(-32).getOrCreateThread(2); this.v8_stack_thread_.name = 'V8 JavaScript'; this.v8_samples_thread_ = this.model_.getOrCreateProcess(-32).getOrCreateThread(3); this.v8_samples_thread_.name = 'V8 PC'; var lines = this.logData_.split('\n'); for (var i = 0; i < lines.length; i++) { logreader.processLogLine(lines[i]); } }, /** * Called by the Model after all other importers have imported their * events. */ finalizeImport: function() { }, }; tracing.Model.registerImporter(V8LogImporter); return { V8LogImporter: V8LogImporter }; });