feat: implement performance view
All checks were successful
Deploy to GitHub Pages / build_site (push) Successful in 2m10s

This commit is contained in:
2024-04-25 03:37:52 +02:00
parent c28ef550a9
commit e0e1743b77
12 changed files with 421 additions and 179 deletions

View File

@@ -0,0 +1,68 @@
<script lang="ts">
export let points: number[];
$: max = Math.max(...points);
$: min = Math.min(...points);
function constructPath() {
return points
.map((point, i) => {
const x = (i / (points.length - 1)) * 100;
const y = 100 - ((point - min) / (max - min)) * 100;
return `${x},${y}`;
})
.join(" ");
}
</script>
<div class="wrapper">
<p>Runtime Execution</p>
<span class="min">{min}ms</span>
<span class="max">{max}ms</span>
<svg preserveAspectRatio="none" viewBox="0 0 100 100">
<polyline vector-effect="non-scaling-stroke" points={constructPath()} />
</svg>
</div>
<style>
span {
position: absolute;
right: 10px;
font-size: 0.8em;
opacity: 0.5;
}
.max {
top: 4px;
}
.min {
bottom: 5px;
}
.wrapper {
position: relative;
border-bottom: solid thin var(--outline);
display: flex;
}
p {
margin: 0px;
top: 3px;
left: 5px;
font-size: 0.9em;
opacity: 0.5;
position: absolute;
}
svg {
height: 124px;
margin: 24px 0px;
border-top: solid thin var(--outline);
border-bottom: solid thin var(--outline);
width: 100%;
}
polyline {
fill: none;
stroke: var(--layer-3);
opacity: 0.5;
stroke-width: 1;
}
</style>

View File

