2 Copyright 2014 The Chromium Authors. All rights reserved.
3 Use of this source code is governed by a BSD-style license that can be
4 found in the LICENSE file.
8 <title>Binary Size Analysis
</title>
9 <script src=
"d3/d3.js" charset=
"utf-8"></script>
10 <script src=
"D3SymbolTreeMap.js" charset=
"utf-8"></script>
11 <script src=
"data.js" charset=
"utf-8"></script>
18 border:
1px solid rgb(
100,
100,
100);
19 -webkit-user-select: none;
25 var filterChanging
= false;
26 var savedSettings
= {};
29 if (window
.metadata
!== undefined && window
.metadata
.subtitle
) {
30 document
.getElementById('subtitle').innerHTML
= ': ' + escape(metadata
.subtitle
);
33 treemap
= new D3SymbolTreeMap(
36 savedSettings
.maxLevels
);
40 function getIdealSizes() {
41 var width
= window
.innerWidth
- 20;
42 var height
= window
.innerHeight
- 70;
43 return {'width': width
, 'height': height
};
46 function showReport(title
, data
, headers
, dataFunction
, styleFunction
) {
47 var div
= d3
.select('body').append('div')
49 .style('padding', '5px')
50 .style('position', 'absolute')
53 .style('background-color', 'rgba(255,255,255,0.9)')
54 .style('width', '80%')
55 .style('height', '80%')
56 .style('z-index', '2147483647')
57 .style('border', '3px ridge grey')
58 .style('box-shadow', '10px 10px 5px rgba(80,80,80,0.7)')
59 .style('text-align', 'center')
60 .style('border-radius', '10px');
61 var titlebar
= div
.append('div')
63 .style('padding', '5px')
64 .style('position', 'absolute')
67 .style('width', '100%')
68 .style('height', '10%')
69 .style('font-size', 'x-large');
71 var controls
= div
.append('div')
73 .style('padding', '5px')
74 .style('position', 'absolute')
77 .style('width', '100%')
78 .style('height', '10%');
79 controls
.append('input').attr('type', 'button')
80 .attr('value', 'Dismiss')
81 .on('click', function(){div
.remove();});
83 var tableDiv
= div
.append('div')
84 .style('overflow', 'auto')
85 .style('position', 'absolute')
88 .style('width', '100%')
89 .style('height', '80%')
90 .style('border-top', '1px solid rgb(230,230,230)')
91 .style('border-bottom', '1px solid rgb(230,230,230)');
92 var table
= tableDiv
.append('table')
94 .attr('cellspacing', '0')
95 .attr('cellpadding', '2')
96 .style('margin-left', 'auto')
97 .style('margin-right', 'auto');
98 var header
= table
.append('tr');
99 for (var i
= 0; i
< headers
.length
; i
++) {
100 header
.append('th').text(headers
[i
]);
103 for (var i
= 0; i
< data
.length
; i
++) {
104 var row
= table
.append('tr');
105 for (j
= 0; j
< headers
.length
; j
++) {
106 var td
= row
.append('td');
108 styleFunction
.call(this, td
, j
);
110 dataFunction
.call(this, data
[i
], j
, td
);
115 function bigSymbolsReport() {
116 var list
= treemap
.biggestSymbols(100);
117 var headers
= ['Rank', 'Size (Bytes)', 'Type', 'Location'];
118 var styleFunction = function(selection
, index
) {
120 selection
.style('font-family', 'monospace');
124 var dataFunction = function(record
, index
, cell
) {
126 cell
.text(recordIndex
++);
127 } else if (index
=== 1) {
128 cell
.text(D3SymbolTreeMap
._pretty(record
.value
));
129 } else if (index
=== 2) {
132 if (treemap
.pathFor(record
).indexOf('/out') == 0) {
133 cell
.append('span').text(treemap
.pathFor(record
));
135 cell
.append('span').text('Symbol: ');
136 cell
.append('span').text(record
.n
);
138 var href
= 'https://code.google.com/p/chromium/codesearch#chromium/src'
139 + treemap
.pathFor(record
)
144 .attr('target', '_blank')
145 .text(treemap
.pathFor(record
));
147 cell
.append('span').text('Symbol: ');
148 cell
.append('span').text(record
.n
);
152 showReport('100 Largest Symbols', list
, headers
, dataFunction
, styleFunction
);
155 function bigPathsReport() {
156 var list
= treemap
.biggestPaths(100);
157 var headers
= ['Rank', 'Size (Bytes)', 'Location'];
158 var styleFunction = function(selection
, index
) {
160 selection
.style('font-family', 'monospace');
164 var dataFunction = function(record
, index
, cell
) {
166 cell
.text(recordIndex
++);
167 } else if (index
=== 1) {
168 cell
.text(D3SymbolTreeMap
._pretty(record
.value
));
169 } else if (index
=== 2) {
170 if (treemap
.pathFor(record
).indexOf('/out') == 0) {
171 cell
.text(treemap
.pathFor(record
));
173 var href
= 'https://code.google.com/p/chromium/codesearch#chromium/src' + treemap
.pathFor(record
);
176 .attr('target', '_blank')
177 .text(treemap
.pathFor(record
));
182 showReport('100 Largest Paths', list
, headers
, dataFunction
, styleFunction
);
185 function symbolFilterTextChanged() {
186 if (filterChanging
) return true;
187 filterChanging
= true;
188 var enabled
= document
.getElementById('symbol_types_filter').value
;
189 for (var x
=0; x
<=25; x
++) {
190 var checkBox
= document
.getElementById('check_' + x
);
191 checkBox
.checked
= (enabled
.indexOf(checkBox
.value
) != -1);
193 filterChanging
= false;
196 function updateFilterText() {
197 if (filterChanging
) return true;
198 filterChanging
= true;
200 for (var x
=0; x
<=25; x
++) {
201 var checkBox
= document
.getElementById('check_' + x
);
202 if (checkBox
.checked
) {
203 text
+= checkBox
.value
;
206 document
.getElementById('symbol_types_filter').value
=text
;
207 filterChanging
= false;
210 function initFilterOptions() {
212 for (var x
=0; x
<=25; x
++) {
213 var checkBox
= document
.getElementById('check_' + x
);
214 checkBox
.onchange
=updateFilterText
;
215 var swatch
= document
.getElementById('swatch_' + x
);
216 swatch
.style
.backgroundColor
= D3SymbolTreeMap
.getColorForType(checkBox
.value
).toString();
218 var gteCheckbox
= document
.getElementById('check_gte');
219 gteCheckbox
.onchange = function() {
220 document
.getElementById('symbol_filter_gte').disabled
= !gteCheckbox
.checked
;
222 var regexCheckbox
= document
.getElementById('check_regex');
223 regexCheckbox
.onchange = function() {
224 document
.getElementById('symbol_filter_regex').disabled
= !regexCheckbox
.checked
;
226 var excludeRegexCheckbox
= document
.getElementById('check_exclude_regex');
227 excludeRegexCheckbox
.onchange = function() {
228 document
.getElementById('symbol_filter_exclude_regex').disabled
= !excludeRegexCheckbox
.checked
;
230 var idealSizes
= getIdealSizes();
231 document
.getElementById('width').value
= idealSizes
.width
;
232 document
.getElementById('height').value
= idealSizes
.height
;
233 saveFilterSettings();
236 function filterSetAll(enabled
) {
237 for (var x
=0; x
<=25; x
++) {
238 var checkBox
= document
.getElementById('check_' + x
);
239 checkBox
.checked
= enabled
;
244 function showOptions() {
245 loadFilterSettings();
246 var container
= document
.getElementById('options_container');
247 var w
= container
.offsetWidth
;
248 var h
= container
.offsetHeight
;
249 container
.style
.margin
= '-' + (h
/2) + 'px 0 0 -' + (w/2) + 'px';
250 container
.style
.visibility
= 'visible';
253 function hideOptions() {
254 var container
= document
.getElementById('options_container');
255 container
.style
.visibility
= 'hidden';
258 function applySettings() {
260 var oldWidth
= savedSettings
.width
;
261 var oldHeight
= savedSettings
.height
;
262 var oldSymbols
= savedSettings
.symbolTypes
;
263 var oldRegex
= savedSettings
.regex
;
264 var oldExcludeRegex
= savedSettings
.excludeRegex
;
265 var oldGte
= savedSettings
.gte
;
266 var oldMaxLevels
= savedSettings
.maxLevels
;
267 saveFilterSettings();
268 var resizeNeeded
= oldWidth
!== savedSettings
.width
|| oldHeight
!== savedSettings
.height
;
269 var regexChanged
= oldRegex
!== savedSettings
.regex
;
270 var excludeRegexChanged
= oldExcludeRegex
!== savedSettings
.excludeRegex
;
271 var symbolsChanged
= oldSymbols
!== savedSettings
.symbolTypes
;
272 var gteChanged
= oldGte
!== savedSettings
.gte
;
273 var filterChanged
= regexChanged
|| excludeRegexChanged
|| symbolsChanged
|| gteChanged
;
274 var maxLevelsChanged
= oldMaxLevels
!== savedSettings
.maxLevels
;
278 typeFilter = function(datum
) {
279 if (datum
.depth
=== 0) return true; // root node
280 if (datum
.t
=== undefined) return true;
281 return savedSettings
.symbolTypes
!== undefined &&
282 savedSettings
.symbolTypes
.indexOf(datum
.t
) !== -1;
286 var regexFilter
= undefined;
287 if (savedSettings
.regex
!== undefined && savedSettings
.regex
.length
> 0) {
288 console
.log('filter: regex is "' + savedSettings
.regex
+ '"');
289 var regex
= new RegExp(savedSettings
.regex
);
290 regexFilter = function(datum
) {
291 if (datum
.depth
=== 0) return true; // root node
292 var fullName
= this.pathFor(datum
);
293 if (datum
.children
=== undefined) { // it is a leaf node (symbol)
294 fullName
+= ':' + datum
.n
;
296 return regex
.test(fullName
);
300 // Exclude regex filter
301 var excludeRegexFilter
= undefined;
302 if (savedSettings
.excludeRegex
!== undefined && savedSettings
.excludeRegex
.length
> 0) {
303 console
.log('filter: exclude-regex is "' + savedSettings
.excludeRegex
+ '"');
304 var excludeRegex
= new RegExp(savedSettings
.excludeRegex
);
305 excludeRegexFilter = function(datum
) {
306 if (datum
.depth
=== 0) return true; // root node
307 var fullName
= this.pathFor(datum
);
308 if (datum
.children
=== undefined) { // it is a leaf node (symbol)
309 fullName
+= ':' + datum
.n
;
311 return !excludeRegex
.test(fullName
);
316 var sizeFilter
= undefined;
317 if (savedSettings
.gte
!== undefined) {
318 console
.log('filter: minimum size is ' + savedSettings
.gte
+ ' bytes');
319 sizeFilter = function(datum
) {
320 if (datum
.children
!== undefined) return true; // non-leaf
321 if (datum
.value
=== undefined) console
.log('whoops');
322 return datum
.value
>= savedSettings
.gte
;
326 // Make a filter to apply to the tree
327 var filter = function(datum
) {
328 if (typeFilter
&& !typeFilter
.call(this, datum
)) return false;
329 if (regexFilter
&& !regexFilter
.call(this, datum
)) return false;
330 if (excludeRegexFilter
&& !excludeRegexFilter
.call(this, datum
)) return false;
331 if (sizeFilter
&& !sizeFilter
.call(this, datum
)) return false;
334 treemap
.filter(filter
);
337 // Adjust levels if needed.
338 if (maxLevelsChanged
) {
339 treemap
.setMaxLevels(savedSettings
.maxLevels
);
342 // Resize map if necessary.
344 console
.log('desired treemap dimensions have changed, requesting resize');
345 treemap
.resize(savedSettings
.width
, savedSettings
.height
);
349 function cancelSettings() {
351 loadFilterSettings();
354 function saveFilterSettings() {
355 savedSettings
.symbolTypes
= document
.getElementById('symbol_types_filter').value
;
356 if (document
.getElementById('check_regex').checked
) {
357 savedSettings
.regex
= document
.getElementById('symbol_filter_regex').value
;
359 savedSettings
.regex
= undefined;
361 if (document
.getElementById('check_exclude_regex').checked
) {
362 savedSettings
.excludeRegex
= document
.getElementById('symbol_filter_exclude_regex').value
;
364 savedSettings
.excludeRegex
= undefined;
366 if (document
.getElementById('check_gte').checked
) {
367 savedSettings
.gte
= parseInt(document
.getElementById('symbol_filter_gte').value
);
369 savedSettings
.gte
= undefined;
371 savedSettings
.width
= parseInt(document
.getElementById('width').value
);
372 savedSettings
.height
= parseInt(document
.getElementById('height').value
);
373 savedSettings
.maxLevels
= parseInt(document
.getElementById('max_levels').value
);
376 function loadFilterSettings() {
377 document
.getElementById('symbol_types_filter').value
= savedSettings
.symbolTypes
;
378 symbolFilterTextChanged();
379 if (savedSettings
.regex
!== undefined) {
380 document
.getElementById('check_regex').checked
= true;
381 document
.getElementById('symbol_filter_regex').value
= savedSettings
.regex
;
383 document
.getElementById('check_regex').checked
= false;
385 if (savedSettings
.excludeRegex
!== undefined) {
386 document
.getElementById('check_exclude_regex').checked
= true;
387 document
.getElementById('symbol_filter_exclude_regex').value
= savedSettings
.excludeRegex
;
389 document
.getElementById('check_exclude_regex').checked
= false;
391 if (savedSettings
.gte
!== undefined) {
392 document
.getElementById('check_gte').checked
= true;
393 document
.getElementById('symbol_filter_gte').value
= savedSettings
.gte
;
395 document
.getElementById('check_gte').checked
= false;
397 document
.getElementById('width').value
= savedSettings
.width
;
398 document
.getElementById('height').value
= savedSettings
.height
;
399 document
.getElementById('max_levels').value
= savedSettings
.maxLevels
;
402 function escape(str
) {
403 return str
.replace(/&/g
, '&')
404 .replace(/"/g, '"')
405 .replace(/</g, '<')
406 .replace(/>/g, '>');
410 <body onload='init()'>
411 <div style='position: absolute; top: 5px; left: 5px;'>
412 <input type='button' onclick='showOptions()' value='Options & Legend...'>
413 <span style='-webkit-user-select: none; cursor: help;' title='Click to view the symbol legend or to configure filters and options for the treemap'>[?]</span>
415 <div style='position: absolute; right: 5px; top: 5px; white-space: nowrap;'>
417 <input type='button' onclick='bigSymbolsReport()' value='Large Symbols' title='Click to view a report of the largest 100 symbols that are with the bounds of the treemap that is currently displayed.'>
418 <input type='button' onclick='bigPathsReport()' value='Large Files' title='Click to view a report of the largest 100 source files that are with the bounds of the treemap that is currently displayed.'>
420 <div style='text-align: center; margin-bottom: 5px;'>
421 <span style='font-size: x-large; font-weight: bold; font-variant: small-caps'>Binary Size Analysis<span id='subtitle'></span></span>
422 <br><span style='font-size: small; font-style: italic;'>Double-click a box to zoom in, double-click outermost title to zoom out.</span>
424 <table id='options_container' style='visibility: hidden; border: 3px ridge grey; padding: 0px; top: 50%; left: 50%; position: fixed; z-index: 2147483646; overflow: auto; background-color: rgba(255,255,255,0.9); border-radius: 10px; box-shadow: 10px 10px 5px rgba(80,80,80,0.7);'><tr><td style='vertical-align: top'>
425 <table cellspacing=0 cellborder=0 style='width:100%'>
426 <tr><th colspan=3 style='padding-bottom: .25em; text-decoration: underline;'>Symbol Types To Show</th></tr>
428 <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
429 <span class='swatch' id='swatch_0'> </span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
430 <br><span class='swatch' id='swatch_1'> </span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
431 <br><span class='swatch' id='swatch_2'> </span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
432 <br><span class='swatch' id='swatch_3'> </span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
433 <br><span class='swatch' id='swatch_4'> </span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
434 <br><span class='swatch' id='swatch_5'> </span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
435 <br><span class='swatch' id='swatch_6'> </span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
436 <br><span class='swatch' id='swatch_7'> </span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
437 <br><span class='swatch' id='swatch_8'> </span><input checked type='checkbox' id='check_8' value='i'>Indirect function (i)
439 <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
440 <span class='swatch' id='swatch_9'> </span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
441 <br><span class='swatch' id='swatch_10'> </span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
442 <br><span class='swatch' id='swatch_11'> </span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
443 <br><span class='swatch' id='swatch_12'> </span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
444 <br><span class='swatch' id='swatch_13'> </span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
445 <br><span class='swatch' id='swatch_14'> </span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
446 <br><span class='swatch' id='swatch_15'> </span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
447 <br><span class='swatch' id='swatch_16'> </span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
448 <br><span class='swatch' id='swatch_17'> </span><input checked type='checkbox' id='check_17' value='U'>Undefined (U)
450 <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
451 <span class='swatch' id='swatch_18'> </span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
452 <br><span class='swatch' id='swatch_19'> </span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
453 <br><span class='swatch' id='swatch_20'> </span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
454 <br><span class='swatch' id='swatch_21'> </span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
455 <br><span class='swatch' id='swatch_22'> </span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
456 <br><span class='swatch' id='swatch_23'> </span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
457 <br><span class='swatch' id='swatch_24'> </span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
458 <br><span class='swatch' id='swatch_25'> </span><input checked type='checkbox' id='check_25' value='?'>Unrecognized (?)
461 <tr><td colspan=3 style='text-align: center; white-space: nowrap; padding-top: 1em;'>
462 Select <input type='button' onclick='filterSetAll(true)' value='All'>,
463 <input type='button' onclick='filterSetAll(false)' value='None'>,
464 or type a string: <input id='symbol_types_filter' size=30 value='' onkeyup='symbolFilterTextChanged()' onblur='updateFilterText()'>
465 <span style='-webkit-user-select: none; cursor: help;' title='Enter codes from the list above for the symbols you want to see. The checkboxes will update automatically to match the string that you enter.'>[?]</span>
468 </td></tr><tr><td style='vertical-align: top; padding-top: 10px; border-top: 1px solid grey;'>
469 <table cellspacing=0 cellborder=0 style='width: 100%'>
470 <tr><th colspan=2 style='padding-bottom: .25em; text-decoration: underline;'>Advanced Options</th></tr>
472 <td style='white-space: nowrap; vertical-align: top;'>
473 <input type='checkbox' id='check_regex'>
474 Only include symbols matching this regex:
476 <td style='text-align: right; vertical-align: top;'>
477 <input disabled id='symbol_filter_regex' size=30 value='' style='text-align: right;'>
478 <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Only symbols that match this regex will be shown. This filter applies before any exclusion regex specified below. The format of each symbol is [path]:[symbol_name]'>[?]</span>
482 <td style='white-space: nowrap; vertical-align: top;'>
483 <input type='checkbox' id='check_exclude_regex'>
484 Exclude all symbols matching this regex:
486 <td style='text-align: right; vertical-align: top;'>
487 <input disabled id='symbol_filter_exclude_regex' size=30 value='' style='text-align: right;'>
488 <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Symbols that match this tegex will not be shown. This filter applies after any inclusion filter specified above. The format of each symbol is [path]:[symbol_name]'>[?]</span>
492 <td style='white-space: nowrap; vertical-align: top;'>
493 <input type='checkbox' id='check_gte'>
494 Only include symbols that are at least <span style='font-style: italic;'>n</span> bytes:
496 <td style='text-align: right; vertical-align: top;'>
497 <input disabled id='symbol_filter_gte' size=8 value='' style='text-align: right;'>
498 <span style='-webkit-user-select: none; cursor: help;' title='Symbols whose size is less than this value will be hidden.'>[?]</span>
502 <td style='white-space: nowrap vertical-align: top;;'>
503 Show at most <span style='font-style: italic;'>n</span> levels of detail at a time:
505 <td style='text-align: right; vertical-align: top;'>
506 <input id='max_levels' size=4 value='2' style='text-align: right;'><span style='-webkit-user-select: none; cursor: help;' title='Increasing this value shows more detail without the need to zoom, but uses more computing power.'>[?]</span>
510 <td style='white-space: nowrap vertical-align: top;;'>
511 Set the size of the treemap to <span style='font-style: italic;'>W x H</span> pixels:
513 <td style='text-align: right; vertical-align: top;'>
514 <input id='width' size=4 value='' style='text-align: right;'>
515 x <input id='height' size=4 value='' style='text-align: right;'>
520 <tr><td style='padding-top: 10px; text-align: right; border-top: 1px solid grey'>
521 <input type='button' value='Apply' onclick='applySettings()'>
522 <input type='button' value='Cancel' onclick='cancelSettings()'>