• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7/**
8 * @fileoverview V8LogImporter imports v8.log files into the provided model.
9 */
10base.require('tracing.trace_model');
11base.require('tracing.trace_model.slice');
12base.require('tracing.color_scheme');
13base.require('tracing.importer.v8.log_reader');
14base.require('tracing.importer.v8.codemap');
15
16base.exportTo('tracing.importer', function() {
17
18  function V8LogImporter(model, eventData) {
19
20    this.importPriority = 3;
21    this.model_ = model;
22
23    this.logData_ = eventData;
24
25    this.code_map_ = new tracing.importer.v8.CodeMap();
26    this.v8_timer_thread_ = undefined;
27    this.v8_stack_thread_ = undefined;
28    this.v8_samples_thread_ = undefined;
29  }
30
31  var kV8BinarySuffixes = ['/d8', '/libv8.so'];
32  var kStackFrames = 8;
33
34  var TimerEventDefaultArgs = {
35    'V8.Execute': { pause: false, no_execution: false},
36    'V8.External': { pause: false, no_execution: true},
37    'V8.CompileFullCode': { pause: true, no_execution: true},
38    'V8.RecompileSynchronous': { pause: true, no_execution: true},
39    'V8.RecompileParallel': { pause: false, no_execution: false},
40    'V8.CompileEval': { pause: true, no_execution: true},
41    'V8.Parse': { pause: true, no_execution: true},
42    'V8.PreParse': { pause: true, no_execution: true},
43    'V8.ParseLazy': { pause: true, no_execution: true},
44    'V8.GCScavenger': { pause: true, no_execution: true},
45    'V8.GCCompactor': { pause: true, no_execution: true},
46    'V8.GCContext': { pause: true, no_execution: true}
47  };
48
49  /**
50   * @return {boolean} Whether obj is a V8 log string.
51   */
52  V8LogImporter.canImport = function(eventData) {
53    if (typeof(eventData) !== 'string' && !(eventData instanceof String))
54      return false;
55
56    return eventData.substring(0, 12) == 'timer-event,' ||
57           eventData.substring(0, 5) == 'tick,' ||
58           eventData.substring(0, 15) == 'shared-library,' ||
59           eventData.substring(0, 9) == 'profiler,';
60  };
61
62  V8LogImporter.prototype = {
63
64    __proto__: Object.prototype,
65
66    extractSubtrace: function() {
67      return undefined;
68    },
69
70    processTimerEvent_: function(name, start, length) {
71      var args = TimerEventDefaultArgs[name];
72      if (args === undefined) return;
73      start /= 1000;  // Convert to milliseconds.
74      length /= 1000;
75      var colorId = tracing.getStringColorId(name);
76      var slice = new tracing.trace_model.Slice('v8', name, colorId, start,
77          args, length);
78      this.v8_timer_thread_.sliceGroup.pushSlice(slice);
79    },
80
81    processTimerEventStart_: function(name, start) {
82      var args = TimerEventDefaultArgs[name];
83      if (args === undefined) return;
84      start /= 1000;  // Convert to milliseconds.
85      this.v8_timer_thread_.sliceGroup.beginSlice('v8', name, start, args);
86    },
87
88    processTimerEventEnd_: function(name, end) {
89      end /= 1000;  // Convert to milliseconds.
90      this.v8_timer_thread_.sliceGroup.endSlice(end);
91    },
92
93    processCodeCreateEvent_: function(type, kind, address, size, name) {
94      var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(size, name);
95      code_entry.kind = kind;
96      this.code_map_.addCode(address, code_entry);
97    },
98
99    processCodeMoveEvent_: function(from, to) {
100      this.code_map_.moveCode(from, to);
101    },
102
103    processCodeDeleteEvent_: function(address) {
104      this.code_map_.deleteCode(address);
105    },
106
107    processSharedLibrary_: function(name, start, end) {
108      var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(
109          end - start, name);
110      code_entry.kind = -3;  // External code kind.
111      for (var i = 0; i < kV8BinarySuffixes.length; i++) {
112        var suffix = kV8BinarySuffixes[i];
113        if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
114          code_entry.kind = -1;  // V8 runtime code kind.
115          break;
116        }
117      }
118      this.code_map_.addLibrary(start, code_entry);
119    },
120
121    findCodeKind_: function(kind) {
122      for (name in CodeKinds) {
123        if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
124          return CodeKinds[name];
125        }
126      }
127    },
128
129    nameForCodeEntry_: function(entry) {
130      if (entry)
131        return entry.name;
132      return 'UnknownCode';
133    },
134
135    processTickEvent_: function(pc, sp, start, unused_x, unused_y, vmstate,
136                                stack) {
137      var entry = this.code_map_.findEntry(pc);
138      var name = this.nameForCodeEntry_(entry);
139      start /= 1000;
140      this.v8_samples_thread_.addSample('v8', name, start);
141      if (stack && stack.length) {
142        for (var i = 0; i < 8; i++) {
143          if (!stack[i]) break;
144          entry = this.code_map_.findEntry(stack[i]);
145          name = this.nameForCodeEntry_(entry);
146          var colorId = tracing.getStringColorId(name);
147          var slice = new tracing.trace_model.Slice(
148              'v8', name, colorId, start, {}, 0);
149          this.v8_stack_thread_.sliceGroup.pushSlice(slice);
150        }
151      }
152    },
153
154    processDistortion_: function(distortion_in_picoseconds) {
155      distortion_per_entry = distortion_in_picoseconds / 1000000;
156    },
157
158    processPlotRange_: function(start, end) {
159      xrange_start_override = start;
160      xrange_end_override = end;
161    },
162
163    /**
164     * Walks through the events_ list and outputs the structures discovered to
165     * model_.
166     */
167    importEvents: function() {
168      var logreader = new tracing.importer.v8.LogReader(
169          { 'timer-event' : {
170            parsers: [null, parseInt, parseInt],
171            processor: this.processTimerEvent_.bind(this)
172          },
173          'shared-library': {
174            parsers: [null, parseInt, parseInt],
175            processor: this.processSharedLibrary_.bind(this)
176          },
177          'timer-event-start' : {
178            parsers: [null, parseInt],
179            processor: this.processTimerEventStart_.bind(this)
180          },
181          'timer-event-end' : {
182            parsers: [null, parseInt],
183            processor: this.processTimerEventEnd_.bind(this)
184          },
185          'code-creation': {
186            parsers: [null, parseInt, parseInt, parseInt, null],
187            processor: this.processCodeCreateEvent_.bind(this)
188          },
189          'code-move': {
190            parsers: [parseInt, parseInt],
191            processor: this.processCodeMoveEvent_.bind(this)
192          },
193          'code-delete': {
194            parsers: [parseInt],
195            processor: this.processCodeDeleteEvent_.bind(this)
196          },
197          'tick': {
198            parsers: [parseInt, parseInt, parseInt, null, null, parseInt,
199                      'var-args'],
200            processor: this.processTickEvent_.bind(this)
201          },
202          'distortion': {
203            parsers: [parseInt],
204            processor: this.processDistortion_.bind(this)
205          },
206          'plot-range': {
207            parsers: [parseInt, parseInt],
208            processor: this.processPlotRange_.bind(this)
209          }
210          });
211
212      this.v8_timer_thread_ =
213          this.model_.getOrCreateProcess(-32).getOrCreateThread(1);
214      this.v8_timer_thread_.name = 'V8 Timers';
215      this.v8_stack_thread_ =
216          this.model_.getOrCreateProcess(-32).getOrCreateThread(2);
217      this.v8_stack_thread_.name = 'V8 JavaScript';
218      this.v8_samples_thread_ =
219          this.model_.getOrCreateProcess(-32).getOrCreateThread(3);
220      this.v8_samples_thread_.name = 'V8 PC';
221
222      var lines = this.logData_.split('\n');
223      for (var i = 0; i < lines.length; i++) {
224        logreader.processLogLine(lines[i]);
225      }
226    },
227
228    /**
229     * Called by the Model after all other importers have imported their
230     * events.
231     */
232    finalizeImport: function() {
233    },
234
235    /**
236     * Called by the model to join references between objects, after final model
237     * bounds have been computed.
238     */
239    joinRefs: function() {
240    }
241  };
242
243  tracing.TraceModel.registerImporter(V8LogImporter);
244
245  return {
246    V8LogImporter: V8LogImporter
247  };
248});
249