Commit a444ac46 authored by Andrew Grieve's avatar Andrew Grieve Committed by Commit Bot

SuperSize: Add --method-count to html_report

This generates an html report that shows java method counts rather than
binary size.

Change-Id: I6d6ba23969fa495e714ea3d1264cd1dbf61bd4bc
Reviewed-on: https://chromium-review.googlesource.com/1055855Reviewed-by: default avatarPeter Wen <wnwen@chromium.org>
Commit-Queue: agrieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558303}
parent 454c4015
......@@ -239,6 +239,9 @@ Example Usage:
``` bash
tools/binary_size/supersize html_report chrome.size --report-dir size-report -v
xdg-open size-report/index.html
# Report showing Dex method counts rather than binary size:
tools/binary_size/supersize html_report chrome.size --report-dir size-report -v --method-count
```
### Usage: diff
......
......@@ -135,6 +135,7 @@ def ParseJava(name):
if '(' in name:
package, method_sig = name.split(' ', 1)
class_name = package.split('.')[-1]
# E.g. <init>() <-- no return type
if method_sig.startswith('<'):
method_name = method_sig
else:
......
......@@ -18,6 +18,7 @@ import path_util
# Node dictionary keys. These are output in json read by the webapp so
# keep them short to save file size.
# Note: If these change, the webapp must also change.
_METHOD_COUNT_MODE_KEY = 'methodCountMode'
_NODE_TYPE_KEY = 'k'
_NODE_TYPE_BUCKET = 'b'
_NODE_TYPE_PATH = 'p'
......@@ -91,6 +92,21 @@ def _MakeChildrenDictsIntoLists(node):
len(children))
def _CombineSingleChildNodes(node):
"""Collapse "java"->"com"->"google" into ."java/com/google"."""
children = node.get(_NODE_CHILDREN_KEY)
if children:
child = children[0]
if len(children) == 1 and node[_NODE_TYPE_KEY] == child[_NODE_TYPE_KEY]:
node[_NODE_NAME_KEY] = '{}/{}'.format(
node[_NODE_NAME_KEY], child[_NODE_NAME_KEY])
node[_NODE_CHILDREN_KEY] = child[_NODE_CHILDREN_KEY]
_CombineSingleChildNodes(node)
else:
for child in children:
_CombineSingleChildNodes(child)
def _AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size,
min_symbol_size):
"""Puts symbol into the file path node |node|."""
......@@ -112,12 +128,16 @@ def _AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size,
node[_NODE_SYMBOL_TYPE_KEY] = symbol_type
def _MakeCompactTree(symbols, min_symbol_size):
def _MakeCompactTree(symbols, min_symbol_size, method_count_mode):
if method_count_mode:
# Include all symbols and avoid bucket nodes.
min_symbol_size = -1
result = {
_NODE_NAME_KEY: '/',
_NODE_CHILDREN_KEY: {},
_NODE_TYPE_KEY: 'p',
_NODE_MAX_DEPTH_KEY: 0,
_METHOD_COUNT_MODE_KEY: bool(method_count_mode),
}
for symbol in symbols:
file_path = symbol.source_path or symbol.object_path or _NAME_NO_PATH_BUCKET
......@@ -134,7 +154,8 @@ def _MakeCompactTree(symbols, min_symbol_size):
symbol_type = _NODE_SYMBOL_TYPE_VTABLE
elif symbol.name.endswith(']'):
symbol_type = _NODE_SYMBOL_TYPE_GENERATED
_AddSymbolIntoFileNode(node, symbol_type, symbol.template_name, symbol.pss,
symbol_size = 1 if method_count_mode else symbol.pss
_AddSymbolIntoFileNode(node, symbol_type, symbol.template_name, symbol_size,
min_symbol_size)
depth += 2
result[_NODE_MAX_DEPTH_KEY] = max(result[_NODE_MAX_DEPTH_KEY], depth)
......@@ -146,6 +167,7 @@ def _MakeCompactTree(symbols, min_symbol_size):
_SplitLargeBucket(no_path_bucket)
_MakeChildrenDictsIntoLists(result)
_CombineSingleChildNodes(result)
return result
......@@ -174,6 +196,8 @@ def AddArguments(parser):
parser.add_argument('--min-symbol-size', type=float, default=1024,
help='Minimum size (PSS) for a symbol to be included as '
'an independent node.')
parser.add_argument('--method-count', action='store_true',
help='Show dex method count rather than size')
def Run(args, parser):
......@@ -183,9 +207,10 @@ def Run(args, parser):
logging.info('Reading .size file')
size_info = archive.LoadAndPostProcessSizeInfo(args.input_file)
symbols = size_info.raw_symbols
if not args.include_bss:
if args.method_count:
symbols = symbols.WhereInSection('m')
elif not args.include_bss:
symbols = symbols.WhereInSection('b').Inverted()
symbols = symbols.WherePssBiggerThan(0)
# Copy report boilerplate into output directory. This also proves that the
# output directory is safe for writing, so there should be no problems writing
......@@ -193,7 +218,7 @@ def Run(args, parser):
_CopyTemplateFiles(args.report_dir)
logging.info('Creating JSON objects')
tree_root = _MakeCompactTree(symbols, args.min_symbol_size)
tree_root = _MakeCompactTree(symbols, args.min_symbol_size, args.method_count)
logging.info('Serializing JSON')
with open(os.path.join(args.report_dir, 'data.js'), 'w') as out_file:
......
......@@ -12,6 +12,7 @@ function D3SymbolTreeMap(mapWidth, mapHeight, levelsToShow) {
this._mapHeight = mapHeight;
this.boxPadding = {'l': 5, 'r': 5, 't': 20, 'b': 5};
this.infobox = undefined;
this.methodCountMode = false;
this._maskContainer = undefined;
this._highlightContainer = undefined;
// Transition in this order:
......@@ -53,7 +54,10 @@ D3SymbolTreeMap._pretty = function(num) {
* Express a number in terms of KiB, MiB, GiB, etc.
* Note that these are powers of 2, not of 10.
*/
D3SymbolTreeMap._byteify = function(num) {
D3SymbolTreeMap.prototype._byteify = function(num) {
if (this.methodCountMode) {
return num + ' methods';
}
var suffix;
if (num >= 1024) {
if (num >= 1024 * 1024 * 1024) {
......@@ -145,6 +149,7 @@ D3SymbolTreeMap.prototype.init = function() {
.style('margin', 0)
.style('box-shadow', '5px 5px 5px #888');
this._layout = this._createTreeMapLayout();
this.methodCountMode = tree_data['methodCountMode'];
this._setData(tree_data); // TODO: Don't use global 'tree_data'
}
......@@ -446,7 +451,7 @@ D3SymbolTreeMap.prototype._handleInodes = function() {
return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
})
.text(function(datum) {
var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
var sizeish = ' [' + thisTreeMap._byteify(datum.value) + ']'
var text;
if (datum.k === 'b') { // bucket
if (datum === thisTreeMap._currentRoot) {
......@@ -515,7 +520,7 @@ D3SymbolTreeMap.prototype._handleInodes = function() {
.style('width', function(datum) { return datum.dx; })
.style('height', function(datum) { return thisTreeMap.boxPadding.t; })
.text(function(datum) {
var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
var sizeish = ' [' + thisTreeMap._byteify(datum.value) + ']'
var text;
if (datum.k === 'b') {
if (datum === thisTreeMap._currentRoot) {
......@@ -758,8 +763,10 @@ D3SymbolTreeMap.prototype._createInfoBox = function() {
D3SymbolTreeMap.prototype._showInfoBox = function(datum) {
this.infobox.text('');
var numSymbols = 0;
var sizeish = D3SymbolTreeMap._pretty(datum.value) + ' bytes (' +
D3SymbolTreeMap._byteify(datum.value) + ')';
var sizeish = this._byteify(datum.value);
if (!this.methodCountMode) {
sizeish = D3SymbolTreeMap._pretty(datum.value) + ' bytes (' + sizeish + ')'
}
if (datum.k === 'p' || datum.k === 'b') { // path or bucket
if (datum.symbol_stats) { // can be empty if filters are applied
for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
......@@ -793,10 +800,11 @@ D3SymbolTreeMap.prototype._showInfoBox = function(datum) {
this.infobox.append('div').text('Location: ' + this.pathFor(datum))
}
}
if (datum.k === 'p') {
if (datum.k === 'p' && !this.methodCountMode) {
this.infobox.append('div')
.text('Number of symbols: ' + D3SymbolTreeMap._pretty(numSymbols));
if (datum.symbol_stats) { // can be empty if filters are applied
// can be empty if filters are applied
if (datum.symbol_stats) {
var table = this.infobox.append('table')
.attr('border', 1).append('tbody');
var header = table.append('tr');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment