add "timeline" system for measuring app start performance

This commit is contained in:
hippoz 2022-11-17 21:11:32 +02:00
parent be560e5510
commit 17e086769d
No known key found for this signature in database
GPG key ID: 7C52899193467641
8 changed files with 72 additions and 1 deletions

View file

@ -1,6 +1,7 @@
import gateway, { GatewayEventType } from "./gateway";
import { removeItem, setItem } from "./storage";
import { overlayStore, OverlayType } from "./stores";
import { timeline } from "./timeline";
export function useAuthHandlers() {
gateway.subscribe(GatewayEventType.Ready, () => {
@ -14,6 +15,7 @@ export function useAuthHandlers() {
}
export function authWithToken(token, shouldUpdate=false) {
timeline.addCheckpoint("Authentication started (authWithToken)");
if (shouldUpdate)
setItem("auth:token", token);
gateway.init(token);

View file

@ -1,9 +1,19 @@
<script>
import { afterUpdate, beforeUpdate } from "svelte";
import { showSidebar, selectedChannel, smallViewport, showChannelView, theme, showPresenceSidebar } from "../stores";
import { timeline } from "../timeline";
import ChannelView from "./ChannelView.svelte";
import OverlayProvider from "./overlays/OverlayProvider.svelte";
import PresenceSidebar from "./PresenceSidebar.svelte";
import Sidebar from "./Sidebar.svelte";
beforeUpdate(() => {
timeline.addCheckpoint("Main component update start");
});
afterUpdate(() => {
timeline.addCheckpoint("Main component update end");
});
</script>
<svelte:head>

View file

@ -2,6 +2,7 @@ import gateway from './gateway';
import { getItem, init, setItem, removeItem } from './storage';
import { allStores } from './stores';
import { authWithToken, logOut } from './auth';
import { timeline } from './timeline';
export function useDebuggingApi() {
window.__waffle = {
@ -16,6 +17,7 @@ export function useDebuggingApi() {
authWithToken,
logOut
},
timeline,
stores: allStores,
app: null
};

View file

@ -1,5 +1,6 @@
import logger from "./logging";
import { getItem } from "./storage";
import { timeline } from "./timeline";
export const GatewayErrors = {
BAD_PAYLOAD: 4001,
@ -58,6 +59,7 @@ export default {
handlers: new Map(),
disableReconnect: false,
init(token) {
timeline.addCheckpoint("Gateway connection start");
if (!token) {
log("no auth token, skipping connection");
this.dispatch(GatewayEventType.Close, GatewayErrors.BAD_AUTH);
@ -67,6 +69,7 @@ export default {
log(`connecting to gateway - gatewayBase: ${getItem("server:gatewayBase")}`);
this.ws = new WebSocket(getItem("server:gatewayBase"));
this.ws.onopen = () => {
timeline.addCheckpoint("Gateway connection open");
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
@ -80,6 +83,7 @@ export default {
switch (payload.t) {
case GatewayPayloadType.Hello: {
timeline.addCheckpoint("Gateway hello");
this.send({
t: GatewayPayloadType.Authenticate,
d: {
@ -98,6 +102,8 @@ export default {
break;
}
case GatewayPayloadType.Ready: {
timeline.addCheckpoint("Gateway ready");
this.user = payload.d.user;
this.channels = payload.d.channels;
@ -111,6 +117,7 @@ export default {
this.dispatch(payload.t, payload.d);
};
this.ws.onclose = ({ code }) => {
timeline.addCheckpoint("Gateway close");
this.authenticated = false;
this.user = null;
this.channels = null;

View file

@ -11,3 +11,11 @@ export default function logger(sink) {
}
};
}
export function tableLogger(sink) {
return (...args) => {
if (getItem(`log:${sink}`)) {
console.table(...args);
}
};
}

View file

@ -7,8 +7,13 @@ import gateway, { GatewayEventType } from './gateway';
import { pluginStore } from './stores';
import "@material-design-icons/font";
import { timeline } from './timeline';
timeline.start();
function handleGatewaySettlement() {
timeline.addCheckpoint("Got gateway settlement");
const loadingElement = document.getElementById("pre--loading-screen");
if (loadingElement) {
loadingElement.parentElement.removeChild(loadingElement);
@ -19,6 +24,8 @@ function handleGatewaySettlement() {
});
window.__waffle.app = app;
timeline.addCheckpoint("Created application");
pluginStore.consumePluginLoaders();
const scripts = getItem("app:javascript");
scripts.forEach((script) => {
@ -32,18 +39,24 @@ function handleGatewaySettlement() {
document.head.appendChild(style);
});
timeline.addCheckpoint("Loaded custom user content");
gateway.unsubscribe(GatewayEventType.Ready, handleGatewaySettlement);
gateway.unsubscribe(GatewayEventType.Close, handleGatewaySettlement);
timeline.addCheckpoint("All initialization finished");
timeline.dump();
}
function main() {
timeline.addCheckpoint("Main reached");
useDebuggingApi();
useAuthHandlers();
initResponsiveHandlers();
gateway.subscribe(GatewayEventType.Ready, handleGatewaySettlement);
gateway.subscribe(GatewayEventType.Close, handleGatewaySettlement);
authWithToken(getItem("auth:token"));
}

View file

@ -8,6 +8,7 @@ const defaults = {
"log:Gateway": false,
"log:Store": false,
"log:Messages": false,
"log:Timeline": false,
"ui:stateful:presistSelectedChannel": true,
"ui:showSidebarToggle": false,
"ui:alwaysUseMobileChatBar": false,

28
frontend/src/timeline.js Normal file
View file

@ -0,0 +1,28 @@
import { tableLogger } from "./logging";
export class Timeline {
constructor() {
this.startedAt = -1;
this.checkpoints = [];
this.logger = tableLogger("Timeline");
}
start() {
this.startedAt = performance.now();
this.checkpoints.push({
offset: 0,
label: "Timeline Started"
});
}
addCheckpoint(label) {
const offset = performance.now() - this.startedAt;
this.checkpoints.push({ offset, label });
}
dump() {
this.logger(this.checkpoints);
}
}
export const timeline = new Timeline();