v8/tools/system-analyzer/ic-panel.mjs
Zeynep Cankara 832fac51ad [tools][system-analyzer] Convert modules to ES6
This CL identifies dependencies between modules
and convert existing javascript files to ES6
standard modules.

It cleans the unused code and remove duplicate
code throughout the app.

Bug: v8:10670

Change-Id: I787de8ca0d76c56aec5aeb3faa94a9e158a94c72
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2292237
Commit-Queue: Zeynep Cankara <zcankara@google.com>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Sathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68847}
2020-07-14 15:34:54 +00:00

233 lines
6.2 KiB
JavaScript

// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {Group} from './ic-model.mjs';
import CustomIcProcessor from "./ic-processor.mjs";
defineCustomElement('ic-panel', (templateText) =>
class ICPanel extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
this.groupKeySelect.addEventListener(
'change', e => this.updateTable(e));
this.$('#filterICTimeBtn').addEventListener(
'click', e => this.handleICTimeFilter(e));
this._noOfItems = 100;
this._startTime = 0;
this._endTime = 0;
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
set entries(value){
this._entries = value;
}
get entries(){
return this._entries;
}
get groupKeySelect() {
return this.$('#group-key');
}
get tableSelect() {
return this.$('#table');
}
get tableBodySelect() {
return this.$('#table-body');
}
get countSelect() {
return this.$('#count');
}
get spanSelectAll(){
return this.querySelectorAll("span");
}
set filteredEntries(value){
this._filteredEntries = value;
}
get filteredEntries(){
return this._filteredEntries;
}
set entries(value){
this._entries = value;
this.filteredEntries = value;
this.updateTable();
}
get entries(){
return this._entries;
}
filterEntriesByTime() {
this.filteredEntries = this.entries.filter(e => e.time >= this._startTime && e.time <= this._endTime);
}
updateTable(event) {
let select = this.groupKeySelect;
let key = select.options[select.selectedIndex].text;
let tableBody = this.tableBodySelect;
this.removeAllChildren(tableBody);
let groups = Group.groupBy(this.filteredEntries, key, true);
this.display(groups, tableBody);
//TODO(zcankara) do not send an event here, filtering will done outside
this.dispatchEvent(new CustomEvent(
'change', {bubbles: true, composed: true, detail: this.filteredEntries}));
}
escapeHtml(unsafe) {
if (!unsafe) return "";
return unsafe.toString()
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
processValue(unsafe) {
if (!unsafe) return "";
if (!unsafe.startsWith("http")) return this.escapeHtml(unsafe);
let a = document.createElement("a");
a.href = unsafe;
a.textContent = unsafe;
return a;
}
removeAllChildren(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
td(tr, content, className) {
let node = document.createElement("td");
if (typeof content == "object") {
node.appendChild(content);
} else {
node.innerHTML = content;
}
node.className = className;
tr.appendChild(node);
return node
}
set noOfItems(value){
this._noOfItems = value;
}
get noOfItems(){
return this._noOfItems;
}
display(entries, parent) {
let fragment = document.createDocumentFragment();
//let max = entries.length;
let max = Math.min(1000, entries.length)
for (let i = 0; i < max; i++) {
let entry = entries[i];
let tr = document.createElement("tr");
tr.entry = entry;
let details = this.td(tr,'<span>&#8505;</a>', 'details');
details.onclick = _ => this.toggleDetails(details);
this.td(tr, entry.percentage + "%", 'percentage');
this.td(tr, entry.count, 'count');
this.td(tr, this.processValue(entry.key), 'key');
fragment.appendChild(tr);
}
let omitted = entries.length - max;
if (omitted > 0) {
let tr = document.createElement("tr");
let tdNode = this.td(tr, 'Omitted ' + omitted + " entries.");
tdNode.colSpan = 4;
fragment.appendChild(tr);
}
parent.appendChild(fragment);
}
displayDrilldown(entry, previousSibling) {
let tr = document.createElement('tr');
tr.className = "entry-details";
tr.style.display = "none";
// indent by one td.
tr.appendChild(document.createElement("td"));
let td = document.createElement("td");
td.colSpan = 3;
for (let key in entry.groups) {
td.appendChild(this.displayDrilldownGroup(entry, key));
}
tr.appendChild(td);
// Append the new TR after previousSibling.
previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling)
}
displayDrilldownGroup(entry, key) {
let max = 20;
let group = entry.groups[key];
let div = document.createElement("div")
div.className = 'drilldown-group-title'
div.textContent = key + ' [top ' + max + ' out of ' + group.length + ']';
let table = document.createElement("table");
this.display(group.slice(0, max), table, false)
div.appendChild(table);
return div;
}
toggleDetails(node) {
let tr = node.parentNode;
let entry = tr.entry;
// Create subgroup in-place if the don't exist yet.
if (entry.groups === undefined) {
entry.createSubGroups();
this.displayDrilldown(entry, tr);
}
let details = tr.nextSibling;
let display = details.style.display;
if (display != "none") {
display = "none";
} else {
display = "table-row"
};
details.style.display = display;
}
initGroupKeySelect() {
let select = this.groupKeySelect;
select.options.length = 0;
for (let i in CustomIcProcessor.kProperties) {
let option = document.createElement("option");
option.text = CustomIcProcessor.kProperties[i];
select.add(option);
}
}
handleICTimeFilter(e) {
this._startTime = parseInt(this.$('#filter-time-start').value);
console.assert(this._startTime >= 0, { errorMsg: "start time must be a non-negative integer!" });
this._endTime = parseInt(this.$('#filter-time-end').value);
console.assert(this._endTime <= this.entries[this.entries.length - 1].time,
{ errorMsg: "end time must be smaller or equal to the the time of the last event!" });
console.assert(this._startTime < this._endTime,
{ errorMsg: "end time must be smaller than the start time!" });
this.filterEntriesByTime();
this.updateTable(e);
}
});