Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / sampling_summary_side_panel.js
1 // Copyright (c) 2014 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 tvcm.require('tracing.analysis.util');
8 tvcm.require('tracing.selection');
9 tvcm.require('tracing.timeline_view_side_panel');
10 tvcm.require('tvcm.iteration_helpers');
11 tvcm.require('tvcm.statistics');
12 tvcm.require('tvcm.ui.dom_helpers');
13 tvcm.require('tvcm.ui.pie_chart');
14 tvcm.require('tvcm.ui.sunburst_chart');
15
16 tvcm.requireTemplate('tracing.sampling_summary_side_panel');
17
18 tvcm.exportTo('tracing', function() {
19   var RequestSelectionChangeEvent = tracing.RequestSelectionChangeEvent;
20
21   /**
22      * @constructor
23      */
24   var CallTreeNode = function(name, category) {
25     this.parent = undefined;
26     this.name = name;
27     this.category = category;
28     this.selfTime = 0.0;
29     this.children = [];
30   }
31
32   /**
33    * @constructor
34    */
35   var Thread = function(thread) {
36     this.thread = thread;
37     this.rootNode = new CallTreeNode('root', 'root');
38     this.rootCategories = {};
39     this.sfToNode = {};
40     this.sfToNode[0] = self.rootNode;
41   }
42
43   Thread.prototype = {
44     getCallTreeNode: function(stackFrame) {
45       if (stackFrame.id in this.sfToNode)
46         return this.sfToNode[stackFrame.id];
47
48       // Create & save the node.
49       var newNode = new CallTreeNode(stackFrame.title, stackFrame.category);
50       this.sfToNode[stackFrame.id] = newNode;
51
52       // Add node to parent tree node.
53       if (stackFrame.parentFrame) {
54         var parentNode = this.getCallTreeNode(stackFrame.parentFrame);
55         parentNode.children.push(newNode);
56       } else {
57         // Creating a root category node for each category helps group samples
58         // that may be missing call stacks.
59         var rootCategory = this.rootCategories[stackFrame.category];
60         if (!rootCategory) {
61           rootCategory =
62               new CallTreeNode(stackFrame.category, stackFrame.category);
63           this.rootNode.children.push(rootCategory);
64           this.rootCategories[stackFrame.category] = rootCategory;
65         }
66         rootCategory.children.push(newNode);
67       }
68       return newNode;
69     },
70
71     addSample: function(sample) {
72       var node = this.getCallTreeNode(sample.leafStackFrame);
73       node.selfTime += sample.weight;
74     }
75   };
76
77   function genCallTree(node, isRoot) {
78     var ret = {
79       category: node.category,
80       name: node.name
81     };
82
83     if (isRoot || node.children.length > 0) {
84       ret.children = [];
85       for (var c = 0; c < node.children.length; c++)
86         ret.children.push(genCallTree(node.children[c], false));
87       if (node.selfTime > 0.0)
88         ret.children.push({
89           name: '<self>',
90           category: ret.category,
91           size: node.selfTime
92         });
93     }
94     else {
95       ret.size = node.selfTime;
96     }
97     if (isRoot)
98       return ret.children;
99     return ret;
100   }
101
102   // Create sunburst data from model data.
103   function createSunburstData(model, rangeOfInterest) {
104     // TODO(vmiura): Add selection.
105     var threads = {};
106     function getOrCreateThread(thread) {
107       var ret = undefined;
108       if (thread.tid in threads) {
109         ret = threads[thread.tid];
110       } else {
111         ret = new Thread(thread);
112         threads[thread.tid] = ret;
113       }
114       return ret;
115     }
116
117     // Process samples.
118     var samples = model.samples;
119     var rangeMin = rangeOfInterest.min;
120     var rangeMax = rangeOfInterest.max;
121     for (var i = 0; i < samples.length; i++) {
122       var sample = samples[i];
123       if (sample.start >= rangeMin && sample.start <= rangeMax)
124         getOrCreateThread(sample.thread).addSample(sample);
125     }
126
127     // Generate sunburst data.
128     var sunburstData = {
129       name: '<All Threads>',
130       category: 'root',
131       children: []
132     };
133     for (var t in threads) {
134       if (!threads.hasOwnProperty(t)) continue;
135       var thread = threads[t];
136       var threadData = {
137         name: '<' + thread.thread.name + '>',
138         category: 'Thread',
139         children: genCallTree(thread.rootNode, true)
140       };
141       sunburstData.children.push(threadData);
142     }
143     return sunburstData;
144   }
145
146   // Create sunburst chart from model data.
147   function createSunburstChart(model, rangeOfInterest) {
148     // TODO(vmiura): Add selection.
149     var sunburstData = createSunburstData(model, rangeOfInterest);
150     var chart = new tvcm.ui.SunburstChart();
151     chart.width = 800;
152     chart.height = 800;
153     chart.chartTitle = 'Sampling Summary';
154     chart.data = sunburstData;
155     return chart;
156   }
157
158   /**
159    * @constructor
160    */
161   var SamplingSummarySidePanel =
162       tvcm.ui.define('x-sample-summary-side-panel',
163                      tracing.TimelineViewSidePanel);
164   SamplingSummarySidePanel.textLabel = 'Sampling Summary';
165   SamplingSummarySidePanel.supportsModel = function(m) {
166     if (m == undefined) {
167       return {
168         supported: false,
169         reason: 'Unknown tracing model'
170       };
171     }
172
173     if (m.samples.length == 0) {
174       return {
175         supported: false,
176         reason: 'No sampling data in trace'
177       };
178     }
179
180     return {
181       supported: true
182     };
183   };
184
185   SamplingSummarySidePanel.prototype = {
186     __proto__: tracing.TimelineViewSidePanel.prototype,
187
188     decorate: function() {
189       tracing.TimelineViewSidePanel.prototype.decorate.call(this);
190       this.classList.add('x-sample-summary-side-panel');
191       this.appendChild(tvcm.instantiateTemplate(
192           '#x-sample-summary-side-panel-template'));
193
194       this.rangeOfInterest_ = new tvcm.Range();
195       this.chart_ = undefined;
196     },
197
198     get model() {
199       return model_;
200     },
201
202     set model(model) {
203       this.model_ = model;
204       this.updateContents_();
205     },
206
207     get rangeOfInterest() {
208       return this.rangeOfInterest_;
209     },
210
211     set rangeOfInterest(rangeOfInterest) {
212       this.rangeOfInterest_ = rangeOfInterest;
213       this.updateContents_();
214     },
215
216     updateContents_: function() {
217       var resultArea = this.querySelector('result-area');
218       this.chart_ = undefined;
219       resultArea.textContent = '';
220
221       if (this.model_ === undefined)
222         return;
223
224       var rangeOfInterest;
225       if (this.rangeOfInterest_.isEmpty)
226         rangeOfInterest = this.model_.bounds;
227       else
228         rangeOfInterest = this.rangeOfInterest_;
229
230       this.chart_ = createSunburstChart(this.model_, rangeOfInterest);
231       resultArea.appendChild(this.chart_);
232       this.chart_.setSize(this.chart_.getMinSize());
233     }
234   };
235
236   tracing.TimelineViewSidePanel.registerPanelSubtype(SamplingSummarySidePanel);
237
238   return {
239     SamplingSummarySidePanel: SamplingSummarySidePanel,
240     createSunburstData: createSunburstData
241   };
242 });