Commit 9c10bfec authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools][system-analyzer] Improve map stats panel

- Introduce LazyTable that only shows the first 100 entries and can
  lazily expand
- Make StatsPanel.update method async to not block the UI
- Show "Total" entry as last item in StatsPanel tables
- Fix StatsPanel table entries text alignment
- Remove unused getters from StatsPanel class

Drive-by-fix:
- MapPanel._displayedMapsInTree is undefined when expanding to
  a sub-transition tree

Bug: v8:10644
Change-Id: I5ce7c8b1ee825515cf790a3e52534c3069d8be89
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2507716
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70903}
parent 32250399
...@@ -186,11 +186,37 @@ class V8CustomElement extends HTMLElement { ...@@ -186,11 +186,37 @@ class V8CustomElement extends HTMLElement {
removeAllChildren(node) { return removeAllChildren(node); } removeAllChildren(node) { return removeAllChildren(node); }
} }
class LazyTable {
constructor(table, rowData, rowElementCreator) {
this._table = table;
this._rowData = rowData;
this._rowElementCreator = rowElementCreator;
const tbody = table.querySelector('tbody');
table.replaceChild(document.createElement('tbody'), tbody);
table.querySelector("tfoot td").onclick = (e) => this._addMoreRows();
this._addMoreRows();
}
_nextRowDataSlice() {
return this._rowData.splice(0, 100);
}
_addMoreRows() {
const fragment = new DocumentFragment();
for (let row of this._nextRowDataSlice()) {
const tr = this._rowElementCreator(row);
fragment.appendChild(tr);
}
this._table.querySelector('tbody').appendChild(fragment);
}
}
function delay(time) { function delay(time) {
return new Promise(resolver => setTimeout(resolver, time)); return new Promise(resolver => setTimeout(resolver, time));
} }
export { export {
defineCustomElement, V8CustomElement, removeAllChildren, defineCustomElement, V8CustomElement, removeAllChildren,
$, div, typeToColor, CSSColor, delay $, div, typeToColor, CSSColor, delay, LazyTable,
}; };
...@@ -41,7 +41,7 @@ found in the LICENSE file. --> ...@@ -41,7 +41,7 @@ found in the LICENSE file. -->
} }
.map.selected { .map.selected {
border-color: var(--map-background-color); border-color: var(--on-surface-color);
} }
.transitions { .transitions {
......
...@@ -131,7 +131,7 @@ defineCustomElement( ...@@ -131,7 +131,7 @@ defineCustomElement(
addTransitionTo(map) { addTransitionTo(map) {
// transition[ transitions[ transition[...], transition[...], ...]]; // transition[ transitions[ transition[...], transition[...], ...]];
this._displayedMapsInTree.add(map); this._displayedMapsInTree?.add(map);
let transition = this.div("transition"); let transition = this.div("transition");
if (map.isDeprecated()) transition.classList.add("deprecated"); if (map.isDeprecated()) transition.classList.add("deprecated");
if (map.edge) { if (map.edge) {
......
...@@ -14,42 +14,60 @@ found in the LICENSE file. --> ...@@ -14,42 +14,60 @@ found in the LICENSE file. -->
margin: auto; margin: auto;
} }
#stats table { table {
flex: 1; flex: 1;
padding-right: 50px;
max-height: 250px; max-height: 250px;
display: inline-block; display: inline-block;
overflow-y: scroll; overflow-y: scroll;
border-collapse: collapse;
}
table td {
padding: 2px;
} }
#stats table td { table thead td {
cursor: pointer; border-bottom: 1px var(--on-surface-color) dotted;
} }
#stats .transitionTable { table tbody td {
overflow-y: scroll; cursor: pointer;
} }
#stats .transitionTable tr { #nameTable tr {
max-width: 200px; max-width: 200px;
} }
#stats .transitionType { #nameTable tr td:nth-child(1) {
text-align: right; text-align: right;
max-width: 380px;
} }
#stats .transitionType tr td:nth-child(2) { #typeTable {
text-align: left; text-align: right;
max-width: 380px;
} }
#stats table thead td { #typeTable tr td:nth-child(2) {
border-bottom: 1px var(--on-surface-color) dotted; text-align: left;
} }
</style> </style>
<div class="panel"> <div class="panel">
<h2>Map Stats</h2> <h2>Map Stats</h2>
<section id="stats"> <section id="stats">
<table id="typeTable" class="statsTable">
<thead>
<tr><td></td><td>Type</td><td>Count</td><td>Percent</td></tr>
</thead>
<tbody></tbody>
</table>
<table id="nameTable">
<thead>
<tr><td>Count</td><td>Propery Name</td></tr>
</thead>
<tbody></tbody>
<tfoot>
<tr><td colspan="2" class="clickable">Show more...</td></tr>
</tfoo>
</table>
</section> </section>
</div> </div>
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import { V8CustomElement, defineCustomElement } from "./helper.mjs"; import { V8CustomElement, defineCustomElement } from "./helper.mjs";
import { SelectionEvent } from "./events.mjs"; import { SelectionEvent } from "./events.mjs";
import { delay, LazyTable } from "./helper.mjs";
defineCustomElement( defineCustomElement(
"stats-panel", "stats-panel",
...@@ -24,10 +25,6 @@ defineCustomElement( ...@@ -24,10 +25,6 @@ defineCustomElement(
this.selectedLogEntries = timeline.all this.selectedLogEntries = timeline.all
} }
get timeline() {
return this._timeline;
}
set selectedLogEntries(entries) { set selectedLogEntries(entries) {
this._selectedLogEntries = entries; this._selectedLogEntries = entries;
this.update(); this.update();
...@@ -37,10 +34,6 @@ defineCustomElement( ...@@ -37,10 +34,6 @@ defineCustomElement(
this._transitions = value; this._transitions = value;
} }
get transitions() {
return this._transitions;
}
filterUniqueTransitions(filter) { filterUniqueTransitions(filter) {
// Returns a list of Maps whose parent is not in the list. // Returns a list of Maps whose parent is not in the list.
return this._selectedLogEntries.filter((map) => { return this._selectedLogEntries.filter((map) => {
...@@ -51,8 +44,8 @@ defineCustomElement( ...@@ -51,8 +44,8 @@ defineCustomElement(
}); });
} }
update() { async update() {
this.removeAllChildren(this.stats); await delay(1);
this.updateGeneralStats(); this.updateGeneralStats();
this.updateNamedTransitionsStats(); this.updateNamedTransitionsStats();
} }
...@@ -60,7 +53,6 @@ defineCustomElement( ...@@ -60,7 +53,6 @@ defineCustomElement(
updateGeneralStats() { updateGeneralStats() {
console.assert(this._timeline !== undefined, "Timeline not set yet!"); console.assert(this._timeline !== undefined, "Timeline not set yet!");
let pairs = [ let pairs = [
["Total", null, (e) => true],
["Transitions", "primary", (e) => e.edge && e.edge.isTransition()], ["Transitions", "primary", (e) => e.edge && e.edge.isTransition()],
["Fast to Slow", "violet", (e) => e.edge && e.edge.isFastToSlow()], ["Fast to Slow", "violet", (e) => e.edge && e.edge.isFastToSlow()],
["Slow to Fast", "orange", (e) => e.edge && e.edge.isSlowToFast()], ["Slow to Fast", "orange", (e) => e.edge && e.edge.isSlowToFast()],
...@@ -82,14 +74,10 @@ defineCustomElement( ...@@ -82,14 +74,10 @@ defineCustomElement(
], ],
["Deprecated", null, (e) => e.isDeprecated()], ["Deprecated", null, (e) => e.isDeprecated()],
["Bootstrapped", "green", (e) => e.isBootstrapped()], ["Bootstrapped", "green", (e) => e.isBootstrapped()],
["Total", null, (e) => true],
]; ];
let text = ""; let tbody = document.createElement("tbody");
let tableNode = this.table("transitionType");
tableNode.innerHTML =
"<thead><tr><td>Color</td><td>Type</td><td>Count</td>" +
"<td>Percent</td></tr></thead>";
let name, filter;
let total = this._selectedLogEntries.length; let total = this._selectedLogEntries.length;
pairs.forEach(([name, color, filter]) => { pairs.forEach(([name, color, filter]) => {
let row = this.tr(); let row = this.tr();
...@@ -112,9 +100,9 @@ defineCustomElement( ...@@ -112,9 +100,9 @@ defineCustomElement(
row.appendChild(this.td(count)); row.appendChild(this.td(count));
let percent = Math.round((count / total) * 1000) / 10; let percent = Math.round((count / total) * 1000) / 10;
row.appendChild(this.td(percent.toFixed(1) + "%")); row.appendChild(this.td(percent.toFixed(1) + "%"));
tableNode.appendChild(row); tbody.appendChild(row);
}); });
this.stats.appendChild(tableNode); this.$("#typeTable").replaceChild(tbody, this.$("#typeTable tbody"));
} }
count(filter) { count(filter) {
...@@ -126,13 +114,9 @@ defineCustomElement( ...@@ -126,13 +114,9 @@ defineCustomElement(
} }
updateNamedTransitionsStats() { updateNamedTransitionsStats() {
let tableNode = this.table("transitionTable"); let rowData = Array.from(this._transitions.entries());
let nameMapPairs = Array.from(this.transitions.entries()); rowData.sort((a, b) => b[1].length - a[1].length);
tableNode.innerHTML = new LazyTable(this.$("#nameTable"), rowData, ([name, maps]) => {
"<thead><tr><td>Count</td><td>Propery Name</td></tr></thead>";
nameMapPairs
.sort((a, b) => b[1].length - a[1].length)
.forEach(([name, maps]) => {
let row = this.tr(); let row = this.tr();
row.maps = maps; row.maps = maps;
row.classList.add('clickable'); row.classList.add('clickable');
...@@ -145,9 +129,8 @@ defineCustomElement( ...@@ -145,9 +129,8 @@ defineCustomElement(
); );
row.appendChild(this.td(maps.length)); row.appendChild(this.td(maps.length));
row.appendChild(this.td(name)); row.appendChild(this.td(name));
tableNode.appendChild(row); return row;
}); });
this.stats.appendChild(tableNode);
} }
} }
); );
...@@ -116,11 +116,11 @@ found in the LICENSE file. --> ...@@ -116,11 +116,11 @@ found in the LICENSE file. -->
position: absolute; position: absolute;
} }
</style> </style>
<table id="legend"> <table id="legend" class="typeStatsTable">
<thead> <thead>
<tr> <tr>
<td></td> <td></td>
<td class="legendTypeColumn">Type</td> <td>Type</td>
<td>Count</td> <td>Count</td>
<td>Percent</td> <td>Percent</td>
</tr> </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