Home | History | Annotate | Download | only in importer
      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  */
     10 base.require('tracing.trace_model');
     11 base.require('tracing.trace_model.slice');
     12 base.require('tracing.color_scheme');
     13 base.require('tracing.importer.v8.log_reader');
     14 base.require('tracing.importer.v8.codemap');
     15 
     16 base.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