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

[tools] Improve system-analyzer startup and loader

- Display spinner properly again
- Defer loadding additional App and subsequent modules
- Preload file reader module and template

Change-Id: Ifc81a93864d61c282db90df25f93dc0eefef4373
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2494925
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70730}
parent 80ec52ea
......@@ -43,7 +43,7 @@
}
body {
font-family: "Roboto", sans-serif;
font-family: sans-serif;
font-size: 14px;
color: var(--on-background-color);
margin: 10px 10px 0 10px;
......
......@@ -2,14 +2,27 @@
<!-- Copyright 2020 the V8 project authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Indicium</title>
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
<!-- <link rel="icon" type="image/png" href="/images/favicon.png"/> -->
<link rel="modulepreload" href="./log-file-reader.mjs" >
<link rel="modulepreload" href="./helper.mjs" >
<link rel="preload" href="./log-file-reader-template.html" as="fetch" crossorigin="anonymous">
<script type="module">
// Force instatiating the log-reader before anything else.
import "./log-file-reader.mjs";
// Delay loading of the main App
(async function() {
let module = await import('./index.mjs');
globalThis.app = new module.App("#log-file-reader", "#map-panel", "#map-stats-panel",
"#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track",
"#source-panel");
})();
</script>
<link rel="stylesheet" type="text/css" href="./index.css">
<style>
.theme-switch-wrapper {
......@@ -75,13 +88,6 @@ found in the LICENSE file. -->
content: ":";
}
</style>
<script type="module">
import { App } from './index.mjs';
globalThis.app = new App("#log-file-reader", "#map-panel", "#map-stats-panel",
"#timeline-panel", "#ic-panel", "#map-track", "#ic-track", "#deopt-track",
"#source-panel");
</script>
</head>
<body>
......@@ -177,5 +183,4 @@ found in the LICENSE file. -->
</section>
</div>
</body>
</html>
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { SelectionEvent, FocusEvent, SelectTimeEvent } from "./events.mjs";
import { State } from "./app-model.mjs";
import { MapLogEntry } from "./log/map.mjs";
......@@ -10,18 +9,13 @@ import { IcLogEntry } from "./log/ic.mjs";
import { Processor } from "./processor.mjs";
import { SourcePosition } from "../profile.mjs";
import { $ } from "./helper.mjs";
import "./ic-panel.mjs";
import "./timeline-panel.mjs";
import "./stats-panel.mjs";
import "./map-panel.mjs";
import "./log-file-reader.mjs";
import "./source-panel.mjs";
class App {
_state;
_view;
_navigation;
_startupPromise;
constructor(fileReaderId, mapPanelId, mapStatsPanelId, timelinePanelId,
icPanelId, mapTrackId, icTrackId, deoptTrackId, sourcePanelId) {
this._view = {
......@@ -36,10 +30,6 @@ class App {
deoptTrack: $(deoptTrackId),
sourcePanel: $(sourcePanelId)
};
this._state = new State();
this._navigation = new Navigation(this._state, this._view);
document.addEventListener('keydown',
e => this._navigation.handleKeyDown(e));
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
this.toggleSwitch.addEventListener("change", (e) => this.switchTheme(e));
this._view.logFileReader.addEventListener("fileuploadstart", (e) =>
......@@ -48,6 +38,19 @@ class App {
this._view.logFileReader.addEventListener("fileuploadend", (e) =>
this.handleFileUploadEnd(e)
);
this._startupPromise = this.runAsyncInitialize();
}
async runAsyncInitialize() {
await Promise.all([
import("./ic-panel.mjs"),
import("./timeline-panel.mjs"),
import("./stats-panel.mjs"),
import("./map-panel.mjs"),
import("./source-panel.mjs"),
]);
document.addEventListener('keydown',
e => this._navigation?.handleKeyDown(e));
Object.entries(this._view).forEach(([_, panel]) => {
panel.addEventListener(SelectionEvent.name,
e => this.handleShowEntries(e));
......@@ -57,6 +60,7 @@ class App {
e => this.handleTimeRangeSelect(e));
});
}
handleShowEntries(e) {
if (e.entries[0] instanceof MapLogEntry) {
this.showMapEntries(e.entries);
......@@ -134,27 +138,29 @@ class App {
this._navigation = new Navigation(this._state, this._view);
}
handleFileUploadEnd(e) {
if (!e.detail) return;
async handleFileUploadEnd(e) {
await this._startupPromise;
try {
const processor = new Processor(e.detail);
const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline;
this._state.mapTimeline = mapTimeline;
this._state.icTimeline = icTimeline;
this._state.deoptTimeline = deoptTimeline;
// Transitions must be set before timeline for stats panel.
this._view.mapPanel.timeline = mapTimeline;
this._view.mapTrack.data = mapTimeline;
this._view.mapStatsPanel.transitions = this._state.mapTimeline.transitions;
this._view.mapStatsPanel.timeline = mapTimeline;
this._view.icPanel.timeline = icTimeline;
this._view.icTrack.data = icTimeline;
this._view.deoptTrack.data = deoptTimeline;
this._view.sourcePanel.data = processor.scripts
} catch(e) {
this._view.logFileReader.error = "Log file contains errors!"
}
$("#container").className = "loaded";
// instantiate the app logic
let fileData = e.detail;
const processor = new Processor(fileData.chunk);
const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline;
const deoptTimeline = processor.deoptTimeline;
this._state.mapTimeline = mapTimeline;
this._state.icTimeline = icTimeline;
this._state.deoptTimeline = deoptTimeline;
// Transitions must be set before timeline for stats panel.
this._view.mapPanel.timeline = mapTimeline;
this._view.mapTrack.data = mapTimeline;
this._view.mapStatsPanel.transitions = this._state.mapTimeline.transitions;
this._view.mapStatsPanel.timeline = mapTimeline;
this._view.icPanel.timeline = icTimeline;
this._view.icTrack.data = icTimeline;
this._view.deoptTrack.data = deoptTimeline;
this._view.sourcePanel.data = processor.scripts
this.fileLoaded = true;
}
......
......@@ -14,16 +14,19 @@ found in the LICENSE file. -->
transition: all 0.5s ease-in-out;
background-color: var(--surface-color);
}
#fileReader:hover {
background-color: var(--primary-color);
color: var(--on-primary-color);
}
#fileReader.done {
.done #fileReader{
height: 20px;
line-height: 20px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
#fileReader:hover {
background-color: var(--primary-color);
color: var(--on-primary-color);
.fail #fileReader {
background-color: var(--error-color);
}
.loading #fileReader {
......@@ -47,7 +50,6 @@ found in the LICENSE file. -->
height: 100%;
background-color: var(--file-reader-background-color);
}
#spinner {
position: absolute;
width: 100px;
......@@ -71,12 +73,14 @@ found in the LICENSE file. -->
}
}
</style>
<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 id="root">
<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>
</div>
......@@ -15,6 +15,11 @@ defineCustomElement('log-file-reader', (templateText) =>
e => this.handleKeyEvent(e));
}
set error(message) {
this.updateLabel(message);
this.root.className = 'fail';
}
updateLabel(text) {
this.$('#label').innerText = text;
}
......@@ -41,36 +46,37 @@ defineCustomElement('log-file-reader', (templateText) =>
}
connectedCallback() {
this.$('#fileReader').focus();
this.fileReader.focus();
}
get fileReader() {
return this.$('#fileReader');
}
get root() { return this.$("#root"); }
readFile(file) {
if (!file) {
this.updateLabel('Failed to load file.');
this.error = 'Failed to load file.';
return;
}
this.$('#fileReader').blur();
this.shadowRoot.className = 'loading';
this.fileReader.blur();
this.root.className = 'loading';
const reader = new FileReader();
reader.onload = (e) => {
try {
let dataModel = Object.create(null);
dataModel.file = file;
dataModel.chunk = e.target.result;
this.updateLabel('Finished loading \'' + file.name + '\'.');
this.dispatchEvent(new CustomEvent(
'fileuploadend', {
bubbles: true, composed: true,
detail: dataModel
}));
this.shadowRoot.className = 'success';
this.$('#fileReader').classList.add('done');
} catch (err) {
console.error(err);
this.shadowRoot.className = 'failure';
}
};
reader.onload = (e) => this.handleFileLoad(e, file);
// Delay the loading a bit to allow for CSS animations to happen.
setTimeout(() => reader.readAsText(file), 0);
}
handleFileLoad(e, file) {
const chunk = e.target.result;
this.updateLabel('Finished loading \'' + file.name + '\'.');
this.dispatchEvent(new CustomEvent(
'fileuploadend', {
bubbles: true,
composed: true,
detail: chunk,
}));
this.root.className = 'done';
}
});
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