Commit 5cbd0e8c authored by Jasper Chapman-Black's avatar Jasper Chapman-Black Committed by Commit Bot

SuperSize: Filter instead of highlight by flag

This changes both the ndjson-parsing JS library and
the experimental .size-parsing WebAssembly library.

Bug: 1019933
Change-Id: Ic050e4fb2162d29d2a4031f69bd88c43b0bfa6be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1890021
Commit-Queue: Jasper Chapman-Black <jaspercb@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711352}
parent 75f658a1
......@@ -43,7 +43,8 @@ void LoadSizeFile(const char* compressed, size_t size) {
void BuildTree(bool group_by_component,
const char* include_regex_str,
const char* exclude_regex_str,
int minimum_size_bytes) {
int minimum_size_bytes,
int match_flag) {
std::vector<std::function<bool(const Symbol&)>> filters;
if (minimum_size_bytes > 0) {
......@@ -52,6 +53,14 @@ void BuildTree(bool group_by_component,
});
}
// It's currently not useful to filter on more than one flag, so |match_flag|
// can be assumed to be a power of two.
if (match_flag) {
std::cout << "Filtering on flag matching " << match_flag << std::endl;
filters.push_back(
[match_flag](const Symbol& sym) { return match_flag & sym.flags; });
}
std::unique_ptr<RE2> include_regex;
if (include_regex_str && *include_regex_str) {
include_regex.reset(new RE2(include_regex_str));
......
......@@ -98,9 +98,8 @@ NodeStats::~NodeStats() = default;
NodeStats::NodeStats(SectionId sectionId,
int32_t count,
int32_t highlight,
float size) {
child_stats[sectionId] = {count, highlight, size};
child_stats[sectionId] = {count, size};
}
void NodeStats::WriteIntoJson(Json::Value* out) const {
......@@ -111,7 +110,6 @@ void NodeStats::WriteIntoJson(Json::Value* out) const {
(*out)[sectionId] = Json::Value(Json::objectValue);
(*out)[sectionId]["size"] = stats.size;
(*out)[sectionId]["count"] = stats.count;
(*out)[sectionId]["highlight"] = stats.highlight;
}
}
......
......@@ -85,12 +85,10 @@ struct SizeInfo {
struct Stat {
int32_t count = 0;
int32_t highlight = 0;
float size = 0.0f;
void operator+=(const Stat& other) {
count += other.count;
highlight += other.highlight;
size += other.size;
}
};
......@@ -98,7 +96,7 @@ struct Stat {
struct NodeStats {
NodeStats();
~NodeStats();
NodeStats(SectionId section, int32_t count, int32_t highlight, float size);
NodeStats(SectionId section, int32_t count, float size);
void WriteIntoJson(Json::Value* out) const;
NodeStats& operator+=(const NodeStats& other);
SectionId ComputeBiggestSection() const;
......
......@@ -124,9 +124,8 @@ void TreeBuilder::AddFileEntry(const std::string_view source_path,
symbol_node->container_type = ContainerType::kSymbol;
symbol_node->id_path = sym->full_name;
symbol_node->size = sym->pss();
symbol_node->node_stats =
NodeStats(size_info_->ShortSectionName(sym->section_name), 1, 0,
symbol_node->size);
symbol_node->node_stats = NodeStats(
size_info_->ShortSectionName(sym->section_name), 1, symbol_node->size);
AttachToParent(symbol_node, file_node);
}
......
......@@ -323,7 +323,6 @@ const displayInfocard = (() => {
(a, b) => b[1].size - a[1].size
);
const diffMode = state.has('diff_mode');
const highlightMode = state.has('highlight');
let totalSize = 0;
for (const [, stats] of statsEntries) {
totalSize += Math.abs(stats.size);
......@@ -343,13 +342,6 @@ const displayInfocard = (() => {
const angleEnd = angleStart + arcLength;
this._drawSlice(angleStart, angleEnd, color);
if (highlightMode) {
const highlightPercent = stats.highlight / totalSize;
const highlightArcLength = Math.abs(highlightPercent) * 2 * Math.PI;
const highlightEnd = (angleStart + highlightArcLength);
this._drawBorder(angleStart, highlightEnd, '#feefc3', 32);
}
if (diffMode) {
const strokeColor = stats.size > 0 ? '#ea4335' : '#34a853';
this._drawBorder(angleStart, angleEnd, strokeColor, 16);
......
......@@ -188,9 +188,6 @@ ul {
.grew {
color: #ea4335;
}
.highlight {
background: #feefc3;
}
.diff .size-header::after {
content: " diff";
......
......@@ -34,8 +34,6 @@
* a certain type.
* @prop {number} size Byte size
* @prop {number} count Number of symbols
* @prop {number} highlight Byte size of children that should be
* highlighted.
*/
/**
......
......@@ -40,22 +40,6 @@ const newTreeElement = (() => {
*/
const _uiNodeData = new WeakMap();
/**
* Applies highlights to the tree element based on certain flags and state.
* @param {HTMLSpanElement} symbolNameElement Element that displays the
* short name of the tree item.
* @param {TreeNode} node Data about this symbol name element's tree node.
*/
function _highlightSymbolName(symbolNameElement, node) {
const dexMethodStats = node.childStats[_DEX_METHOD_SYMBOL_TYPE];
if (state.has('highlight')) {
const stats = Object.values(node.childStats);
if (stats.some(stat => stat.highlight > 0)) {
symbolNameElement.classList.add('highlight');
}
}
}
/**
* Replace the contents of the size element for a tree node.
* @param {HTMLElement} sizeElement Element that should display the size
......@@ -350,7 +334,6 @@ const newTreeElement = (() => {
_ZERO_WIDTH_SPACE
);
symbolName.title = data.idPath;
_highlightSymbolName(symbolName, data);
// Set the byte size and hover text
_setSize(element.querySelector('.size'), data);
......
......@@ -144,7 +144,7 @@ const fetcher = new DataFetcher('data.size');
let sizeFileLoaded = false;
async function buildTree(
groupBy, includeRegex, excludeRegex, minSymbolSize, highlightTest,
groupBy, includeRegex, excludeRegex, minSymbolSize, flagToFilter,
methodCountMode, onProgress) {
if (!sizeFileLoaded) {
let sizeBuffer = await fetcher.loadSizeBuffer();
......@@ -189,11 +189,13 @@ async function buildTree(
return message;
}
let BuildTree =
Module.cwrap('BuildTree', 'void', ['bool', 'string', 'string', 'number']);
let BuildTree = Module.cwrap(
'BuildTree', 'void', ['bool', 'string', 'string', 'number', 'number']);
let start_time = Date.now();
const groupByComponent = groupBy === 'component';
BuildTree(groupByComponent, includeRegex, excludeRegex, minSymbolSize);
BuildTree(
groupByComponent, includeRegex, excludeRegex, minSymbolSize,
flagToFilter);
console.log('Constructed tree in ' +
(Date.now() - start_time)/1000.0 + ' seconds');
......@@ -215,8 +217,7 @@ function parseOptions(options) {
const url = params.get('load_url');
const groupBy = params.get('group_by') || 'source_path';
const methodCountMode = params.has('method_count');
const filterGeneratedFiles = params.has('generated_filter');
const flagToHighlight = _NAMES_TO_FLAGS[params.get('highlight')];
const flagToFilter = _NAMES_TO_FLAGS[params.get('flag_filter')] || 0;
let minSymbolSize = Number(params.get('min_size'));
if (Number.isNaN(minSymbolSize)) {
......@@ -226,15 +227,12 @@ function parseOptions(options) {
const includeRegex = params.get('include');
const excludeRegex = params.get('exclude');
function highlightTest(symbolNode) {
return false;
}
return {
groupBy,
includeRegex,
excludeRegex,
minSymbolSize,
highlightTest,
flagToFilter,
url,
methodCountMode
};
......@@ -248,7 +246,7 @@ const actions = {
includeRegex,
excludeRegex,
minSymbolSize,
highlightTest,
flagToFilter,
url,
methodCountMode
} = parseOptions(options);
......@@ -262,7 +260,7 @@ const actions = {
}
return buildTree(
groupBy, includeRegex, excludeRegex, minSymbolSize, highlightTest,
groupBy, includeRegex, excludeRegex, minSymbolSize, flagToFilter,
methodCountMode, progress => {
// @ts-ignore
self.postMessage(progress);
......
......@@ -40,7 +40,6 @@ const _PATH_SEP = '/';
const _NAMES_TO_FLAGS = Object.freeze({
hot: _FLAGS.HOT,
generated: _FLAGS.GENERATED_SOURCE,
coverage: _FLAGS.COVERAGE,
uncompressed: _FLAGS.UNCOMPRESSED,
});
......@@ -137,8 +136,6 @@ class TreeBuilder {
* @param {(symbolNode: TreeNode) => boolean} options.filterTest Called to see
* if a symbol should be included. If a symbol fails the test, it will not be
* attached to the tree.
* @param {(symbolNode: TreeNode) => boolean} options.highlightTest Called to
* see if a symbol should be highlighted.
* @param {boolean} options.methodCountMode Whether we're in "method count"
* mode.
* @param {string} options.sep Path seperator used to find parent names.
......@@ -147,7 +144,6 @@ class TreeBuilder {
constructor(options) {
this._getPath = options.getPath;
this._filterTest = options.filterTest;
this._highlightTest = options.highlightTest;
this._methodCountMode = options.methodCountMode;
this._sep = options.sep || _PATH_SEP;
this._meta = options.meta;
......@@ -198,13 +194,12 @@ class TreeBuilder {
for (const [type, stat] of additionalStats) {
let parentStat = parent.childStats[type];
if (parentStat == null) {
parentStat = {size: 0, count: 0, highlight: 0};
parentStat = {size: 0, count: 0};
parent.childStats[type] = parentStat;
}
parentStat.size += stat.size;
parentStat.count += stat.count;
parentStat.highlight += stat.highlight;
const absSize = Math.abs(parentStat.size);
if (absSize > lastBiggestSize) {
......@@ -439,14 +434,10 @@ class TreeBuilder {
[type]: {
size,
count,
highlight: 0,
},
},
});
if (this._highlightTest(symbolNode)) {
symbolNode.childStats[type].highlight = size;
}
if (this._filterTest(symbolNode)) {
this._attachToParent(symbolNode, fileNode);
}
......@@ -651,8 +642,7 @@ function parseOptions(options) {
const url = params.get('load_url');
const groupBy = params.get('group_by') || 'source_path';
const methodCountMode = params.has('method_count');
const filterGeneratedFiles = params.has('generated_filter');
const flagToHighlight = _NAMES_TO_FLAGS[params.get('highlight')];
const flagToFilter = _NAMES_TO_FLAGS[params.get('flag_filter')];
let minSymbolSize = Number(params.get('min_size'));
if (Number.isNaN(minSymbolSize)) {
......@@ -690,9 +680,9 @@ function parseOptions(options) {
filters.push(s => typeFilter.has(s.type));
}
// Only show generated files
if (filterGeneratedFiles) {
filters.push(s => hasFlag(_FLAGS.GENERATED_SOURCE, s));
// Only show symbols with attached flag
if (flagToFilter) {
filters.push(s => hasFlag(flagToFilter, s));
}
// Search symbol names using regex
......@@ -721,15 +711,7 @@ function parseOptions(options) {
return filters.every(fn => fn(symbolNode));
}
/** @type {(symbolNode: TreeNode) => boolean} */
let highlightTest;
if (flagToHighlight) {
highlightTest = symbolNode => hasFlag(flagToHighlight, symbolNode);
} else {
highlightTest = () => false;
}
return {groupBy, filterTest, highlightTest, url, methodCountMode};
return {groupBy, filterTest, url, methodCountMode};
}
/** @type {TreeBuilder | null} */
......@@ -741,14 +723,11 @@ const fetcher = new DataFetcher('data.ndjson');
* @param {string} groupBy Sets how the tree is grouped.
* @param {(symbolNode: TreeNode) => boolean} filterTest Filter function that
* each symbol is tested against
* @param {(symbolNode: TreeNode) => boolean} highlightTest Filter function that
* each symbol's flags are tested against
* @param {boolean} methodCountMode
* @param {(msg: TreeProgress) => void} onProgress
* @returns {Promise<TreeProgress>}
*/
async function buildTree(
groupBy, filterTest, highlightTest, methodCountMode, onProgress) {
async function buildTree(groupBy, filterTest, methodCountMode, onProgress) {
/** @type {Meta | null} Object from the first line of the data file */
let meta = null;
......@@ -812,7 +791,6 @@ async function buildTree(
builder = new TreeBuilder({
getPath: getPathMap[groupBy],
filterTest,
highlightTest,
methodCountMode,
sep: groupBy === 'component' ? '>' : _PATH_SEP,
meta,
......@@ -847,8 +825,7 @@ async function buildTree(
const actions = {
/** @param {{input:string|null,options:string}} param0 */
load({input, options}) {
const {groupBy, filterTest, highlightTest, url, methodCountMode} =
parseOptions(options);
const {groupBy, filterTest, url, methodCountMode} = parseOptions(options);
if (input === 'from-url://' && url) {
// Display the data from the `load_url` query parameter
console.info('Displaying data from', url);
......@@ -859,7 +836,7 @@ const actions = {
}
return buildTree(
groupBy, filterTest, highlightTest, methodCountMode, progress => {
groupBy, filterTest, methodCountMode, progress => {
// @ts-ignore
self.postMessage(progress);
});
......
......@@ -207,34 +207,25 @@ if ('serviceWorker' in navigator) {
<button type="button" class="text-button" id="type-none">Select none</button>
</fieldset>
<fieldset id="highlight-container">
<legend class="subhead">Highlight symbols</legend>
<fieldset id="flag-container">
<legend class="subhead">Filter symbols</legend>
<div class="radio-wrapper">
<input type="radio" id="clearhighlight" name="highlight" value="clear" checked>
<label class="radio-label" for="clearhighlight">None</label>
<input type="radio" id="clearflag" name="flag_filter" value="clear" checked>
<label class="radio-label" for="clearflag">All</label>
</div>
<div class="radio-wrapper">
<input type="radio" id="hothighlight" name="highlight" value="hot">
<label class="radio-label" for="hothighlight">Hot code</label>
<input type="radio" id="hotflag" name="flag_filter" value="hot">
<label class="radio-label" for="hotflag">Hot code</label>
</div>
<div class="radio-wrapper">
<input type="radio" id="generatedhighlight" name="highlight" value="generated">
<label class="radio-label" for="generatedhighlight">Generated files</label>
<input type="radio" id="generatedflag" name="flag_filter" value="generated">
<label class="radio-label" for="generatedflag">Generated files</label>
</div>
<div class="radio-wrapper">
<input type="radio" id="coveragehightlight" name="highlight" value="coverage">
<label class="radio-label" for="coveragehightlight">Code coverage (not implemented)</label>
</div>
<div class="radio-wrapper">
<input type="radio" id="uncompressedhighlight" name="highlight" value="uncompressed">
<label class="radio-label" for="uncompressedhighlight">Uncompressed .pak files</label>
<input type="radio" id="uncompressedflag" name="flag_filter" value="uncompressed">
<label class="radio-label" for="uncompressedflag">Uncompressed .pak files</label>
</div>
</fieldset>
<p class="checkbox-wrapper">
<input type="checkbox" id="generatedfilter" name="generated_filter" value="on">
<label class="checkbox-label" for="generatedfilter">Show only generated files</label>
</p>
</form>
<div class="symbols">
<!-- Icons for symbols are stored here and cloned. -->
......
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