Commit b1761b06 authored by Zeynep Cankara's avatar Zeynep Cankara Committed by Commit Bot

[tools][system-analyzer] Handle IC Panel time filtering and emit events

This CL redesigns the IC Panel to emit events
upon time range selection. IC entry time range specified
from the input fields and entries falling into the selected
time range bubbled up to the App controller. The IC panel
emits events upon selection of a map or a source file location.

Bug: v8:10644

Change-Id: I468dc52b7a6c62dbdee096e80cc6110ceb994f69
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2305893
Commit-Queue: Zeynep Cankara <zcankara@google.com>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69006}
parent 1a5cd112
......@@ -19,10 +19,6 @@ defineCustomElement('ic-panel', (templateText) =>
this._endTime = 0;
}
set entries(value){
this._entries = value;
}
get entries(){
return this._entries;
}
......@@ -49,36 +45,20 @@ defineCustomElement('ic-panel', (templateText) =>
set filteredEntries(value){
this._filteredEntries = value;
this.updateTable();
}
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) {
updateTable(event) {
let select = this.groupKey;
let key = select.options[select.selectedIndex].text;
let tableBody = this.tableBody;
this.removeAllChildren(tableBody);
let groups = Group.groupBy(this.filteredEntries, key, true);
this.render(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) {
......@@ -119,15 +99,33 @@ defineCustomElement('ic-panel', (templateText) =>
return this._noOfItems;
}
handleMapClick(e){
this.dispatchEvent(new CustomEvent(
'mapclick', {bubbles: true, composed: true,
detail: e.target.parentNode.entry}));
}
handleFilePositionClick(e){
this.dispatchEvent(new CustomEvent(
'filepositionclick', {bubbles: true, composed: true,
detail: e.target.parentNode.entry}));
}
render(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;
//TODO(zcankara) Create one bound method and use it everywhere
if (entry.property === "map") {
tr.addEventListener('click', e => this.handleMapClick(e));
} else if (entry.property == "filePosition") {
tr.addEventListener('click',
e => this.handleFilePositionClick(e));
}
let details = this.td(tr,'<span>&#8505;</a>', 'details');
//TODO(zcankara) don't keep the whole function context alive
details.onclick = _ => this.toggleDetails(details);
this.td(tr, entry.percentage + "%", 'percentage');
this.td(tr, entry.count, 'count');
......@@ -174,21 +172,21 @@ defineCustomElement('ic-panel', (templateText) =>
}
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.renderDrilldown(entry, tr);
}
let details = tr.nextSibling;
let display = details.style.display;
if (display != "none") {
display = "none";
} else {
display = "table-row"
};
details.style.display = display;
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.renderDrilldown(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() {
......@@ -202,16 +200,11 @@ defineCustomElement('ic-panel', (templateText) =>
}
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);
const startTime = parseInt(this.$('#filter-time-start').value);
const endTime = parseInt(this.$('#filter-time-end').value);
const dataModel = {startTime, endTime};
this.dispatchEvent(new CustomEvent(
'ictimefilter', {bubbles: true, composed: true, detail: dataModel}));
}
});
......@@ -17,11 +17,35 @@ class App {
this.icPanelId_ = icPanelId;
this.icPanel_ = this.$(icPanelId);
document.addEventListener('keydown', e => this.handleKeyDown(e));
this.icPanel_.addEventListener(
'ictimefilter', e => this.handleICTimeFilter(e));
this.icPanel_.addEventListener(
'mapclick', e => this.handleMapClick(e));
this.icPanel_.addEventListener(
'filepositionclick', e => this.handleFilePositionClick(e));
this.entries = undefined;
}
handleMapClick(e) {
//TODO(zcankara) Direct the event based on the key and value
console.log("map: ", e.detail.key);
}
handleFilePositionClick(e) {
//TODO(zcankara) Direct the event based on the key and value
console.log("filePosition: ", e.detail.key);
}
handleICTimeFilter(event) {
let filteredEntries = this.entries.filter(
e => e.time >= event.detail.startTime && e.time <= event.detail.endTime);
console.log("filtered entries: ", filteredEntries);
this.icPanel_.filteredEntries = filteredEntries;
}
$(id) { return document.querySelector(id); }
handleKeyDown(event) {
handleKeyDown(event) {
let nav = document.state.navigation;
switch(event.key) {
case "ArrowUp":
......@@ -68,7 +92,8 @@ class App {
let icProcessor = new CustomIcProcessor();
icProcessor.processString(fileData.chunk);
let entries = icProcessor.entries;
this.icPanel_.entries = entries;
this.entries = entries;
this.icPanel_.filteredEntries = entries;
this.icPanel_.count.innerHTML = entries.length;
}
reader.readAsText(fileData.file);
......
......@@ -27,6 +27,13 @@ class State {
get filteredEntries() {
return this._filteredEntries;
}
set entries(value) {
this._entries = value;
}
get entries() {
return this._entries;
}
get timeline() {
return this._timeline
}
......
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