Commit c2e10ac6 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[tools] System-analyzer list panel improvements

- Show selection tab-bar
- Hide panels on empty timeline
- Fix legend position in ic list-panel

Bug: v8:10644
Change-Id: I4ef09627ed4de8682adb60f88be38867bc91640d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2584953Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71731}
parent 0ecf5b06
......@@ -18,7 +18,8 @@
--blue: #6e77dc;
--orange: #dc9b6e;
--violet: #d26edc;
--border-color: 128, 128, 128;
--border-color-rgb: 128, 128, 128;
--border-color: rgba(var(--border-color-rgb), 0.2);
}
[data-theme="light"] {
......@@ -112,11 +113,12 @@ dd {
color: var(--on-surface-color);
padding: 10px;
border-radius: 10px;
border: 3px solid rgba(var(--border-color), 0.2);
border: 3px solid var(--border-color);
overflow: hidden;
}
.panelBody {
position: relative;
max-height: 800px;
overflow-y: scroll;
margin: 0 -10px -10px 0;
......@@ -125,7 +127,7 @@ dd {
.panel > h2, .panelTitle {
margin: -10px -10px 0 -10px;
padding: 5px 10px 5px 10px;
background-color: rgba(var(--border-color),0.2);
background-color: var(--border-color);
border-radius: 7px 7px 0 0;
font-weight: 400;
}
......@@ -144,14 +146,14 @@ select,
button {
background-color: var(--surface-color);
color: var(--on-surface-color);
border: 2px solid rgba(var(--border-color), 0.4);
border: 2px solid rgba(var(--border-color-rgb), 0.4);
border-radius: 5px;
padding: 2px;
}
input:hover,
select:hover,
button:hover {
border: 2px solid rgba(var(--border-color), 0.6);
border: 2px solid rgba(var(--border-color-rgb), 0.6);
}
.colorbox {
......@@ -214,19 +216,18 @@ button:hover {
}
#legend {
.legend {
position: absolute;
right: 10px;
top: 10px;
right: 0px;
top: 0px;
background-color: var(--surface-color);
border-radius: 5px;
border: 3px solid rgba(var(--border-color), 0.2);
border: 3px solid var(--border-color);
padding: 0 10px 0 10px;
}
#legend dt {
.legend dt {
font-family: monospace;
}
#legend h3 {
.legend h3 {
margin-top: 10px;
}
\ No newline at end of file
......@@ -108,7 +108,7 @@ found in the LICENSE file. -->
<div class="panels">
<map-panel id="map-panel"></map-panel>
<list-panel id="ic-list" title="IC List">
<div id="legend">
<div class="legend">
<h3>Legend</h3>
<dl>
<dt>0</dt>
......
......@@ -66,7 +66,7 @@ class App {
document.addEventListener(
SelectionEvent.name, e => this.handleShowEntries(e));
document.addEventListener(
FocusEvent.name, e => this.handleShowEntryDetail(e));
FocusEvent.name, e => this.handleFocusLogEntryl(e));
document.addEventListener(
SelectTimeEvent.name, e => this.handleTimeRangeSelect(e));
document.addEventListener(ToolTipEvent.name, e => this.handleToolTip(e));
......@@ -101,27 +101,6 @@ class App {
}
}
handleShowEntryDetail(e) {
e.stopPropagation();
const entry = e.entry;
switch (entry.constructor) {
case SourcePosition:
return this.selectSourcePosition(entry);
case MapLogEntry:
return this.selectMapLogEntry(entry);
case IcLogEntry:
return this.selectIcLogEntry(entry);
case ApiLogEntry:
return this.selectApiLogEntry(entry);
case CodeLogEntry:
return this.selectCodeLogEntry(entry);
case DeoptLogEntry:
return this.selectDeoptLogEntry(entry);
default:
throw new Error('Unknown selection type!');
}
}
showMapEntries(entries) {
this._state.selectedMapLogEntries = entries;
this._view.mapPanel.selectedLogEntries = entries;
......@@ -168,37 +147,57 @@ class App {
this._view.timelinePanel.timeSelection = {start, end};
}
selectMapLogEntry(entry) {
handleFocusLogEntryl(e) {
e.stopPropagation();
this.focusLogEntry(e.entry);
}
focusLogEntry(entry) {
switch (entry.constructor) {
case SourcePosition:
return this.focusSourcePosition(entry);
case MapLogEntry:
return this.focusMapLogEntry(entry);
case IcLogEntry:
return this.focusIcLogEntry(entry);
case ApiLogEntry:
return this.focusApiLogEntry(entry);
case CodeLogEntry:
return this.focusCodeLogEntry(entry);
case DeoptLogEntry:
return this.focusDeoptLogEntry(entry);
default:
throw new Error('Unknown selection type!');
}
}
focusMapLogEntry(entry) {
this._state.map = entry;
this._view.mapTrack.selectedEntry = entry;
this._view.mapTrack.focusedEntry = entry;
this._view.mapPanel.map = entry;
this._view.mapList.selectedLogEntry = entry;
}
selectIcLogEntry(entry) {
focusIcLogEntry(entry) {
this._state.ic = entry;
this._view.icList.selectedLogEntry = entry;
}
selectCodeLogEntry(entry) {
focusCodeLogEntry(entry) {
this._state.code = entry;
this._view.codePanel.entry = entry;
this._view.codeList.selectedLogEntry = entry;
}
selectDeoptLogEntry(entry) {
this._view.deoptList.selectedLogEntry = entry;
focusDeoptLogEntry(entry) {
this._view.deoptList.focusedLogEntry = entry;
}
selectApiLogEntry(entry) {
focusApiLogEntry(entry) {
this._state.apiLogEntry = entry;
this._view.apiTrack.selectedEntry = entry;
this._view.apiList.selectedLogEntry = entry;
this._view.apiTrack.focusedEntry = entry;
}
selectSourcePosition(sourcePositions) {
focusSourcePosition(sourcePositions) {
if (!sourcePositions.script) return;
this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
this._view.sourcePanel.focusedSourcePositions = [sourcePositions];
}
handleToolTip(event) {
......
......@@ -7,67 +7,68 @@ import {MapLogEntry} from '../log/map.mjs';
import {FocusEvent, SelectionEvent, ToolTipEvent} from './events.mjs';
import {delay, DOM, formatBytes, formatMicroSeconds, V8CustomElement} from './helper.mjs';
DOM.defineCustomElement(
'view/code-panel',
(templateText) => class CodePanel extends V8CustomElement {
_timeline;
_selectedEntries;
_entry;
DOM.defineCustomElement('view/code-panel',
(templateText) =>
class CodePanel extends V8CustomElement {
_timeline;
_selectedEntries;
_entry;
constructor() {
super(templateText);
this._codeSelectNode.onchange = this._handleSelectCode.bind(this);
}
constructor() {
super(templateText);
this._codeSelectNode.onchange = this._handleSelectCode.bind(this);
}
set timeline(timeline) {
this._timeline = timeline;
this.update();
}
set timeline(timeline) {
this._timeline = timeline;
this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
this.update();
}
set selectedEntries(entries) {
this._selectedEntries = entries;
// TODO: add code selection dropdown
this._updateSelect();
this.entry = entries.first();
}
set selectedEntries(entries) {
this._selectedEntries = entries;
// TODO: add code selection dropdown
this._updateSelect();
this.entry = entries.first();
}
set entry(entry) {
this._entry = entry;
this.update();
}
set entry(entry) {
this._entry = entry;
this.update();
}
get _disassemblyNode() {
return this.$('#disassembly');
}
get _disassemblyNode() {
return this.$('#disassembly');
}
get _sourceNode() {
return this.$('#sourceCode');
}
get _sourceNode() {
return this.$('#sourceCode');
}
get _codeSelectNode() {
return this.$('#codeSelect');
}
get _codeSelectNode() {
return this.$('#codeSelect');
}
_update() {
this._disassemblyNode.innerText = this._entry?.disassemble ?? '';
this._sourceNode.innerText = this._entry?.source ?? '';
}
_update() {
this._disassemblyNode.innerText = this._entry?.disassemble ?? '';
this._sourceNode.innerText = this._entry?.source ?? '';
}
_updateSelect() {
const select = this._codeSelectNode;
select.options.length = 0;
const sorted =
this._selectedEntries.slice().sort((a, b) => a.time - b.time);
for (const code of this._selectedEntries) {
const option = DOM.element('option');
option.text =
`${code.name}(...) t=${formatMicroSeconds(code.time)} size=${
formatBytes(code.size)} script=${code.script?.toString()}`;
option.data = code;
select.add(option);
}
}
_handleSelectCode() {
this.entry = this._codeSelectNode.selectedOptions[0].data;
}
});
\ No newline at end of file
_updateSelect() {
const select = this._codeSelectNode;
select.options.length = 0;
const sorted =
this._selectedEntries.slice().sort((a, b) => a.time - b.time);
for (const code of this._selectedEntries) {
const option = DOM.element('option');
option.text =
`${code.name}(...) t=${formatMicroSeconds(code.time)} size=${
formatBytes(code.size)} script=${code.script?.toString()}`;
option.data = code;
select.add(option);
}
}
_handleSelectCode() {
this.entry = this._codeSelectNode.selectedOptions[0].data;
}
});
\ No newline at end of file
......@@ -50,12 +50,51 @@ found in the LICENSE file. -->
max-height: 800px;
overflow-y: scroll;
}
.selection {
display: flex;
margin: 0 -10px 0 -10px;
}
.selection input {
display: none;
}
.selection label {
flex: 1;
padding: 5px;
cursor: pointer;
background-color: var( --surface-color);
font-weight: normal;
text-align: center;
}
.selection label ~ label {
border-left: 2px var(--border-color) solid;
}
.selection label:hover {
background-color: var(--primary-color);
}
.selection [type=radio]:checked + label {
background-color: var(--border-color);
}
.legend {
top: 40px;
}
</style>
<div class="panel">
<h2 id="title"></h2>
<slot></slot>
<div class="selection">
<input type="radio" id="show-all" name="selectionType" value="all">
<label for="show-all">All</label>
<input type="radio" id="show-timerange" name="selectionType" value="timerange">
<label for="show-timerange">Time Range</label>
<input type="radio" id="show-selection" name="selectionType" value="selection">
<label for="show-selection">Last Selection</label>
</div>
<select id="group-key"></select>
<div id="content" class="panelBody">
<slot></slot>
<table id="table" width="100%">
</table>
</div>
......
......@@ -14,7 +14,7 @@ DOM.defineCustomElement('view/list-panel',
(templateText) =>
class ListPanel extends V8CustomElement {
_selectedLogEntries;
_selectedLogEntry;
_displayedLogEntries;
_timeline;
_detailsClickHandler = this._handleDetailsClick.bind(this);
......@@ -24,6 +24,9 @@ DOM.defineCustomElement('view/list-panel',
constructor() {
super(templateText);
this.groupKey.addEventListener('change', e => this.update());
this.showAllRadio.onclick = _ => this._show(this._timeline);
this.showTimerangeRadio.onclick = _ => this._show(this._timeline.selection);
this.showSelectionRadio.onclick = _ => this._show(this._selectedLogEntries);
}
static get observedAttributes() {
......@@ -36,20 +39,22 @@ DOM.defineCustomElement('view/list-panel',
}
}
set timeline(value) {
console.assert(value !== undefined, 'timeline undefined!');
this._timeline = value;
this.selectedLogEntries = this._timeline.all;
this.initGroupKeySelect();
set timeline(timeline) {
console.assert(timeline !== undefined, 'timeline undefined!');
this._timeline = timeline;
this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
this._initGroupKeySelect();
}
set selectedLogEntries(entries) {
this._selectedLogEntries = entries;
this.update();
}
set selectedLogEntry(entry) {
// TODO: show details
if (entries === this._timeline.selection) {
this.showTimerangeRadio.click();
} else if (entries == this._timeline) {
this.showAllRadio.click();
} else {
this._selectedLogEntries = entries;
this.showSelectionRadio.click();
}
}
get entryClass() {
......@@ -64,19 +69,42 @@ DOM.defineCustomElement('view/list-panel',
return this.$('#table');
}
get spanSelectAll() {
return this.querySelectorAll('span');
get showAllRadio() {
return this.$('#show-all');
}
get showTimerangeRadio() {
return this.$('#show-timerange');
}
get showSelectionRadio() {
return this.$('#show-selection');
}
get _propertyNames() {
return this.entryClass?.propertyNames ?? [];
}
_initGroupKeySelect() {
const select = this.groupKey;
select.options.length = 0;
for (const propertyName of this._propertyNames) {
const option = DOM.element('option');
option.text = propertyName;
select.add(option);
}
}
_show(entries) {
this._displayedLogEntries = entries;
this.update();
}
_update() {
if (this._timeline.isEmpty()) return;
DOM.removeAllChildren(this.table);
if (this._displayedLogEntries.length == 0) return;
const propertyName = this.groupKey.selectedOptions[0].text;
const groups =
groupBy(this._selectedLogEntries, each => each[propertyName], true);
groupBy(this._displayedLogEntries, each => each[propertyName], true);
this._render(groups, this.table);
}
......@@ -168,14 +196,4 @@ DOM.defineCustomElement('view/list-panel',
return tr;
}, 10);
}
initGroupKeySelect() {
const select = this.groupKey;
select.options.length = 0;
for (const propertyName of this._propertyNames) {
const option = DOM.element('option');
option.text = propertyName;
select.add(option);
}
}
});
......@@ -43,6 +43,7 @@ DOM.defineCustomElement('view/map-panel',
set timeline(timeline) {
this._timeline = timeline;
this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
this.mapTransitionsPanel.timeline = timeline;
}
......
......@@ -76,7 +76,7 @@ found in the LICENSE file. -->
font-weight: 400;
}
.legend {
.timelineLegend {
position: relative;
float: right;
height: calc(200px + 12px);
......@@ -143,7 +143,7 @@ found in the LICENSE file. -->
</style>
<h3 id="title"></h3>
<div class="legend">
<div class="timelineLegend">
<table id="legendTable">
<thead>
<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