Commit 09c50c62 authored by Samuel Huang's avatar Samuel Huang Committed by Commit Bot

[SuperSize] Tiger Viewer: Add symbol grouping by container.

This CL adds the "Container" option under "Group symbols by". This is
meaningful only for .size / .sizediff files with multiple containers.

Bug: 1040645
Change-Id: I93ea1548c3c11f7dbcbbdd4779e378715c1c373a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2362989Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Commit-Queue: Samuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799131}
parent 3a42ed0d
...@@ -78,7 +78,7 @@ if (is_wasm) { ...@@ -78,7 +78,7 @@ if (is_wasm) {
"-s", "-s",
"ALLOW_MEMORY_GROWTH=1", "ALLOW_MEMORY_GROWTH=1",
"-s", "-s",
"EXPORTED_FUNCTIONS=['_LoadSizeFile','_LoadBeforeSizeFile','_BuildTree','_Open','_malloc','_free']", "EXPORTED_FUNCTIONS=['_LoadSizeFile','_LoadBeforeSizeFile','_BuildTree','_Open','_QueryProperty','_malloc','_free']",
"-s", "-s",
"EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString']", "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString']",
] ]
......
...@@ -55,6 +55,11 @@ bool MatchesRegex(const GroupedPath& id_path, ...@@ -55,6 +55,11 @@ bool MatchesRegex(const GroupedPath& id_path,
return RE2::PartialMatch(Re2StringPiece(sym.FullName()), regex); return RE2::PartialMatch(Re2StringPiece(sym.FullName()), regex);
} }
bool IsMultiContainer() {
// If DeltaSizeInfo is active, still take |info| since it's the "after" info.
return info->containers.size() > 1 || !info->containers[0].name.empty();
}
} // namespace } // namespace
extern "C" { extern "C" {
...@@ -177,6 +182,8 @@ bool BuildTree(bool method_count_mode, ...@@ -177,6 +182,8 @@ bool BuildTree(bool method_count_mode,
std::cout << "group_by=" << group_by << std::endl; std::cout << "group_by=" << group_by << std::endl;
if (!strcmp(group_by, "source_path")) { if (!strcmp(group_by, "source_path")) {
lens = std::make_unique<IdPathLens>(); lens = std::make_unique<IdPathLens>();
} else if (!strcmp(group_by, "container")) {
lens = std::make_unique<ContainerLens>();
} else if (!strcmp(group_by, "component")) { } else if (!strcmp(group_by, "component")) {
lens = std::make_unique<ComponentLens>(); lens = std::make_unique<ComponentLens>();
sep = '>'; sep = '>';
...@@ -196,12 +203,22 @@ bool BuildTree(bool method_count_mode, ...@@ -196,12 +203,22 @@ bool BuildTree(bool method_count_mode,
return bool(diff_info); return bool(diff_info);
} }
// Returns a string that can be parsed to a JS object.
const char* Open(const char* path) { const char* Open(const char* path) {
// Returns a string that can be parsed to a JS object.
static std::string result; static std::string result;
Json::Value v = builder->Open(path); Json::Value v = builder->Open(path);
result = JsonSerialize(v); result = JsonSerialize(v);
return result.c_str(); return result.c_str();
} }
// Returns global properties.
const char* QueryProperty(const char* key) {
if (!strcmp(key, "isMultiContainer")) {
return IsMultiContainer() ? "true" : "false";
}
std::cerr << "Unknown property: " << key << std::endl;
exit(1);
}
} // extern "C" } // extern "C"
} // namespace caspian } // namespace caspian
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
namespace { namespace {
constexpr const char* kDefaultContainer = "(Default container)";
constexpr const char* kNoComponent = "(No component)"; constexpr const char* kNoComponent = "(No component)";
bool PartialMatch(std::string_view view, const RE2& regex) { bool PartialMatch(std::string_view view, const RE2& regex) {
...@@ -33,6 +34,14 @@ std::string_view IdPathLens::ParentName(const BaseSymbol& symbol) { ...@@ -33,6 +34,14 @@ std::string_view IdPathLens::ParentName(const BaseSymbol& symbol) {
return ""; return "";
} }
std::string_view ContainerLens::ParentName(const BaseSymbol& symbol) {
std::string component;
if (symbol.ContainerName() && *symbol.ContainerName()) {
return symbol.ContainerName();
}
return kDefaultContainer;
}
std::string_view ComponentLens::ParentName(const BaseSymbol& symbol) { std::string_view ComponentLens::ParentName(const BaseSymbol& symbol) {
std::string component; std::string component;
if (symbol.Component() && *symbol.Component()) { if (symbol.Component() && *symbol.Component()) {
......
...@@ -21,6 +21,11 @@ class IdPathLens : public BaseLens { ...@@ -21,6 +21,11 @@ class IdPathLens : public BaseLens {
std::string_view ParentName(const BaseSymbol& symbol) override; std::string_view ParentName(const BaseSymbol& symbol) override;
}; };
class ContainerLens : public BaseLens {
public:
std::string_view ParentName(const BaseSymbol& symbol) override;
};
class ComponentLens : public BaseLens { class ComponentLens : public BaseLens {
public: public:
std::string_view ParentName(const BaseSymbol& symbol) override; std::string_view ParentName(const BaseSymbol& symbol) override;
......
...@@ -53,10 +53,17 @@ ...@@ -53,10 +53,17 @@
* include DOM elements for styling. * include DOM elements for styling.
* @prop {number} value The size number used to create the other strings. * @prop {number} value The size number used to create the other strings.
*/ */
/** /**
* @typedef {(node: TreeNode, unit: string) => GetSizeResult} GetSize * @typedef {(node: TreeNode, unit: string) => GetSizeResult} GetSize
*/ */
/**
* @typedef {object} SizeProperties Properties loaded from .size / .sizediff
* files.
* @prop {boolean} isMultiContainer Whether multiple containers exist.
*/
/** /**
* Abberivated keys used by FileEntrys in the JSON data file. These must match * Abberivated keys used by FileEntrys in the JSON data file. These must match
* _COMPACT_*_KEY variables in html_report.py. * _COMPACT_*_KEY variables in html_report.py.
......
...@@ -451,7 +451,11 @@ const newTreeElement = (() => { ...@@ -451,7 +451,11 @@ const newTreeElement = (() => {
); );
} }
window.supersize.treeReady.then(displayTree); window.supersize.treeReady.then((message) => {
document.querySelector('#group-by-container')
.toggleAttribute('disabled', !message.isMultiContainer);
displayTree(message);
});
window.supersize.worker.setOnProgressHandler(displayTree); window.supersize.worker.setOnProgressHandler(displayTree);
_fileUpload.addEventListener('change', event => { _fileUpload.addEventListener('change', event => {
......
...@@ -136,9 +136,12 @@ async function Open(name) { ...@@ -136,9 +136,12 @@ async function Open(name) {
} }
// Placeholder input name until supplied via setInput() // Placeholder input name until supplied via setInput()
const fetcher = new DataFetcher('data.ndjson'); const g_fetcher = new DataFetcher('data.ndjson');
let beforeFetcher = null; let g_beforeFetcher = null;
let sizeFileLoaded = false; let g_sizeFileLoaded = false;
/** @type {SizeProperties} */
let g_size_properties = null;
async function loadSizeFile(isBefore, fetcher) { async function loadSizeFile(isBefore, fetcher) {
const sizeBuffer = await fetcher.loadSizeBuffer(); const sizeBuffer = await fetcher.loadSizeBuffer();
...@@ -153,20 +156,34 @@ async function loadSizeFile(isBefore, fetcher) { ...@@ -153,20 +156,34 @@ async function loadSizeFile(isBefore, fetcher) {
Module._free(heapBuffer.byteOffset); Module._free(heapBuffer.byteOffset);
} }
async function loadSizeProperties() {
const QueryProperty = Module.cwrap('QueryProperty', 'number', ['string']);
const getProperty = (key) => {
const stringPtr = QueryProperty(key);
const r = Module.UTF8ToString(stringPtr, 2 ** 16);
return r;
};
g_size_properties = {
isMultiContainer: (getProperty('isMultiContainer') === 'true')
};
}
async function buildTree( async function buildTree(
groupBy, includeRegex, excludeRegex, includeSections, minSymbolSize, groupBy, includeRegex, excludeRegex, includeSections, minSymbolSize,
flagToFilter, methodCountMode, onProgress) { flagToFilter, methodCountMode, onProgress) {
onProgress({percent: 0.1, id: 0}); onProgress({percent: 0.1, id: 0});
/** @type {Metadata} */
return await LoadWasm.then(async () => { return await LoadWasm.then(async () => {
if (!sizeFileLoaded) { if (!g_sizeFileLoaded) {
const current = loadSizeFile(false, fetcher); const load_promises = [];
const before = load_promises.push(loadSizeFile(false, g_fetcher));
beforeFetcher !== null ? loadSizeFile(true, beforeFetcher) : null; if (g_beforeFetcher !== null) {
await current; load_promises.push(loadSizeFile(true, g_beforeFetcher));
await before; }
await Promise.all(load_promises).then(loadSizeProperties);
onProgress({percent: 0.4, id: 0}); onProgress({percent: 0.4, id: 0});
sizeFileLoaded = true; g_sizeFileLoaded = true;
} }
const BuildTree = Module.cwrap( const BuildTree = Module.cwrap(
...@@ -186,6 +203,7 @@ async function buildTree( ...@@ -186,6 +203,7 @@ async function buildTree(
root, root,
percent: 1.0, percent: 1.0,
diffMode, diffMode,
isMultiContainer: g_size_properties.isMultiContainer,
}; };
}); });
} }
...@@ -251,19 +269,19 @@ const actions = { ...@@ -251,19 +269,19 @@ const actions = {
beforeUrl, beforeUrl,
} = parseOptions(options); } = parseOptions(options);
if (accessToken) { if (accessToken) {
fetcher.setAccessToken(accessToken); g_fetcher.setAccessToken(accessToken);
} }
if (input === 'from-url://' && url) { if (input === 'from-url://' && url) {
// Display the data from the `load_url` query parameter // Display the data from the `load_url` query parameter
console.info('Displaying data from', url); console.info('Displaying data from', url);
fetcher.setInput(url); g_fetcher.setInput(url);
} else if (input != null) { } else if (input != null) {
console.info('Displaying uploaded data'); console.info('Displaying uploaded data');
fetcher.setInput(input); g_fetcher.setInput(input);
} }
if (beforeUrl) { if (beforeUrl) {
beforeFetcher = new DataFetcher(beforeUrl); g_beforeFetcher = new DataFetcher(beforeUrl);
} }
return buildTree( return buildTree(
...@@ -315,4 +333,3 @@ self.onmessage = async event => { ...@@ -315,4 +333,3 @@ self.onmessage = async event => {
runAction(id, action, data); runAction(id, action, data);
} }
}; };
...@@ -762,6 +762,7 @@ async function buildTree(groupBy, filterTest, methodCountMode, onProgress) { ...@@ -762,6 +762,7 @@ async function buildTree(groupBy, filterTest, methodCountMode, onProgress) {
root: builder.formatNode(data.root || builder.rootNode), root: builder.formatNode(data.root || builder.rootNode),
percent, percent,
diffMode: meta && meta.diff_mode, diffMode: meta && meta.diff_mode,
isMultiContainer: false,
}; };
if (data.error) { if (data.error) {
message.error = data.error.message; message.error = data.error.message;
......
...@@ -121,20 +121,39 @@ ...@@ -121,20 +121,39 @@
<fieldset> <fieldset>
<legend class="subhead">Group symbols by</legend> <legend class="subhead">Group symbols by</legend>
<div class="radio-wrapper"> <div class="radio-wrapper">
<input type="radio" id="sourcepath" name="group_by" value="source_path" checked> <input type="radio"
<label class="radio-label" for="sourcepath">Nothing</label> id="group-by-sourcepath"
name="group_by"
value="source_path" checked>
<label class="radio-label" for="group-by-sourcepath">Nothing</label>
</div>
<div class="radio-wrapper show-if-multi-container">
<input type="radio"
id="group-by-container"
name="group_by"
value="container">
<label class="radio-label" for="group-by-container">Container</label>
</div> </div>
<div class="radio-wrapper"> <div class="radio-wrapper">
<input type="radio" id="component" name="group_by" value="component"> <input type="radio"
<label class="radio-label" for="component">Component</label> id="group-by-component"
name="group_by"
value="component">
<label class="radio-label" for="group-by-component">Component</label>
</div> </div>
<div class="radio-wrapper"> <div class="radio-wrapper">
<input type="radio" id="template" name="group_by" value="template"> <input type="radio"
<label class="radio-label" for="template">Template</label> id="group-by-template"
name="group_by"
value="template">
<label class="radio-label" for="group-by-template">Template</label>
</div> </div>
<div class="radio-wrapper"> <div class="radio-wrapper">
<input type="radio" id="generated_type" name="group_by" value="generated_type"> <input type="radio"
<label class="radio-label" for="generated_type">Generated type</label> id="group-by-generated_type"
name="group_by"
value="generated_type">
<label class="radio-label" for="group-by-generated_type">Generated type</label>
</div> </div>
</fieldset> </fieldset>
......
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