[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:
parent
403390ec60
commit
7413658cef
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user