@@ -1,17 +1,122 @@
<script lang="ts">
import type { PerformanceData } from ".";
import { browser } from "$app/environment";
import Monitor from "./Monitor.svelte";
import { humanizeNumber } from "$lib/helpers";
type PerformanceData = {
total: Record<string, number>;
runs: Record<string, number[]>[];
};
export let data: PerformanceData;
export let viewer: PerformanceData;
function getPerformanceData() {
return Object.entries(data.total).sort((a, b) => b[1] - a[1]);
return Object.entries(data.total)
.sort((a, b) => b[1] - a[1])
.filter(([key]) => !key.startsWith("node/"));
}
function getNodePerformanceData() {
return Object.entries(data.total)
.filter(([key]) => key.startsWith("node/"))
.sort((a, b) => b[1] - a[1]);
}
function getViewerPerformanceData() {
return Object.entries(viewer.total)
.filter(([key]) => key !== "total-vertices" && key !== "total-faces")
.sort((a, b) => b[1] - a[1]);
}
function constructPoints(key: keyof (typeof data.runs)[0]) {
return data.runs
.map((run, i) => {
return run[key][0];
})
.slice(-100);
}
</script>
{#if data.runs.length !== 0}
{#each getPerformanceData() as [key, value]}
<p>{key}: {Math.floor(value * 100) / 100}ms</p>
{/each}
{:else}
<p>No runs available</p>
{/if}
{#key data}
{#if browser}
<Monitor points={constructPoints("total")} />
{/if}
<div class="px-4">
{#if data.runs.length !== 0}
<h3>General</h3>
<table>
{#each getPerformanceData() as [key, value]}
<tr>
<td>
{Math.floor(value * 100) / 100}<span>ms</span>
</td>
<td>
{key}
</td>
</tr>
{/each}
<h3>Nodes</h3>
{#each getNodePerformanceData() as [key, value]}
<tr>
<td>
{Math.floor(value * 100) / 100}<span>ms</span>
</td>
<td>
{key.split("/").slice(-1).join("/")}
</td>
</tr>
{/each}
{#if viewer.runs.length}
<h3>Viewer</h3>
<tr>
<td>{humanizeNumber(viewer.runs.at(-1)?.["total-vertices"])}</td>
<td>Vertices</td>
</tr>
<tr>
<td>{humanizeNumber(viewer.runs.at(-1)?.["total-faces"])}</td>
<td>Faces</td>
</tr>
{#each getViewerPerformanceData() as [key, value]}
<tr>
<td>
{Math.floor(value * 100) / 100}<span>ms</span>
</td>
<td>
{key.split("/").slice(-1).join("/")}
</td>
</tr>
{/each}
{/if}
</table>
{:else}
<p>No runs available</p>
{/if}
</div>
{/key}
<style>
h3 {
margin: 0;
margin-top: 1em;
margin-bottom: 0.2em;
margin-left: 3px;
}
span {
opacity: 0.3;
margin-left: 4px;
}
td {
padding-right: 10px;
padding-block: 5px;
}
tr > td:nth-child(1) {
text-align: right;
}
tr > td:nth-child(2) {
opacity: 0.5;
}
</style>

View File

@@ -1,68 +1,2 @@
import { readable, type Readable } from "svelte/store";
export type PerformanceData = {
total: Record<string, number>;
runs: Record<string, number[]>[];
}
export interface PerformanceStore extends Readable<PerformanceData> {
startRun(): void;
stopRun(): void;
addPoint(name: string, value?: number): void;
get: () => PerformanceData;
}
export function createPerformanceStore(): PerformanceStore {
let data: PerformanceData = { total: {}, runs: [] };
let currentRun: Record<string, number[]> | undefined;
let set: (v: PerformanceData) => void;
const { subscribe } = readable<PerformanceData>({ total: {}, runs: [] }, (_set) => {
set = _set;
});
function startRun() {
currentRun = {};
}
function stopRun() {
if (currentRun) {
// Calculate total
Object.keys(currentRun).forEach((name) => {
if (!currentRun?.[name]?.length) return;
let runTotal = currentRun[name].reduce((a, b) => a + b, 0) / currentRun[name].length;
if (!data.total[name]) {
data.total[name] = runTotal;
} else {
data.total[name] = (data.total[name] + runTotal) / 2;
}
});
data.runs.push(currentRun);
currentRun = undefined;
if (set) set(data);
}
}
function addPoint(name: string, value: number) {
if (!currentRun) return;
currentRun[name] = currentRun[name] || [];
currentRun[name].push(value);
}
function get() {
return data;
}
return {
subscribe,
startRun,
stopRun,
addPoint,
get
}
}
export * from "./store";
export { default as PerformanceViewer } from "./PerformanceViewer.svelte";

View File

@@ -0,0 +1,67 @@
import { readable, type Readable } from "svelte/store";
export type PerformanceData = {
total: Record<string, number>;
runs: Record<string, number[]>[];
}
export interface PerformanceStore extends Readable<PerformanceData> {
startRun(): void;
stopRun(): void;
addPoint(name: string, value?: number): void;
get: () => PerformanceData;
}
export function createPerformanceStore(): PerformanceStore {
let data: PerformanceData = { total: {}, runs: [] };
let currentRun: Record<string, number[]> | undefined;
let set: (v: PerformanceData) => void;
const { subscribe } = readable<PerformanceData>({ total: {}, runs: [] }, (_set) => {
set = _set;
});
function startRun() {
currentRun = {};
}
function stopRun() {
if (currentRun) {
// Calculate total
Object.keys(currentRun).forEach((name) => {
if (!currentRun?.[name]?.length) return;
let runTotal = currentRun[name].reduce((a, b) => a + b, 0) / currentRun[name].length;
if (!data.total[name]) {
data.total[name] = runTotal;
} else {
data.total[name] = (data.total[name] + runTotal) / 2;
}
});
data.runs.push(currentRun);
currentRun = undefined;
if (set) set(data);
}
}
function addPoint(name: string, value: number) {
if (!currentRun) return;
currentRun[name] = currentRun[name] || [];
currentRun[name].push(value);
}
function get() {
return data;
}
return {
subscribe,
startRun,
stopRun,
addPoint,
get
}
}