[tools] Improve system-analyzer

- Fix State timerange adjustment for multiple timelines
- Fix grid layout for detail panels
- Style panels consistently
- Simplify file-reader html

Bug: v8:10644
Change-Id: I277d88e2deb2bf71b0204034f6e63ea35f85a791
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2485812
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Sathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70653}
This commit is contained in:
Camillo Bruni 2020-10-19 18:48:36 +02:00 committed by Commit Bot
parent 403390ec60
commit 7413658cef
8 changed files with 149 additions and 142 deletions

View File

@ -13,6 +13,7 @@ class State {
_chunks;
_icTimeline;
_mapTimeline;
_deoptTimeline;
_minStartTime = Number.POSITIVE_INFINITY;
_maxEndTime = Number.NEGATIVE_INFINITY;
get minStartTime() {
@ -21,28 +22,42 @@ class State {
get maxEndTime() {
return this._maxEndTime;
}
selectTimeRange(start, end) {
this.timeSelection.start = start;
this.timeSelection.end = end;
this._icTimeline.selectTimeRange(start, end);
this._mapTimeline.selectTimeRange(start, end);
this._deoptTimeline.selectTimeRange(start, end);
}
_updateTimeRange(timeline) {
this._minStartTime = Math.min(this._minStartTime, timeline.startTime);
this._maxEndTime = Math.max(this._maxEndTime, timeline.endTime);
timeline.startTime = this._minStartTime;
timeline.endTime = this._maxEndTime;
}
get mapTimeline() {
return this._mapTimeline;
}
set mapTimeline(timeline) {
this._updateTimeRange(timeline);
timeline.startTime = this._minStartTime;
timeline.endTime = this._maxEndTime;
this._mapTimeline = timeline;
}
set icTimeline(timeline) {
this._updateTimeRange(timeline);
timeline.startTime = this._minStartTime;
timeline.endTime = this._maxEndTime;
this._icTimeline = timeline;
}
get icTimeline() {
return this._icTimeline;
}
set icTimeline(timeline) {
this._updateTimeRange(timeline);
this._icTimeline = timeline;
}
get deoptTimeline() {
return this._deoptTimeline;
}
set deoptTimeline(timeline) {
this._updateTimeRange(timeline);
this._deoptTimeline = timeline;
}
set chunks(value) {
//TODO(zcankara) split up between maps and ics, and every timeline track
this._chunks = value;

View File

@ -46,11 +46,14 @@ body {
font-family: "Roboto", sans-serif;
font-size: 14px;
color: var(--on-background-color);
margin-left: 2.5%;
margin-right: 2.5%;
margin: 10px 10px 0 10px;
background-color: var(--background-color);
}
section {
margin-bottom: 10px;
}
::-webkit-scrollbar, ::-webkit-scrollbar-track, ::-webkit-scrollbar-corner {
background-color: rgba(0, 0, 0, 0.0);
}
@ -58,7 +61,7 @@ body {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-thumb {
::-webkit-scrollbar-thumb {
background-color: rgba(128, 128, 128, 0.5);
border-radius: 8px;
cursor: pointer;
@ -104,11 +107,16 @@ dd {
}
.panel {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
background-color: var(--surface-color);
color: var(--on-surface-color);
padding: 10px 10px 10px 10px;
overflow-x: auto;
border-radius: 10px;
border: 3px solid rgba(128, 128, 128, 0.2);
}
.panel > h2 {
margin-top: 5px;
}
button {

View File

@ -58,19 +58,19 @@ found in the LICENSE file. -->
display: none;
}
#container.loaded {
display: grid;
align-content: center;
grid-template-columns: repeat(auto-fit, minmax(400px, 800px));
grid-template-rows: repeat(auto-fit, minmax(400px, 800px));
grid-auto-flow: dense;
grid-gap: 1em;
#timeline-panel {
width: 100%;
}
#container.loaded>#timeline-panel {
grid-column: span 2;
overflow: scroll;
.panels{
display: grid;
align-content: center;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
grid-auto-flow: row dense;
grid-gap: 10px;
margin-top: 10px;
}
dt::after {
content: ":";
}
@ -95,82 +95,86 @@ found in the LICENSE file. -->
<timeline-track id="ic-track"></timeline-track>
<timeline-track id="deopt-track"></timeline-track>
</timeline-panel>
<map-panel id="map-panel"></map-panel>
<ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel>
<source-panel id="source-panel"></source-panel>
</section>
<section id="settings">
<h2>Settings</h2>
<span>Theme:</span>
<div class="theme-switch-wrapper">
<label class="theme-switch" for="theme-switch-input">
<input type="checkbox" id="theme-switch-input" />
<div class="slider"></div>
</label>
<div class="panels">
<map-panel id="map-panel"></map-panel>
<ic-panel id="ic-panel" onchange="app.handleSelectIc(event)"></ic-panel>
<source-panel id="source-panel"></source-panel>
</div>
</section>
<section id="instructions">
<h2>Instructions</h2>
<p>
Unified web interface to analyse runtime information stored in the v8 log.
</p>
For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>:
<ul>
<li>
<code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE</code>
</li>
</ul>
For generating a v8.log file from Chrome:
<ul>
<li>
<code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox
--js-flags='--trace-ic --trace-maps --log-source-code
$WEBSITE_URL</code>
</li>
</ul>
<div class="panels">
<section id="settings" class="panel">
<h2>Settings</h2>
<span>Theme:</span>
<div class="theme-switch-wrapper">
<label class="theme-switch" for="theme-switch-input">
<input type="checkbox" id="theme-switch-input" />
<div class="slider"></div>
</label>
</div>
</section>
<h3>Log Options:</h3>
<dl class="d8-options">
<dt><code>--trace-maps</code></dt>
<dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank">
Maps</a></dd>
<dt><code>--trace-ic</code></dt>
<dd>Log
<a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
ICs</a></dd>
<dt><code>--log-source-code</code></dt>
<dd>Log source code</dd>
</dl>
<section id="instructions" class="panel">
<h2>Instructions</h2>
<p>
Unified web interface to analyse runtime information stored in the v8 log.
</p>
For generating a v8.log file from <a href="https://v8.dev/docs/build">d8</a>:
<ul>
<li>
<code>/path/do/d8 --trace-maps --trace_ic --log-source-code $FILE</code>
</li>
</ul>
For generating a v8.log file from Chrome:
<ul>
<li>
<code>/path/to/chrome --user-data-dir=/var/tmp/chr$RANDOM --no-sandbox
--js-flags='--trace-ic --trace-maps --log-source-code
$WEBSITE_URL</code>
</li>
</ul>
<h3>Keyboard Shortcuts for Navigation</h3>
<dl>
<dt><kbd>SHIFT</kbd> + <kbd>Arrow Up</kbd></dt>
<dd>Follow Map transition forward (first child)</dd>
<h3>Log Options:</h3>
<dl class="d8-options">
<dt><code>--trace-maps</code></dt>
<dd>Log<a href="https://v8.dev/blog/fast-properties" target="_blank">
Maps</a></dd>
<dt><code>--trace-ic</code></dt>
<dd>Log
<a href="https://mathiasbynens.be/notes/shapes-ics" target="_blank">
ICs</a></dd>
<dt><code>--log-source-code</code></dt>
<dd>Log source code</dd>
</dl>
<dt><kbd>SHIFT</kbd> + <kbd>Arrow Down</kbd></dt>
<dd>Follow Map transition backwards</dd>
<h3>Keyboard Shortcuts for Navigation</h3>
<dl>
<dt><kbd>SHIFT</kbd> + <kbd>Arrow Up</kbd></dt>
<dd>Follow Map transition forward (first child)</dd>
<dt><kbd>Arrow Up</kbd></dt>
<dd>Go to previous Map chunk</dd>
<dt><kbd>SHIFT</kbd> + <kbd>Arrow Down</kbd></dt>
<dd>Follow Map transition backwards</dd>
<dt><kbd>Arrow Down</kbd></dt>
<dd>Go to next Map in chunk</dd>
<dt><kbd>Arrow Up</kbd></dt>
<dd>Go to previous Map chunk</dd>
<dt><kbd>Arrow Left</kbd></dt>
<dd>Go to previous chunk</dd>
<dt><kbd>Arrow Down</kbd></dt>
<dd>Go to next Map in chunk</dd>
<dt><kbd>Arrow Right</kbd></dt>
<dd>Go to next chunk</dd>
<dt><kbd>Arrow Left</kbd></dt>
<dd>Go to previous chunk</dd>
<dt><kbd>+</kbd></dt>
<dd>Timeline zoom in</dd>
<dt><kbd>Arrow Right</kbd></dt>
<dd>Go to next chunk</dd>
<dt><kbd>-</kbd></dt>
<dd>Timeline zoom out</dd>
</dl>
</section>
<dt><kbd>+</kbd></dt>
<dd>Timeline zoom in</dd>
<dt><kbd>-</kbd></dt>
<dd>Timeline zoom out</dd>
</dl>
</section>
</div>
</body>
</html>

View File

@ -24,6 +24,7 @@ class App {
constructor(fileReaderId, mapPanelId, timelinePanelId,
icPanelId, mapTrackId, icTrackId, deoptTrackId, sourcePanelId) {
this._view = {
__proto__: null,
logFileReader: $(fileReaderId),
icPanel: $(icPanelId),
mapPanel: $(mapPanelId),
@ -40,10 +41,10 @@ class App {
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
this.toggleSwitch.addEventListener("change", (e) => this.switchTheme(e));
this._view.logFileReader.addEventListener("fileuploadstart", (e) =>
this.handleFileUpload(e)
this.handleFileUploadStart(e)
);
this._view.logFileReader.addEventListener("fileuploadend", (e) =>
this.handleDataUpload(e)
this.handleFileUploadEnd(e)
);
Object.entries(this._view).forEach(([_, panel]) => {
panel.addEventListener(SelectionEvent.name,
@ -67,15 +68,15 @@ class App {
}
showMapEntries(entries) {
this._state.selectedMapLogEntries = entries;
this._view.mapPanel.selectedMapLogEntries = this.#state.selectedMapLogEntries;
this._view.mapPanel.selectedMapLogEntries = entries;
}
showIcEntries(entries) {
this._state.selectedIcLogEntries = entries;
this._view.icPanel.selectedLogEntries = this.#state.selectedIcLogEntries;
this._view.icPanel.selectedLogEntries = entries;
}
showSourcePositionEntries(entries) {
//TODO(zcankara) Handle multiple source position selection events
this._view.sourcePanel.selectedSourcePositions = entries;
//TODO: Handle multiple source position selection events
this._view.sourcePanel.selectedSourcePositions = entries
}
handleTimeRangeSelect(e) {
@ -93,12 +94,9 @@ class App {
}
}
selectTimeRange(start, end) {
this._state.timeSelection.start = start;
this._state.timeSelection.end = end;
this._state.icTimeline.selectTimeRange(start, end);
this._state.mapTimeline.selectTimeRange(start, end);
this._view.mapPanel.selectedMapLogEntries =
this._state.mapTimeline.selection;
this._state.selectTimeRange(start, end);
this._view.mapPanel.selectedMapLogEntries =
this._state.mapTimeline.selection;
this._view.icPanel.selectedLogEntries = this._state.icTimeline.selection;
}
selectMapLogEntry(entry) {
@ -115,7 +113,7 @@ class App {
this._view.sourcePanel.selectedSourcePositions = [sourcePositions];
}
handleFileUpload(e) {
handleFileUploadStart(e) {
this.restartApp();
$("#container").className = "initial";
}
@ -125,32 +123,22 @@ class App {
this._navigation = new Navigation(this._state, this._view);
}
// Event log processing
handleLoadTextProcessor(text) {
let logProcessor = new Processor();
logProcessor.processString(text);
return logProcessor;
}
// call when a new file uploaded
handleDataUpload(e) {
handleFileUploadEnd(e) {
if (!e.detail) return;
$("#container").className = "loaded";
// instantiate the app logic
let fileData = e.detail;
const processor = this.handleLoadTextProcessor(fileData.chunk);
const processor = new Processor(fileData.chunk);
const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline;
// Load map log events timeline.
this._state.mapTimeline = mapTimeline;
this._state.icTimeline = icTimeline;
this._state.deoptTimeline = deoptTimeline;
// Transitions must be set before timeline for stats panel.
this._view.mapPanel.transitions = this._state.mapTimeline.transitions;
this._view.mapTrack.data = mapTimeline;
this._state.chunks = this._view.mapTrack.chunks;
this._view.mapPanel.timeline = mapTimeline;
// Load ic log events timeline.
this._state.icTimeline = icTimeline;
this._view.icPanel.timeline = icTimeline;
this._view.icTrack.data = icTimeline;
this._view.deoptTrack.data = deoptTimeline;
@ -161,6 +149,7 @@ class App {
refreshTimelineTrackView() {
this._view.mapTrack.data = this._state.mapTimeline;
this._view.icTrack.data = this._state.icTimeline;
this._view.deoptTrack.data = this._state.deoptTimeline;
}
switchTheme(event) {
@ -186,7 +175,7 @@ class Navigation {
this.state.map = value
}
get chunks() {
return this.state.chunks
return this.state.mapTimeline.chunks;
}
increaseTimelineResolution() {
this._view.timelinePanel.nofChunks *= 1.5;

View File

@ -7,14 +7,11 @@ found in the LICENSE file. -->
</head>
<style>
#fileReader {
width: 100%;
height: 100px;
line-height: 100px;
text-align: center;
border-radius: 5px;
cursor: pointer;
transition: all 0.5s ease-in-out;
border: 2px solid var(--primary-color);
background-color: var(--surface-color);
}
@ -74,15 +71,12 @@ found in the LICENSE file. -->
}
}
</style>
<section id="fileReaderSection">
<div id="fileReader" tabindex=1>
<span id="label">
Drag and drop a v8.log file into this area, or click to choose from disk.
</span>
<input id="file" type="file" name="file">
</div>
<div id="loader">
<div id="spinner"></div>
</div>
</section>
<div id="fileReader" class="panel" tabindex=1>
<span id="label">
Drag and drop a v8.log file into this area, or click to choose from disk.
</span>
<input id="file" type="file" name="file">
</div>
<div id="loader">
<div id="spinner"></div>
</div>

View File

@ -15,10 +15,6 @@ defineCustomElement('log-file-reader', (templateText) =>
e => this.handleKeyEvent(e));
}
get section() {
return this.$('#fileReaderSection');
}
updateLabel(text) {
this.$('#label').innerText = text;
}
@ -54,7 +50,7 @@ defineCustomElement('log-file-reader', (templateText) =>
return;
}
this.$('#fileReader').blur();
this.section.className = 'loading';
this.shadowRoot.className = 'loading';
const reader = new FileReader();
reader.onload = (e) => {
try {
@ -67,11 +63,11 @@ defineCustomElement('log-file-reader', (templateText) =>
bubbles: true, composed: true,
detail: dataModel
}));
this.section.className = 'success';
this.shadowRoot.className = 'success';
this.$('#fileReader').classList.add('done');
} catch (err) {
console.error(err);
this.section.className = 'failure';
this.shadowRoot.className = 'failure';
}
};
// Delay the loading a bit to allow for CSS animations to happen.

View File

@ -19,7 +19,7 @@ export class Processor extends LogReader {
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
MAJOR_VERSION = 7;
MINOR_VERSION = 6;
constructor() {
constructor(logString) {
super();
this.propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
@ -98,6 +98,7 @@ export class Processor extends LogReader {
processor: this.processPropertyIC.bind(this, 'StoreInArrayLiteralIC')
},
};
if (logString) this.processString(logString);
}
printError(str) {

View File

@ -12,7 +12,6 @@ found in the LICENSE file. -->
overflow-y: hidden;
overflow-x: scroll;
user-select: none;
background-color: var(--timeline-background-color);
}
#timelineLabel {
@ -66,15 +65,16 @@ found in the LICENSE file. -->
max-width: 280px;
padding-left: 20px;
padding-top: 10px;
border-collapse: collapse;
}
th,
td {
width: 200px;
text-align: left;
padding-bottom: 1px;
padding-bottom: 3px;
}
/* right align numbers */
#legend td:nth-of-type(4n+3),
#legend td:nth-of-type(4n+4) {
@ -88,7 +88,7 @@ found in the LICENSE file. -->
.timeline {
background-color: var(--timeline-background-color);
}
#timeline .rightHandle,
#timeline .leftHandle {
background-color: rgba(200, 200, 200, 0.5);
@ -106,7 +106,7 @@ found in the LICENSE file. -->
z-index: 2;
}
</style>
<div class="timeline">
<div>
<table id="legend">
<thead>
<tr>