Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / importer / v8_log_importer.html
1 <!DOCTYPE html>
2 <!--
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.
6 -->
7
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">
14
15 <script>
16
17 'use strict';
18
19 /**
20  * @fileoverview V8LogImporter imports v8.log files into the provided model.
21  */
22 tvcm.exportTo('tracing.importer', function() {
23   var Importer = tracing.importer.Importer;
24
25   function V8LogImporter(model, eventData) {
26     this.importPriority = 3;
27     this.model_ = model;
28
29     this.logData_ = eventData;
30
31     this.code_map_ = new tracing.importer.v8.CodeMap();
32     this.v8_timer_thread_ = undefined;
33     this.v8_thread_ = undefined;
34
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);
38
39     // We reconstruct the stack timeline from ticks.
40     this.v8_stack_timeline_ = new Array();
41   }
42
43   var kV8BinarySuffixes = ['/d8', '/libv8.so'];
44
45
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}
59   };
60
61   /**
62    * @return {boolean} Whether obj is a V8 log string.
63    */
64   V8LogImporter.canImport = function(eventData) {
65     if (typeof(eventData) !== 'string' && !(eventData instanceof String))
66       return false;
67
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,';
73   };
74
75   V8LogImporter.prototype = {
76
77     __proto__: Importer.prototype,
78
79     processTimerEvent_: function(name, start, length) {
80       var args = TimerEventDefaultArgs[name];
81       if (args === undefined) return;
82       start /= 1000;  // Convert to milliseconds.
83       length /= 1000;
84       var colorId = tvcm.ui.getStringColorId(name);
85       var slice = new tracing.trace_model.Slice('v8', name, colorId, start,
86           args, length);
87       this.v8_timer_thread_.sliceGroup.pushSlice(slice);
88     },
89
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);
95     },
96
97     processTimerEventEnd_: function(name, end) {
98       end /= 1000;  // Convert to milliseconds.
99       this.v8_timer_thread_.sliceGroup.endSlice(end);
100     },
101
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);
106     },
107
108     processCodeMoveEvent_: function(from, to) {
109       this.code_map_.moveCode(from, to);
110     },
111
112     processCodeDeleteEvent_: function(address) {
113       this.code_map_.deleteCode(address);
114     },
115
116     processSharedLibrary_: function(name, start, end) {
117       var code_entry = new tracing.importer.v8.CodeMap.CodeEntry(
118           end - start, name);
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.
124           break;
125         }
126       }
127       this.code_map_.addLibrary(start, code_entry);
128     },
129
130     findCodeKind_: function(kind) {
131       for (name in CodeKinds) {
132         if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
133           return CodeKinds[name];
134         }
135       }
136     },
137
138     processTickEvent_: function(pc, start, unused_x, unused_y, vmstate, stack) {
139       start /= 1000;
140
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];
145         }
146         return undefined;
147       }
148
149       var lastStackFrame;
150       if (stack && stack.length) {
151
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++) {
156           if (!stack[i])
157             break;
158           var entry = this.code_map_.findEntry(stack[i]);
159
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(),
166                 'v8', entryName,
167                 tvcm.ui.getStringColorId(entryName));
168             lastStackFrame.entryID = entryID;
169             this.model_.addStackFrame(lastStackFrame);
170           } else {
171             lastStackFrame = childFrame;
172           }
173         }
174       } else {
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,
181               'v8', pcEntryName,
182               tvcm.ui.getStringColorId(pcEntryName));
183           this.model_.addStackFrame(lastStackFrame);
184         }
185         lastStackFrame = this.model_.stackFrames[pcEntryID];
186       }
187
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);
192     },
193
194     processDistortion_: function(distortion_in_picoseconds) {
195       distortion_per_entry = distortion_in_picoseconds / 1000000;
196     },
197
198     processPlotRange_: function(start, end) {
199       xrange_start_override = start;
200       xrange_end_override = end;
201     },
202
203     /**
204      * Walks through the events_ list and outputs the structures discovered to
205      * model_.
206      */
207     importEvents: function() {
208       var logreader = new tracing.importer.v8.LogReader(
209           { 'timer-event' : {
210             parsers: [null, parseInt, parseInt],
211             processor: this.processTimerEvent_.bind(this)
212           },
213           'shared-library': {
214             parsers: [null, parseInt, parseInt],
215             processor: this.processSharedLibrary_.bind(this)
216           },
217           'timer-event-start' : {
218             parsers: [null, parseInt],
219             processor: this.processTimerEventStart_.bind(this)
220           },
221           'timer-event-end' : {
222             parsers: [null, parseInt],
223             processor: this.processTimerEventEnd_.bind(this)
224           },
225           'code-creation': {
226             parsers: [null, parseInt, parseInt, parseInt, null],
227             processor: this.processCodeCreateEvent_.bind(this)
228           },
229           'code-move': {
230             parsers: [parseInt, parseInt],
231             processor: this.processCodeMoveEvent_.bind(this)
232           },
233           'code-delete': {
234             parsers: [parseInt],
235             processor: this.processCodeDeleteEvent_.bind(this)
236           },
237           'tick': {
238             parsers: [parseInt, parseInt, null, null, parseInt, 'var-args'],
239             processor: this.processTickEvent_.bind(this)
240           },
241           'distortion': {
242             parsers: [parseInt],
243             processor: this.processDistortion_.bind(this)
244           },
245           'plot-range': {
246             parsers: [parseInt, parseInt],
247             processor: this.processPlotRange_.bind(this)
248           }
249           });
250
251       this.v8_timer_thread_ =
252           this.model_.getOrCreateProcess(-32).getOrCreateThread(1);
253       this.v8_timer_thread_.name = 'V8 Timers';
254       this.v8_thread_ =
255           this.model_.getOrCreateProcess(-32).getOrCreateThread(2);
256       this.v8_thread_.name = 'V8';
257
258       var lines = this.logData_.split('\n');
259       for (var i = 0; i < lines.length; i++) {
260         logreader.processLogLine(lines[i]);
261       }
262
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();
267
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);
276         }
277       }
278       addSlices(this.v8_stack_timeline_, this.v8_thread_);
279     }
280   };
281
282   tracing.TraceModel.registerImporter(V8LogImporter);
283
284   return {
285     V8LogImporter: V8LogImporter
286   };
287 });
288 </script>