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 {
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) {
return new Promise(resolver => setTimeout(resolver, time));
}
export {
defineCustomElement, V8CustomElement, removeAllChildren,
$, div, typeToColor, CSSColor, delay
$, div, typeToColor, CSSColor, delay, LazyTable,
};
......@@ -41,7 +41,7 @@ found in the LICENSE file. -->
}
.map.selected {
border-color: var(--map-background-color);
border-color: var(--on-surface-color);
}
.transitions {
......
......@@ -131,7 +131,7 @@ defineCustomElement(
addTransitionTo(map) {
// transition[ transitions[ transition[...], transition[...], ...]];
this._displayedMapsInTree.add(map);
this._displayedMapsInTree?.add(map);
let transition = this.div("transition");
if (map.isDeprecated()) transition.classList.add("deprecated");
if (map.edge) {
......
......@@ -14,42 +14,60 @@ found in the LICENSE file. -->
margin: auto;
}
#stats table {
table {
flex: 1;
padding-right: 50px;
max-height: 250px;
display: inline-block;
overflow-y: scroll;
border-collapse: collapse;
}
table td {
padding: 2px;
}
#stats table td {
cursor: pointer;
table thead td {
border-bottom: 1px var(--on-surface-color) dotted;
}
#stats .transitionTable {
overflow-y: scroll;
table tbody td {
cursor: pointer;
}
#stats .transitionTable tr {
#nameTable tr {
max-width: 200px;
}
#stats .transitionType {
#nameTable tr td:nth-child(1) {
text-align: right;
max-width: 380px;
}
#stats .transitionType tr td:nth-child(2) {
text-align: left;
#typeTable {
text-align: right;
max-width: 380px;
}
#stats table thead td {
border-bottom: 1px var(--on-surface-color) dotted;
#typeTable tr td:nth-child(2) {
text-align: left;
}
</style>
<div class="panel">
<h2>Map Stats</h2>
<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>
</div>
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import { V8CustomElement, defineCustomElement } from "./helper.mjs";
import { SelectionEvent } from "./events.mjs";
import { delay, LazyTable } from "./helper.mjs";
defineCustomElement(
"stats-panel",
......@@ -24,10 +25,6 @@ defineCustomElement(
this.selectedLogEntries = timeline.all
}
get timeline() {
return this._timeline;
}
set selectedLogEntries(entries) {
this._selectedLogEntries = entries;
this.update();
......@@ -37,10 +34,6 @@ defineCustomElement(
this._transitions = value;
}
get transitions() {
return this._transitions;
}
filterUniqueTransitions(filter) {
// Returns a list of Maps whose parent is not in the list.
return this._selectedLogEntries.filter((map) => {
......@@ -51,8 +44,8 @@ defineCustomElement(
});
}
update() {
this.removeAllChildren(this.stats);
async update() {
await delay(1);
this.updateGeneralStats();
this.updateNamedTransitionsStats();
}
......@@ -60,7 +53,6 @@ defineCustomElement(
updateGeneralStats() {
console.assert(this._timeline !== undefined, "Timeline not set yet!");
let pairs = [
["Total", null, (e) => true],
["Transitions", "primary", (e) => e.edge && e.edge.isTransition()],
["Fast to Slow", "violet", (e) => e.edge && e.edge.isFastToSlow()],
["Slow to Fast", "orange", (e) => e.edge && e.edge.isSlowToFast()],
......@@ -82,14 +74,10 @@ defineCustomElement(
],
["Deprecated", null, (e) => e.isDeprecated()],
["Bootstrapped", "green", (e) => e.isBootstrapped()],
["Total", null, (e) => true],
];
let text = "";
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 tbody = document.createElement("tbody");
let total = this._selectedLogEntries.length;
pairs.forEach(([name, color, filter]) => {
let row = this.tr();
......@@ -112,9 +100,9 @@ defineCustomElement(
row.appendChild(this.td(count));
let percent = Math.round((count / total) * 1000) / 10;
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) {
......@@ -126,13 +114,9 @@ defineCustomElement(
}
updateNamedTransitionsStats() {
let tableNode = this.table("transitionTable");
let nameMapPairs = Array.from(this.transitions.entries());
tableNode.innerHTML =
"<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 rowData = Array.from(this._transitions.entries());
rowData.sort((a, b) => b[1].length - a[1].length);
new LazyTable(this.$("#nameTable"), rowData, ([name, maps]) => {
let row = this.tr();
row.maps = maps;
row.classList.add('clickable');
......@@ -145,9 +129,8 @@ defineCustomElement(
);
row.appendChild(this.td(maps.length));
row.appendChild(this.td(name));
tableNode.appendChild(row);
return row;
});
this.stats.appendChild(tableNode);
}
}
);
......@@ -116,11 +116,11 @@ found in the LICENSE file. -->
position: absolute;
}
</style>
<table id="legend">
<table id="legend" class="typeStatsTable">
<thead>
<tr>
<td></td>
<td class="legendTypeColumn">Type</td>
<td>Type</td>
<td>Count</td>
<td>Percent</td>
</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