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