Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / 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_stack_thread_ = undefined;
31     this.v8_samples_thread_ = undefined;
32
33     // we maintain the timestamp of the last tick to verify if a stack is
34     // a continuation from the last sample, or it is a new stack.
35     this.last_tick_timestamp_ = undefined;
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 = tracing.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     nameForCodeEntry_: function(entry) {
136       if (entry)
137         return entry.name;
138       return 'UnknownCode';
139     },
140
141     processTickEvent_: function(pc, start, unused_x, unused_y, vmstate, stack) {
142       // Transform ticks into events by aggregating stack frames across ticks
143       // For example:
144       //
145       // Tick Time: 0 1 2 3 4 5 6 7 8 9
146       // Stack:     A A A A B B   C C C
147       //            D D   E F       G G
148       //            H     I           J
149       //
150       // would become
151       //
152       // Time:      0 1   3 4 5   7   9
153       // Slices:    [  A  ] [B]   [ C ]
154       //            [D]   E F       [G]
155       //            H     I           J
156
157       var entry = this.code_map_.findEntry(pc);
158       var name = this.nameForCodeEntry_(entry);
159       start /= 1000;
160       this.v8_samples_thread_.addSample('v8', name, start);
161
162       if (stack && stack.length) {
163         var stack_frame = this.v8_stack_timeline_;
164         for (var i = stack.length - 1; i >= 0; i--) {
165           if (!stack[i]) break;
166           entry = this.code_map_.findEntry(stack[i]);
167           name = this.nameForCodeEntry_(entry);
168           if (stack_frame.length > 0 &&
169                   stack_frame[stack_frame.length - 1].name == name &&
170                   stack_frame[stack_frame.length - 1].end ==
171                       this.last_tick_timestamp_) {
172             // If the entry from the previous stack at the same level had the
173             // same name we extend it to include the current tick as well.
174             stack_frame[stack_frame.length - 1].end = start;
175           } else {
176             // otherwise we create a new entry.
177             var record = {
178               name: name,
179               start: start,
180               end: start,
181               children: new Array()
182             };
183             stack_frame.push(record);
184           }
185           stack_frame = stack_frame[stack_frame.length - 1].children;
186         }
187         // The last tick time stamp gets updated only when we have a stack
188         this.last_tick_timestamp_ = start;
189       }
190     },
191
192     processDistortion_: function(distortion_in_picoseconds) {
193       distortion_per_entry = distortion_in_picoseconds / 1000000;
194     },
195
196     processPlotRange_: function(start, end) {
197       xrange_start_override = start;
198       xrange_end_override = end;
199     },
200
201     /**
202      * Walks through the events_ list and outputs the structures discovered to
203      * model_.
204      */
205     importEvents: function() {
206       var logreader = new tracing.importer.v8.LogReader(
207           { 'timer-event' : {
208             parsers: [null, parseInt, parseInt],
209             processor: this.processTimerEvent_.bind(this)
210           },
211           'shared-library': {
212             parsers: [null, parseInt, parseInt],
213             processor: this.processSharedLibrary_.bind(this)
214           },
215           'timer-event-start' : {
216             parsers: [null, parseInt],
217             processor: this.processTimerEventStart_.bind(this)
218           },
219           'timer-event-end' : {
220             parsers: [null, parseInt],
221             processor: this.processTimerEventEnd_.bind(this)
222           },
223           'code-creation': {
224             parsers: [null, parseInt, parseInt, parseInt, null],
225             processor: this.processCodeCreateEvent_.bind(this)
226           },
227           'code-move': {
228             parsers: [parseInt, parseInt],
229             processor: this.processCodeMoveEvent_.bind(this)
230           },
231           'code-delete': {
232             parsers: [parseInt],
233             processor: this.processCodeDeleteEvent_.bind(this)
234           },
235           'tick': {
236             parsers: [parseInt, parseInt, null, null, parseInt, 'var-args'],
237             processor: this.processTickEvent_.bind(this)
238           },
239           'distortion': {
240             parsers: [parseInt],
241             processor: this.processDistortion_.bind(this)
242           },
243           'plot-range': {
244             parsers: [parseInt, parseInt],
245             processor: this.processPlotRange_.bind(this)
246           }
247           });
248
249       this.v8_timer_thread_ =
250           this.model_.getOrCreateProcess(-32).getOrCreateThread(1);
251       this.v8_timer_thread_.name = 'V8 Timers';
252       this.v8_stack_thread_ =
253           this.model_.getOrCreateProcess(-32).getOrCreateThread(2);
254       this.v8_stack_thread_.name = 'V8 JavaScript';
255       this.v8_samples_thread_ =
256           this.model_.getOrCreateProcess(-32).getOrCreateThread(3);
257       this.v8_samples_thread_.name = 'V8 PC';
258
259       var lines = this.logData_.split('\n');
260       for (var i = 0; i < lines.length; i++) {
261         logreader.processLogLine(lines[i]);
262       }
263
264       function addSlices(slices, thread) {
265         for (var i = 0; i < slices.length; i++) {
266           var duration = slices[i].end - slices[i].start;
267           var slice = new tracing.trace_model.Slice('v8', slices[i].name,
268               tracing.getStringColorId(slices[i].name),
269               slices[i].start, {}, duration);
270           thread.sliceGroup.pushSlice(slice);
271           addSlices(slices[i].children, thread);
272         }
273       }
274       addSlices(this.v8_stack_timeline_, this.v8_stack_thread_);
275       this.v8_stack_thread_.createSubSlices();
276       this.v8_timer_thread_.createSubSlices();
277     }
278   };
279
280   tracing.TraceModel.registerImporter(V8LogImporter);
281
282   return {
283     V8LogImporter: V8LogImporter
284   };
285 });