Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / src / tcmalloc / tcmalloc_snapshot_view.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 tvcm.requireStylesheet('tcmalloc.tcmalloc_snapshot_view');
8
9 tvcm.require('tracing.analysis.object_snapshot_view');
10 tvcm.require('tracing.analysis.util');
11
12 tvcm.exportTo('tcmalloc', function() {
13
14   var tsRound = tracing.analysis.tsRound;
15
16   /*
17    * Displays a heap memory snapshot in a human readable form.
18    * @constructor
19    */
20   var TcmallocSnapshotView = tvcm.ui.define(
21       'heap-snapshot-view',
22       tracing.analysis.ObjectSnapshotView);
23
24   TcmallocSnapshotView.prototype = {
25     __proto__: tracing.analysis.ObjectSnapshotView.prototype,
26
27     decorate: function() {
28       this.classList.add('tcmalloc-snapshot-view');
29     },
30
31     updateContents: function() {
32       var snapshot = this.objectSnapshot_;
33       if (!snapshot || !snapshot.heap_) {
34         this.textContent = 'No heap found.';
35         return;
36       }
37       // Clear old snapshot view.
38       this.textContent = '';
39
40       // Note: "total" may actually be less than the largest allocation bin.
41       // This might happen if one stack is doing a lot of allocation, then
42       // passing off to another stack for deallocation.  That stack will
43       // have a high "current bytes" count and the other one might be
44       // negative or zero. So "total" may be smaller than the largest trace.
45       var subhead = document.createElement('div');
46       subhead.textContent = 'Retaining ' +
47           this.getByteString_(snapshot.total_.currentBytes) + ' in ' +
48           snapshot.total_.currentAllocs +
49           ' allocations. Showing > 0.1 MB.';
50       subhead.className = 'subhead';
51       this.appendChild(subhead);
52
53       // Build a nested tree-view of allocations
54       var myList = this.buildAllocList_(snapshot.heap_, false);
55       this.appendChild(myList);
56     },
57
58     /**
59      * Creates a nested list with clickable entries.
60      * @param {Object} heapEntry The current trace heap entry.
61      * @param {boolean} hide Whether this list is hidden by default.
62      * @return {Element} A <ul> list element.
63      */
64     buildAllocList_: function(heapEntry, hide) {
65       var myList = document.createElement('ul');
66       myList.hidden = hide;
67       var keys = Object.keys(heapEntry.children);
68       keys.sort(function(a, b) {
69         // Sort from large to small.
70         return heapEntry.children[b].currentBytes -
71             heapEntry.children[a].currentBytes;
72       });
73       for (var i = 0; i < keys.length; i++) {
74         var traceName = keys[i];
75         var trace = heapEntry.children[traceName];
76         // Don't show small nodes - they make things harder to see.
77         if (trace.currentBytes < 100 * 1024)
78           continue;
79         var childCount = Object.keys(trace.children).length;
80         var isLeaf = childCount == 0;
81         var myItem = this.buildItem_(
82             traceName, isLeaf, trace.currentBytes, trace.currentAllocs);
83         myList.appendChild(myItem);
84         // Build a nested <ul> list of my children.
85         if (childCount > 0)
86           myItem.appendChild(this.buildAllocList_(trace, true));
87       }
88       return myList;
89     },
90
91     /*
92      * Returns a <li> for an allocation traceName of size bytes.
93      */
94     buildItem_: function(traceName, isLeaf, bytes, allocs) {
95       var myItem = document.createElement('li');
96       myItem.className = 'trace-item';
97       myItem.id = traceName;
98
99       var byteDiv = document.createElement('div');
100       byteDiv.textContent = this.getByteString_(bytes);
101       byteDiv.className = 'trace-bytes';
102       myItem.appendChild(byteDiv);
103
104       if (traceName.length == 0) {
105         // The empty trace name indicates that the allocations occurred at
106         // this trace level, not in a sub-trace. This looks weird as the
107         // empty string, so replace it with something non-empty and don't
108         // give that line an expander.
109         traceName = '(here)';
110       } else if (traceName.indexOf('..') == 0) {
111         // Tasks in RunTask have special handling. They show the path of the
112         // filename. Convert '../../foo.cc' into 'RunTask from foo.cc'.
113         var lastSlash = traceName.lastIndexOf('/');
114         if (lastSlash != -1)
115           traceName = 'Task from ' + traceName.substr(lastSlash + 1);
116       }
117       var traceDiv = document.createElement('div');
118       traceDiv.textContent = traceName;
119       traceDiv.className = 'trace-name';
120       myItem.appendChild(traceDiv);
121
122       // Don't allow leaf nodes to be expanded.
123       if (isLeaf)
124         return myItem;
125
126       // Expand the element when it is clicked.
127       var self = this;
128       myItem.addEventListener('click', function(event) {
129         // Allow click on the +/- image (li) or child divs.
130         if (this == event.target || this == event.target.parentElement) {
131           this.classList.toggle('expanded');
132           var child = this.querySelector('ul');
133           child.hidden = !child.hidden;
134           // Highlight this stack trace in the timeline view.
135           self.onItemClicked_(this);
136         }
137       });
138       myItem.classList.add('collapsed');
139       return myItem;
140     },
141
142     onItemClicked_: function(traceItem) {
143       // Compute the full stack trace the user just clicked.
144       var traces = [];
145       while (traceItem.classList.contains('trace-item')) {
146         var traceNameDiv = traceItem.firstElementChild.nextElementSibling;
147         traces.unshift(traceNameDiv.textContent);
148         var traceNameUl = traceItem.parentElement;
149         traceItem = traceNameUl.parentElement;
150       }
151       // Tell the instance that this stack trace is selected.
152       var instance = this.objectSnapshot_.objectInstance;
153       instance.selectedTraces = traces;
154       // Invalid the viewport to cause a redraw.
155       var trackView = document.querySelector('.timeline-track-view');
156       trackView.viewport_.dispatchChangeEvent();
157     },
158
159     /*
160      * Returns a human readable string for a size in bytes.
161      */
162     getByteString_: function(bytes) {
163       var mb = bytes / 1024 / 1024;
164       return mb.toFixed(1) + ' MB';
165     }
166   };
167
168   tracing.analysis.ObjectSnapshotView.register(
169       'memory::Heap', TcmallocSnapshotView);
170
171   return {
172     TcmallocSnapshotView: TcmallocSnapshotView
173   };
174
175 });