Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / importer / v8_log_importer.js
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 tvcm.require('tracing.importer.importer');
11 tvcm.require('tracing.trace_model');
12 tvcm.require('tracing.trace_model.slice');
13 tvcm.require('tracing.color_scheme');
14 tvcm.require('tracing.importer.v8.log_reader');
15 tvcm.require('tracing.importer.v8.codemap');
16
17 tvcm.exportTo('tracing.importer', function() {
18
19   var Importer = tracing.importer.Importer;
20
21   function V8LogImporter(model, eventData) {
22
23     this.importPriority = 3;
24     this.model_ = model;
25
26     this.logData_ = eventData;
27
28     this.code_map_ = new tracing.importer.v8.CodeMap();
29     this.v8_timer_thread_ = undefined;
30     this.v8_thread_ = undefined;
31
32     this.root_stack_frame_ = new tracing.trace_model.StackFrame(
33         undefined, 'v8-root-stack-frame',
34         'v8-root-stack-frame', 'v8-root-stack-frame', 0);
35
36     // We reconstruct the stack timeline from ticks.
37     this.v8_stack_timeline_ = new Array();
38   }
39
40   var kV8BinarySuffixes = ['/d8', '/libv8.so'];
41
42
43   var TimerEventDefaultArgs = {
44     'V8.Execute': { pause: false, no_execution: false},
45     'V8.External': { pause: false, no_execution: true},
46     'V8.CompileFullCode': { pause: true, no_execution: true},
47     'V8.RecompileSynchronous': { pause: true, no_execution: true},
48     'V8.RecompileParallel': { pause: false, no_execution: false},
49     'V8.CompileEval': { pause: true, no_execution: true},
50     'V8.Parse': { pause: true, no_execution: true},
51     'V8.PreParse': { pause: true, no_execution: true},
52     'V8.ParseLazy': { pause: true, no_execution: true},
53     'V8.GCScavenger': { pause: true, no_execution: true},
54     'V8.GCCompactor': { pause: true, no_execution: true},
55     'V8.GCContext': { pause: true, no_execution: true}
56   };
57
58   /**
59    * @return {boolean} Whether obj is a V8 log string.
60    */
61   V8LogImporter.canImport = function(eventData) {
62     if (typeof(eventData) !== 'string' && !(eventData instanceof String))
63       return false;
64
65     return eventData.substring(0, 12) == 'timer-event,' ||
66            eventData.substring(0, 5) == 'tick,' ||
67            eventData.substring(0, 15) == 'shared-library,' ||
68            eventData.substring(0, 9) == 'profiler,' ||
69            eventData.substring(0, 14) == 'code-creation,';
70   };
71
72   V8LogImporter.prototype = {
73
74     __proto__: Importer.prototype,
75
76     processTimerEvent_: function(name, start, length) {
77       var args = TimerEventDefaultArgs[name];
78       if (args === undefined) return;
79       start /= 1000;  // Convert to milliseconds.
80       length /= 1000;
81       var colorId = tvcm.ui.getStringColorId(name);
82       var slice = new tracing.trace_model.Slice('v8', name, colorId, start,
83           args, length);
84       this.v8_timer_thread_.sliceGroup.pushSlice(slice);
85     },
86
87     processTimerEventStart_: function(name, start) {
88       var args = TimerEventDefaultArgs[name];
89       if (args === undefined) return;
90       start /= 1000;  // Convert to milliseconds.
91       this.v8_timer_thread_.sliceGroup.beginSlice('v8', name, start, args);
92     },
93
94     processTimerEventEnd_: function(name, end) {
95       end /= 1000;  // Convert to milliseconds.
96       this.v8_timer_thread_.sliceGroup.endSlice(end);
97     },
98
99     processCodeCreateEvent_: function(type, kind, address, size, name) {
100       var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(size, name);
101       code_entry.kind = kind;
102       this.code_map_.addCode(address, code_entry);
103     },
104
105     processCodeMoveEvent_: function(from, to) {
106       this.code_map_.moveCode(from, to);
107     },
108
109     processCodeDeleteEvent_: function(address) {
110       this.code_map_.deleteCode(address);
111     },
112
113     processSharedLibrary_: function(name, start, end) {
114       var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(
115           end - start, name);
116       code_entry.kind = -3;  // External code kind.
117       for (var i = 0; i < kV8BinarySuffixes.length; i++) {
118         var suffix = kV8BinarySuffixes[i];
119         if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
120           code_entry.kind = -1;  // V8 runtime code kind.
121           break;
122         }
123       }
124       this.code_map_.addLibrary(start, code_entry);
125     },
126
127     findCodeKind_: function(kind) {
128       for (name in CodeKinds) {
129         if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
130           return CodeKinds[name];
131         }
132       }
133     },
134
135     processTickEvent_: function(pc, start, unused_x, unused_y, vmstate, stack) {
136       start /= 1000;
137
138       function findChildWithEntryID(stackFrame, entryID) {
139         for (var i = 0; i < stackFrame.children.length; i++) {
140           if (stackFrame.children[i].entryID == entryID)
141             return stackFrame.children[i];
142         }
143         return undefined;
144       }
145
146       var lastStackFrame;
147       if (stack && stack.length) {
148
149         lastStackFrame = this.root_stack_frame_;
150         // v8 log stacks are inverted, leaf first and the root at the end.
151         stack = stack.reverse();
152         for (var i = 0; i < stack.length; i++) {
153           if (!stack[i])
154             break;
155           var entry = this.code_map_.findEntry(stack[i]);
156
157           var entryID = entry ? entry.id : 'Unknown';
158           var childFrame = findChildWithEntryID(lastStackFrame, entryID);
159           if (childFrame === undefined) {
160             var entryName = entry ? entry.name : 'Unknown';
161             lastStackFrame = new tracing.trace_model.StackFrame(
162                 lastStackFrame, 'v8sf-' + tvcm.GUID.allocate(),
163                 'v8', entryName,
164                 tvcm.ui.getStringColorId(name));
165             lastStackFrame.entryID = entryID;
166             this.model_.addStackFrame(lastStackFrame);
167           } else {
168             lastStackFrame = childFrame;
169           }
170         }
171       } else {
172         var pcEntry = this.code_map_.findEntry(pc);
173         var pcEntryID = 'v8pc-' + (pcEntry ? pcEntry.id : 'Unknown');
174         if (this.model_.stackFrames[pcEntryID] === undefined) {
175           var pcEntryName = pcEntry ? pcEntry.name : 'Unknown';
176           lastStackFrame = new tracing.trace_model.StackFrame(
177               undefined, pcEntryID,
178               'v8', pcEntryName,
179               tvcm.ui.getStringColorId(name));
180           this.model_.addStackFrame(lastStackFrame);
181         }
182         lastStackFrame = this.model_.stackFrames[pcEntryID];
183       }
184
185       var sample = new tracing.trace_model.Sample(
186           undefined, this.v8_thread_, 'V8 PC',
187           start, lastStackFrame, 1);
188       this.model_.samples.push(sample);
189     },
190
191     processDistortion_: function(distortion_in_picoseconds) {
192       distortion_per_entry = distortion_in_picoseconds / 1000000;
193     },
194
195     processPlotRange_: function(start, end) {
196       xrange_start_override = start;
197       xrange_end_override = end;
198     },
199
200     /**
201      * Walks through the events_ list and outputs the structures discovered to
202      * model_.
203      */
204     importEvents: function() {
205       var logreader = new tracing.importer.v8.LogReader(
206           { 'timer-event' : {
207             parsers: [null, parseInt, parseInt],
208             processor: this.processTimerEvent_.bind(this)
209           },
210           'shared-library': {
211             parsers: [null, parseInt, parseInt],
212             processor: this.processSharedLibrary_.bind(this)
213           },
214           'timer-event-start' : {
215             parsers: [null, parseInt],
216             processor: this.processTimerEventStart_.bind(this)
217           },
218           'timer-event-end' : {
219             parsers: [null, parseInt],
220             processor: this.processTimerEventEnd_.bind(this)
221           },
222           'code-creation': {
223             parsers: [null, parseInt, parseInt, parseInt, null],
224             processor: this.processCodeCreateEvent_.bind(this)
225           },
226           'code-move': {
227             parsers: [parseInt, parseInt],
228             processor: this.processCodeMoveEvent_.bind(this)
229           },
230           'code-delete': {
231             parsers: [parseInt],
232             processor: this.processCodeDeleteEvent_.bind(this)
233           },
234           'tick': {
235             parsers: [parseInt, parseInt, null, null, parseInt, 'var-args'],
236             processor: this.processTickEvent_.bind(this)
237           },
238           'distortion': {
239             parsers: [parseInt],
240             processor: this.processDistortion_.bind(this)
241           },
242           'plot-range': {
243             parsers: [parseInt, parseInt],
244             processor: this.processPlotRange_.bind(this)
245           }
246           });
247
248       this.v8_timer_thread_ =
249           this.model_.getOrCreateProcess(-32).getOrCreateThread(1);
250       this.v8_timer_thread_.name = 'V8 Timers';
251       this.v8_thread_ =
252           this.model_.getOrCreateProcess(-32).getOrCreateThread(2);
253       this.v8_thread_.name = 'V8';
254
255       var lines = this.logData_.split('\n');
256       for (var i = 0; i < lines.length; i++) {
257         logreader.processLogLine(lines[i]);
258       }
259
260       // The processing of samples adds all the root stack frame to
261       // this.root_stack_frame_. But, we don't want that stack frame in the real
262       // model. So get rid of it.
263       this.root_stack_frame_.removeAllChildren();
264
265       function addSlices(slices, thread) {
266         for (var i = 0; i < slices.length; i++) {
267           var duration = slices[i].end - slices[i].start;
268           var slice = new tracing.trace_model.Slice('v8', slices[i].name,
269               tvcm.ui.getStringColorId(slices[i].name),
270               slices[i].start, {}, duration);
271           thread.sliceGroup.pushSlice(slice);
272           addSlices(slices[i].children, thread);
273         }
274       }
275       addSlices(this.v8_stack_timeline_, this.v8_thread_);
276     }
277   };
278
279   tracing.TraceModel.registerImporter(V8LogImporter);
280
281   return {
282     V8LogImporter: V8LogImporter
283   };
284 });