@ogygia/devtools 0.0.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +24 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +24 -0
- package/dist/devtools/BoundaryOverlay.svelte +396 -0
- package/dist/devtools/BoundaryOverlay.svelte.d.ts +19 -0
- package/dist/devtools/Devtools.svelte +663 -0
- package/dist/devtools/Devtools.svelte.d.ts +15 -0
- package/dist/devtools/HubTab.svelte +206 -0
- package/dist/devtools/HubTab.svelte.d.ts +11 -0
- package/dist/devtools/HydrationTab.svelte +237 -0
- package/dist/devtools/HydrationTab.svelte.d.ts +13 -0
- package/dist/devtools/IslandDetail.svelte +615 -0
- package/dist/devtools/IslandDetail.svelte.d.ts +15 -0
- package/dist/devtools/LedgerTab.svelte +287 -0
- package/dist/devtools/LedgerTab.svelte.d.ts +11 -0
- package/dist/devtools/LensTab.svelte +290 -0
- package/dist/devtools/LensTab.svelte.d.ts +19 -0
- package/dist/devtools/NavTab.svelte +229 -0
- package/dist/devtools/NavTab.svelte.d.ts +11 -0
- package/dist/devtools/PageTab.svelte +1122 -0
- package/dist/devtools/PageTab.svelte.d.ts +15 -0
- package/dist/devtools/ProfilerTab.svelte +755 -0
- package/dist/devtools/ProfilerTab.svelte.d.ts +15 -0
- package/dist/devtools/PropsTree.svelte +155 -0
- package/dist/devtools/PropsTree.svelte.d.ts +15 -0
- package/dist/devtools/SessionTab.svelte +796 -0
- package/dist/devtools/SessionTab.svelte.d.ts +11 -0
- package/dist/devtools/TimelineTab.svelte +267 -0
- package/dist/devtools/TimelineTab.svelte.d.ts +11 -0
- package/dist/devtools/WireTab.svelte +149 -0
- package/dist/devtools/WireTab.svelte.d.ts +11 -0
- package/dist/devtools/bytes.d.ts +70 -0
- package/dist/devtools/bytes.js +82 -0
- package/dist/devtools/cache-headers.d.ts +20 -0
- package/dist/devtools/cache-headers.js +81 -0
- package/dist/devtools/highlight.d.ts +7 -0
- package/dist/devtools/highlight.js +83 -0
- package/dist/devtools/hydration.d.ts +48 -0
- package/dist/devtools/hydration.js +93 -0
- package/dist/devtools/index.d.ts +3 -0
- package/dist/devtools/index.js +3 -0
- package/dist/devtools/ledger-dom.d.ts +7 -0
- package/dist/devtools/ledger-dom.js +151 -0
- package/dist/devtools/leftovers.d.ts +77 -0
- package/dist/devtools/leftovers.js +319 -0
- package/dist/devtools/names.d.ts +1 -0
- package/dist/devtools/names.js +34 -0
- package/dist/devtools/page.d.ts +96 -0
- package/dist/devtools/page.js +957 -0
- package/dist/devtools/profile-anchors.d.ts +22 -0
- package/dist/devtools/profile-anchors.js +135 -0
- package/dist/devtools/profile-store.d.ts +175 -0
- package/dist/devtools/profile-store.js +239 -0
- package/dist/devtools/regions.d.ts +77 -0
- package/dist/devtools/regions.js +132 -0
- package/dist/devtools/session.d.ts +31 -0
- package/dist/devtools/session.js +455 -0
- package/dist/devtools/since-load.d.ts +50 -0
- package/dist/devtools/since-load.js +89 -0
- package/dist/devtools/source-lines.d.ts +24 -0
- package/dist/devtools/source-lines.js +106 -0
- package/dist/devtools/styles.d.ts +52 -0
- package/dist/devtools/styles.js +248 -0
- package/dist/devtools/testing-engine.d.ts +83 -0
- package/dist/devtools/testing-engine.js +220 -0
- package/dist/devtools/ui-app.d.ts +5 -0
- package/dist/devtools/ui-app.js +69 -0
- package/dist/devtools/ui.d.ts +50 -0
- package/dist/devtools/ui.js +175 -0
- package/dist/profiler/alloc.d.ts +75 -0
- package/dist/profiler/alloc.js +76 -0
- package/dist/profiler/analyze.d.ts +437 -0
- package/dist/profiler/analyze.js +1941 -0
- package/dist/profiler/app-path.d.ts +7 -0
- package/dist/profiler/app-path.js +26 -0
- package/dist/profiler/async-io.d.ts +58 -0
- package/dist/profiler/async-io.js +187 -0
- package/dist/profiler/beacon-standalone.d.ts +4 -0
- package/dist/profiler/beacon-standalone.js +409 -0
- package/dist/profiler/browser-findings.d.ts +25 -0
- package/dist/profiler/browser-findings.js +260 -0
- package/dist/profiler/byte-strip.d.ts +58 -0
- package/dist/profiler/byte-strip.js +228 -0
- package/dist/profiler/client-files.d.ts +16 -0
- package/dist/profiler/client-files.js +60 -0
- package/dist/profiler/client-windows.d.ts +49 -0
- package/dist/profiler/client-windows.js +95 -0
- package/dist/profiler/client.d.ts +40 -0
- package/dist/profiler/client.js +82 -0
- package/dist/profiler/compare.d.ts +308 -0
- package/dist/profiler/compare.js +733 -0
- package/dist/profiler/compress.d.ts +10 -0
- package/dist/profiler/compress.js +36 -0
- package/dist/profiler/contention.d.ts +60 -0
- package/dist/profiler/contention.js +86 -0
- package/dist/profiler/crypto.d.ts +19 -0
- package/dist/profiler/crypto.js +101 -0
- package/dist/profiler/doc-diff.d.ts +47 -0
- package/dist/profiler/doc-diff.js +214 -0
- package/dist/profiler/dom-diff.d.ts +43 -0
- package/dist/profiler/dom-diff.js +121 -0
- package/dist/profiler/drill.d.ts +89 -0
- package/dist/profiler/drill.js +553 -0
- package/dist/profiler/embedded-maps.d.ts +37 -0
- package/dist/profiler/embedded-maps.js +135 -0
- package/dist/profiler/env.d.ts +6 -0
- package/dist/profiler/env.js +10 -0
- package/dist/profiler/forecast.d.ts +76 -0
- package/dist/profiler/forecast.js +225 -0
- package/dist/profiler/frames.d.ts +11 -0
- package/dist/profiler/frames.js +42 -0
- package/dist/profiler/gc.d.ts +144 -0
- package/dist/profiler/gc.js +271 -0
- package/dist/profiler/hole-slots.d.ts +31 -0
- package/dist/profiler/hole-slots.js +90 -0
- package/dist/profiler/index.d.ts +288 -0
- package/dist/profiler/index.js +4921 -0
- package/dist/profiler/insights.d.ts +96 -0
- package/dist/profiler/insights.js +239 -0
- package/dist/profiler/ledger.d.ts +121 -0
- package/dist/profiler/ledger.js +440 -0
- package/dist/profiler/lineage.d.ts +81 -0
- package/dist/profiler/lineage.js +359 -0
- package/dist/profiler/module-map.d.ts +12 -0
- package/dist/profiler/module-map.js +94 -0
- package/dist/profiler/net.d.ts +169 -0
- package/dist/profiler/net.js +586 -0
- package/dist/profiler/on-demand.d.ts +11 -0
- package/dist/profiler/on-demand.js +15 -0
- package/dist/profiler/own-requests.d.ts +9 -0
- package/dist/profiler/own-requests.js +17 -0
- package/dist/profiler/patterns.d.ts +476 -0
- package/dist/profiler/patterns.js +2203 -0
- package/dist/profiler/profiler-router.d.ts +245 -0
- package/dist/profiler/profiler-router.js +113 -0
- package/dist/profiler/refresh-stub.d.ts +2 -0
- package/dist/profiler/refresh-stub.js +37 -0
- package/dist/profiler/report.d.ts +1404 -0
- package/dist/profiler/report.js +2638 -0
- package/dist/profiler/river.d.ts +65 -0
- package/dist/profiler/river.js +298 -0
- package/dist/profiler/route-files.d.ts +22 -0
- package/dist/profiler/route-files.js +55 -0
- package/dist/profiler/route-imports.d.ts +14 -0
- package/dist/profiler/route-imports.js +83 -0
- package/dist/profiler/saving.d.ts +22 -0
- package/dist/profiler/saving.js +42 -0
- package/dist/profiler/score.d.ts +109 -0
- package/dist/profiler/score.js +261 -0
- package/dist/profiler/session-cookie.d.ts +28 -0
- package/dist/profiler/session-cookie.js +45 -0
- package/dist/profiler/sink.d.ts +81 -0
- package/dist/profiler/sink.js +124 -0
- package/dist/profiler/site-fixes.d.ts +25 -0
- package/dist/profiler/site-fixes.js +62 -0
- package/dist/profiler/source-scan.d.ts +210 -0
- package/dist/profiler/source-scan.js +1724 -0
- package/dist/profiler/span.d.ts +90 -0
- package/dist/profiler/span.js +109 -0
- package/dist/profiler/stacks.d.ts +43 -0
- package/dist/profiler/stacks.js +107 -0
- package/dist/profiler/standalone.d.ts +27 -0
- package/dist/profiler/standalone.js +98 -0
- package/dist/profiler/steps.d.ts +39 -0
- package/dist/profiler/steps.js +74 -0
- package/dist/profiler/storage/index.d.ts +87 -0
- package/dist/profiler/storage/index.js +76 -0
- package/dist/profiler/storage/postgres.d.ts +12 -0
- package/dist/profiler/storage/postgres.js +94 -0
- package/dist/profiler/storage/redis.d.ts +19 -0
- package/dist/profiler/storage/redis.js +148 -0
- package/dist/profiler/storage/sqlite.d.ts +2 -0
- package/dist/profiler/storage/sqlite.js +85 -0
- package/dist/profiler/storage/visits.d.ts +4 -0
- package/dist/profiler/storage/visits.js +6 -0
- package/dist/profiler/stream-tail.d.ts +26 -0
- package/dist/profiler/stream-tail.js +74 -0
- package/dist/profiler/timeline.d.ts +279 -0
- package/dist/profiler/timeline.js +690 -0
- package/dist/profiler/ui/AllocStrip.svelte +146 -0
- package/dist/profiler/ui/AllocStrip.svelte.d.ts +17 -0
- package/dist/profiler/ui/Awaits.svelte +363 -0
- package/dist/profiler/ui/Awaits.svelte.d.ts +16 -0
- package/dist/profiler/ui/ByteStrip.svelte +182 -0
- package/dist/profiler/ui/ByteStrip.svelte.d.ts +18 -0
- package/dist/profiler/ui/Compare.svelte +24 -0
- package/dist/profiler/ui/Compare.svelte.d.ts +16 -0
- package/dist/profiler/ui/CompareBody.svelte +429 -0
- package/dist/profiler/ui/CompareBody.svelte.d.ts +8 -0
- package/dist/profiler/ui/ComponentsTable.svelte +265 -0
- package/dist/profiler/ui/ComponentsTable.svelte.d.ts +20 -0
- package/dist/profiler/ui/Dashboard.svelte +492 -0
- package/dist/profiler/ui/Dashboard.svelte.d.ts +31 -0
- package/dist/profiler/ui/DataRiver.svelte +206 -0
- package/dist/profiler/ui/DataRiver.svelte.d.ts +13 -0
- package/dist/profiler/ui/DomTravel.svelte +207 -0
- package/dist/profiler/ui/DomTravel.svelte.d.ts +9 -0
- package/dist/profiler/ui/DownloadHtml.svelte +52 -0
- package/dist/profiler/ui/DownloadHtml.svelte.d.ts +10 -0
- package/dist/profiler/ui/Drill.svelte +276 -0
- package/dist/profiler/ui/Drill.svelte.d.ts +12 -0
- package/dist/profiler/ui/ExportButton.svelte +59 -0
- package/dist/profiler/ui/ExportButton.svelte.d.ts +8 -0
- package/dist/profiler/ui/Flame.svelte +222 -0
- package/dist/profiler/ui/Flame.svelte.d.ts +12 -0
- package/dist/profiler/ui/FrameDetails.svelte +308 -0
- package/dist/profiler/ui/FrameDetails.svelte.d.ts +16 -0
- package/dist/profiler/ui/FunctionsTable.svelte +156 -0
- package/dist/profiler/ui/FunctionsTable.svelte.d.ts +17 -0
- package/dist/profiler/ui/IslandHeatmap.svelte +151 -0
- package/dist/profiler/ui/IslandHeatmap.svelte.d.ts +16 -0
- package/dist/profiler/ui/IslandsTable.svelte +448 -0
- package/dist/profiler/ui/IslandsTable.svelte.d.ts +16 -0
- package/dist/profiler/ui/KeepLocal.svelte +46 -0
- package/dist/profiler/ui/KeepLocal.svelte.d.ts +8 -0
- package/dist/profiler/ui/Ledger.svelte +196 -0
- package/dist/profiler/ui/Ledger.svelte.d.ts +18 -0
- package/dist/profiler/ui/LocalCompare.svelte +48 -0
- package/dist/profiler/ui/LocalCompare.svelte.d.ts +8 -0
- package/dist/profiler/ui/LocalReports.svelte +68 -0
- package/dist/profiler/ui/LocalReports.svelte.d.ts +7 -0
- package/dist/profiler/ui/Login.svelte +13 -0
- package/dist/profiler/ui/Login.svelte.d.ts +12 -0
- package/dist/profiler/ui/LoginForm.svelte +42 -0
- package/dist/profiler/ui/LoginForm.svelte.d.ts +7 -0
- package/dist/profiler/ui/Message.svelte +10 -0
- package/dist/profiler/ui/Message.svelte.d.ts +12 -0
- package/dist/profiler/ui/OnThisPage.svelte +137 -0
- package/dist/profiler/ui/OnThisPage.svelte.d.ts +3 -0
- package/dist/profiler/ui/OneClock.svelte +297 -0
- package/dist/profiler/ui/OneClock.svelte.d.ts +27 -0
- package/dist/profiler/ui/Panel.svelte +10 -0
- package/dist/profiler/ui/Panel.svelte.d.ts +16 -0
- package/dist/profiler/ui/Paths.svelte +269 -0
- package/dist/profiler/ui/Paths.svelte.d.ts +15 -0
- package/dist/profiler/ui/Patterns.svelte +364 -0
- package/dist/profiler/ui/Patterns.svelte.d.ts +15 -0
- package/dist/profiler/ui/PermalinkGate.svelte +143 -0
- package/dist/profiler/ui/PermalinkGate.svelte.d.ts +10 -0
- package/dist/profiler/ui/RenderSteps.svelte +218 -0
- package/dist/profiler/ui/RenderSteps.svelte.d.ts +13 -0
- package/dist/profiler/ui/Report.svelte +28 -0
- package/dist/profiler/ui/Report.svelte.d.ts +20 -0
- package/dist/profiler/ui/ReportBody.svelte +2592 -0
- package/dist/profiler/ui/ReportBody.svelte.d.ts +21 -0
- package/dist/profiler/ui/Run.svelte +17 -0
- package/dist/profiler/ui/Run.svelte.d.ts +14 -0
- package/dist/profiler/ui/RunView.svelte +146 -0
- package/dist/profiler/ui/RunView.svelte.d.ts +10 -0
- package/dist/profiler/ui/ScoreCard.svelte +197 -0
- package/dist/profiler/ui/ScoreCard.svelte.d.ts +7 -0
- package/dist/profiler/ui/Scrub.svelte +293 -0
- package/dist/profiler/ui/Scrub.svelte.d.ts +18 -0
- package/dist/profiler/ui/SeedExplainer.svelte +193 -0
- package/dist/profiler/ui/SeedExplainer.svelte.d.ts +16 -0
- package/dist/profiler/ui/ShareLink.svelte +148 -0
- package/dist/profiler/ui/ShareLink.svelte.d.ts +8 -0
- package/dist/profiler/ui/Shell.svelte +50 -0
- package/dist/profiler/ui/Shell.svelte.d.ts +27 -0
- package/dist/profiler/ui/Sidebar.svelte +312 -0
- package/dist/profiler/ui/Sidebar.svelte.d.ts +7 -0
- package/dist/profiler/ui/Site.svelte +20 -0
- package/dist/profiler/ui/Site.svelte.d.ts +23 -0
- package/dist/profiler/ui/SiteView.svelte +385 -0
- package/dist/profiler/ui/SiteView.svelte.d.ts +27 -0
- package/dist/profiler/ui/ThemeSwitch.svelte +78 -0
- package/dist/profiler/ui/ThemeSwitch.svelte.d.ts +3 -0
- package/dist/profiler/ui/Timeline.svelte +672 -0
- package/dist/profiler/ui/Timeline.svelte.d.ts +22 -0
- package/dist/profiler/ui/Treemap.svelte +278 -0
- package/dist/profiler/ui/Treemap.svelte.d.ts +20 -0
- package/dist/profiler/ui/Upload.svelte +19 -0
- package/dist/profiler/ui/Upload.svelte.d.ts +10 -0
- package/dist/profiler/ui/UploadForm.svelte +59 -0
- package/dist/profiler/ui/UploadForm.svelte.d.ts +6 -0
- package/dist/profiler/ui/WaitingTable.svelte +55 -0
- package/dist/profiler/ui/WaitingTable.svelte.d.ts +14 -0
- package/dist/profiler/ui/Waterfall.svelte +371 -0
- package/dist/profiler/ui/Waterfall.svelte.d.ts +7 -0
- package/dist/profiler/ui/WhatIf.svelte +87 -0
- package/dist/profiler/ui/WhatIf.svelte.d.ts +18 -0
- package/dist/profiler/ui/fake-progress.svelte.d.ts +15 -0
- package/dist/profiler/ui/fake-progress.svelte.js +38 -0
- package/dist/profiler/ui/format.d.ts +20 -0
- package/dist/profiler/ui/format.js +71 -0
- package/dist/profiler/ui/permalink.d.ts +9 -0
- package/dist/profiler/ui/permalink.js +108 -0
- package/dist/profiler/ui/press.d.ts +5 -0
- package/dist/profiler/ui/press.js +19 -0
- package/dist/profiler/ui/profiler.css +650 -0
- package/dist/profiler/ui/report-data.d.ts +189 -0
- package/dist/profiler/ui/report-data.js +393 -0
- package/dist/profiler/ui/report-request.d.ts +6 -0
- package/dist/profiler/ui/report-request.js +50 -0
- package/dist/profiler/ui/row-anchor.svelte.d.ts +12 -0
- package/dist/profiler/ui/row-anchor.svelte.js +44 -0
- package/dist/profiler/ui/sort.svelte.d.ts +14 -0
- package/dist/profiler/ui/sort.svelte.js +37 -0
- package/dist/profiler/ui/store.d.ts +45 -0
- package/dist/profiler/ui/store.js +92 -0
- package/dist/profiler/visit.d.ts +389 -0
- package/dist/profiler/visit.js +1002 -0
- package/dist/report.d.ts +5 -0
- package/dist/report.js +4 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +38 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.js +78 -0
- package/package.json +99 -6
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { PHASE_LABEL, load_lane_of } from "./timeline.js";
|
|
2
|
+
// src/profiler/drill.ts
|
|
3
|
+
/** `lib/x.ts:42` or `lib/x.ts:42:7` → the file and the line; undefined when `at` names no line */
|
|
4
|
+
function at_line(at) {
|
|
5
|
+
const parts = at.split(":");
|
|
6
|
+
const num = (s) => !!s && s.length > 0 && [...s].every((c) => c >= "0" && c <= "9");
|
|
7
|
+
let n = parts.length;
|
|
8
|
+
if (n >= 3 && num(parts[n - 1]) && num(parts[n - 2])) n--;
|
|
9
|
+
if (n < 2 || !num(parts[n - 1])) return void 0;
|
|
10
|
+
return {
|
|
11
|
+
file: parts.slice(0, n - 1).join(":"),
|
|
12
|
+
line: Number(parts[n - 1])
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const r2 = (n) => Math.round(n * 100) / 100;
|
|
16
|
+
/** children kept per level; the rest fold into one row */
|
|
17
|
+
const KEEP = 6;
|
|
18
|
+
/** a child under this share of its parent folds too */
|
|
19
|
+
const FOLD_SHARE = .02;
|
|
20
|
+
/** more rows past KEEP while the fold would hide over this share of the parent */
|
|
21
|
+
const KEEP_MAX = 12;
|
|
22
|
+
const FOLD_MAX_HIDDEN = .1;
|
|
23
|
+
/** `GET host/api/product/P12` → `GET host/api/product/:id`: one row per endpoint, not per id */
|
|
24
|
+
function call_group(label) {
|
|
25
|
+
const sp = label.indexOf(" ");
|
|
26
|
+
if (sp === -1) return label;
|
|
27
|
+
const method = label.slice(0, sp);
|
|
28
|
+
const rest = label.slice(sp + 1);
|
|
29
|
+
const q = rest.indexOf("?");
|
|
30
|
+
const path = (q === -1 ? rest : rest.slice(0, q)).split("/");
|
|
31
|
+
for (let i = 1; i < path.length; i++) {
|
|
32
|
+
const s = path[i];
|
|
33
|
+
let digits = 0;
|
|
34
|
+
for (let k = 0; k < s.length; k++) if (s.charCodeAt(k) >= 48 && s.charCodeAt(k) <= 57) digits++;
|
|
35
|
+
const version = s.length >= 2 && s[0] === "v" && digits === s.length - 1;
|
|
36
|
+
if (s && !version && (digits === s.length || digits >= 2 && digits / s.length >= .2 || digits > 0 && digits / s.length >= .5 || s.length >= 24)) path[i] = ":id";
|
|
37
|
+
}
|
|
38
|
+
return `${method} ${path.join("/")}`;
|
|
39
|
+
}
|
|
40
|
+
/** a library owner (`render2 (@acme/ui)`) reads as its package; Node's own as `node core` */
|
|
41
|
+
function owner_group(s) {
|
|
42
|
+
const open = s.label.lastIndexOf(" (");
|
|
43
|
+
if (s.category === "dependency" && open !== -1 && s.label.endsWith(")")) return s.label.slice(open + 2, -1);
|
|
44
|
+
if (s.category === "node") return "node core";
|
|
45
|
+
return s.label;
|
|
46
|
+
}
|
|
47
|
+
/** `GET host/path`: an HTTP call (a timer, a file read or a span has no method word) */
|
|
48
|
+
function is_http(label) {
|
|
49
|
+
const sp = label.indexOf(" ");
|
|
50
|
+
if (sp < 3 || sp > 7) return false;
|
|
51
|
+
for (let i = 0; i < sp; i++) {
|
|
52
|
+
const c = label.charCodeAt(i);
|
|
53
|
+
if (c < 65 || c > 90) return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/** the first pending resource with the line that queued it: `Immediate from x.ts:52` → `x.ts:52` */
|
|
58
|
+
function pending_place(pending) {
|
|
59
|
+
for (const p of pending ?? []) {
|
|
60
|
+
const at = p.indexOf(" from ");
|
|
61
|
+
if (at !== -1) return p.slice(at + 6);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** a package row's function: `render2 (@acme/ui)` → `render2`, `node core: writev` → `writev` */
|
|
65
|
+
function sub_fn(label) {
|
|
66
|
+
if (label.startsWith("node core: ")) return label.slice(11);
|
|
67
|
+
const open = label.lastIndexOf(" (");
|
|
68
|
+
return open !== -1 && label.endsWith(")") ? label.slice(0, open) : label;
|
|
69
|
+
}
|
|
70
|
+
/** a place in the framework, a package or the server bundle: never "your line" */
|
|
71
|
+
function foreign_place(caller) {
|
|
72
|
+
return caller.includes("node_modules/") || caller.includes("output/server/") || caller.includes("@sveltejs/") || caller.includes("node:") || caller.includes(".svelte-kit/");
|
|
73
|
+
}
|
|
74
|
+
/** the line of yours at the top of a call's path — the outermost of your frames before the
|
|
75
|
+
* framework's (`svc` ← `currentUser` ← `load:70` → `load:70`): where your code asked for it */
|
|
76
|
+
function outer_of(caller, callers) {
|
|
77
|
+
if (!callers || callers[0] !== caller) return void 0;
|
|
78
|
+
let top;
|
|
79
|
+
for (let i = 1; i < callers.length && !foreign_place(callers[i]); i++) {
|
|
80
|
+
if (callers[i].includes("hooks.server.")) break;
|
|
81
|
+
top = callers[i];
|
|
82
|
+
}
|
|
83
|
+
return top && top !== caller ? top : void 0;
|
|
84
|
+
}
|
|
85
|
+
function fold(nodes, parent_ms) {
|
|
86
|
+
nodes.sort((a, b) => b.ms - a.ms);
|
|
87
|
+
const keep = [];
|
|
88
|
+
let rest_ms = 0;
|
|
89
|
+
let rest_n = 0;
|
|
90
|
+
let left = nodes.reduce((s, n) => s + n.ms, 0);
|
|
91
|
+
for (const n of nodes) if ((keep.length < KEEP || keep.length < KEEP_MAX && left > parent_ms * FOLD_MAX_HIDDEN) && n.ms >= parent_ms * FOLD_SHARE) {
|
|
92
|
+
keep.push(n);
|
|
93
|
+
left -= n.ms;
|
|
94
|
+
} else {
|
|
95
|
+
rest_ms += n.ms;
|
|
96
|
+
rest_n++;
|
|
97
|
+
}
|
|
98
|
+
if (rest_n) keep.push({
|
|
99
|
+
label: `${rest_n} more`,
|
|
100
|
+
ms: r2(rest_ms),
|
|
101
|
+
kind: "more",
|
|
102
|
+
children: nodes.filter((n) => !keep.includes(n))
|
|
103
|
+
});
|
|
104
|
+
return keep;
|
|
105
|
+
}
|
|
106
|
+
/** `src/lib/ds.ts:17` → its folders and file, and the line */
|
|
107
|
+
function split_place(at) {
|
|
108
|
+
const colon = at.lastIndexOf(":");
|
|
109
|
+
return {
|
|
110
|
+
parts: (colon === -1 ? at : at.slice(0, colon)).split("/").filter(Boolean),
|
|
111
|
+
line: colon === -1 ? "" : at.slice(colon + 1)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** the same file when the shorter path is the tail of the longer one: a report spells one file
|
|
115
|
+
* `src/lib/…`, `lib/…` or absolute */
|
|
116
|
+
function same_file(a, b) {
|
|
117
|
+
const n = Math.min(a.length, b.length);
|
|
118
|
+
for (let i = 1; i <= n; i++) if (a[a.length - i] !== b[b.length - i]) return false;
|
|
119
|
+
return n > 0;
|
|
120
|
+
}
|
|
121
|
+
/** Tag every row with the patterns found on its line (a site's own line, or a caller line it names),
|
|
122
|
+
* and a row with lines under it with theirs too. */
|
|
123
|
+
function tag_why(root, patterns) {
|
|
124
|
+
const at_line = /* @__PURE__ */ new Map();
|
|
125
|
+
const add = (file, line, kind) => {
|
|
126
|
+
const { parts } = split_place(file);
|
|
127
|
+
const k = `${parts[parts.length - 1]}:${line}`;
|
|
128
|
+
(at_line.get(k) ?? at_line.set(k, []).get(k)).push({
|
|
129
|
+
parts,
|
|
130
|
+
kind
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
for (const p of patterns) for (const s of p.sites) {
|
|
134
|
+
add(s.path || s.file, s.line, p.kind);
|
|
135
|
+
for (const v of s.via ?? []) add(v.path || v.file, v.line, p.kind);
|
|
136
|
+
}
|
|
137
|
+
if (!at_line.size) return;
|
|
138
|
+
const kinds_at = (at) => {
|
|
139
|
+
const { parts, line } = split_place(at);
|
|
140
|
+
return (at_line.get(`${parts[parts.length - 1]}:${line}`) ?? []).filter((e) => same_file(e.parts, parts)).map((e) => e.kind);
|
|
141
|
+
};
|
|
142
|
+
const walk = (n) => {
|
|
143
|
+
const kinds = new Set(n.at && n.kind !== "lane" ? kinds_at(n.at) : []);
|
|
144
|
+
for (const c of n.children ?? []) for (const k of walk(c)) kinds.add(k);
|
|
145
|
+
if (kinds.size && n.kind !== "render" && n.kind !== "phase") n.why = [...kinds];
|
|
146
|
+
return kinds;
|
|
147
|
+
};
|
|
148
|
+
walk(root);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* WHAT A ROW WAS FOR: the page-data keys its lines feed. A wait or a computation whose line (its
|
|
152
|
+
* own, or one of the lines under it) is among a key's source lines in its load (lineage +
|
|
153
|
+
* `key_sources`) fills that key. When every key it fills is read by nothing, the row's whole time
|
|
154
|
+
* bought nothing.
|
|
155
|
+
*/
|
|
156
|
+
function tag_fills(root, keys) {
|
|
157
|
+
const sourced = keys.filter((k) => k.from && k.lines?.length).map((k) => ({
|
|
158
|
+
...k,
|
|
159
|
+
parts: split_place(k.from).parts,
|
|
160
|
+
set: new Set(k.lines),
|
|
161
|
+
named: new Set(k.names ?? [])
|
|
162
|
+
}));
|
|
163
|
+
if (!sourced.length) return;
|
|
164
|
+
const fills_at = (at) => {
|
|
165
|
+
const { parts, line } = split_place(at);
|
|
166
|
+
const n = Number(line);
|
|
167
|
+
return sourced.filter((k) => k.set.has(n) && same_file(k.parts, parts));
|
|
168
|
+
};
|
|
169
|
+
const walk = (n, lane) => {
|
|
170
|
+
const lines = [];
|
|
171
|
+
const lines_under = (m) => (m.children ?? []).flatMap((c) => c.kind === "line" ? [c] : c.kind === "more" ? lines_under(c) : []);
|
|
172
|
+
const collect = (m) => {
|
|
173
|
+
const under = lines_under(m);
|
|
174
|
+
if (m.at && (m.kind === "line" || m.kind === "cpu") && !under.length) lines.push(m.at);
|
|
175
|
+
for (const c of under) collect(c);
|
|
176
|
+
};
|
|
177
|
+
collect(n);
|
|
178
|
+
if (n.kind === "wait" || n.kind === "cpu") {
|
|
179
|
+
const found = /* @__PURE__ */ new Map();
|
|
180
|
+
let unexplained = false;
|
|
181
|
+
for (const at of lines) {
|
|
182
|
+
const ks = fills_at(at);
|
|
183
|
+
if (!ks.length) unexplained = true;
|
|
184
|
+
for (const k of ks) found.set(k.key, (found.get(k.key) ?? false) || k.verdict !== "unread");
|
|
185
|
+
}
|
|
186
|
+
if (unexplained) found.clear();
|
|
187
|
+
if (!found.size && n.kind === "cpu" && lane) {
|
|
188
|
+
for (const k of sourced) if (k.named.has(n.label) && same_file(k.parts, lane)) found.set(k.key, (found.get(k.key) ?? false) || k.verdict !== "unread");
|
|
189
|
+
}
|
|
190
|
+
if (found.size) n.fills = [...found].map(([key, read]) => ({
|
|
191
|
+
key,
|
|
192
|
+
read
|
|
193
|
+
}));
|
|
194
|
+
}
|
|
195
|
+
if (n.kind === "line" && n.at && !n.fills) {
|
|
196
|
+
const found = /* @__PURE__ */ new Map();
|
|
197
|
+
for (const k of fills_at(n.at)) found.set(k.key, (found.get(k.key) ?? false) || k.verdict !== "unread");
|
|
198
|
+
if (found.size) n.fills = [...found].map(([key, read]) => ({
|
|
199
|
+
key,
|
|
200
|
+
read
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
const here = n.kind === "lane" && n.at ? split_place(n.at + ":0").parts : lane;
|
|
204
|
+
for (const c of n.children ?? []) walk(c, here);
|
|
205
|
+
};
|
|
206
|
+
walk(root);
|
|
207
|
+
}
|
|
208
|
+
/** THE WORK FOR NOTHING: the rows of one render whose every key is unread (the topmost such row on
|
|
209
|
+
* each path, so nothing counts twice), biggest first */
|
|
210
|
+
function unread_rows(root) {
|
|
211
|
+
const out = [];
|
|
212
|
+
const walk = (n) => {
|
|
213
|
+
if (n.fills?.length && n.fills.every((f) => !f.read)) {
|
|
214
|
+
out.push({
|
|
215
|
+
label: n.label,
|
|
216
|
+
ms: n.ms,
|
|
217
|
+
kind: n.kind,
|
|
218
|
+
keys: n.fills.map((f) => f.key),
|
|
219
|
+
...n.at ? { at: n.at } : {}
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
for (const c of n.children ?? []) walk(c);
|
|
224
|
+
};
|
|
225
|
+
if (root) walk(root);
|
|
226
|
+
return out.sort((a, b) => b.ms - a.ms);
|
|
227
|
+
}
|
|
228
|
+
/** `/abs/app/src/lib/x.ts` → `src/lib/x.ts`, `…/node_modules/pkg/a.js` → `pkg/a.js` */
|
|
229
|
+
function short_path(p) {
|
|
230
|
+
const nm = p.lastIndexOf("node_modules/");
|
|
231
|
+
if (nm !== -1) return p.slice(nm + 13);
|
|
232
|
+
const src = p.lastIndexOf("/src/");
|
|
233
|
+
return src !== -1 ? p.slice(src + 1) : p;
|
|
234
|
+
}
|
|
235
|
+
function build_drill(tl, ledger = [], patterns = [], gc_makers = [], renders_of = /* @__PURE__ */ new Map(), owner_runs = {}, cold_owners = /* @__PURE__ */ new Map(), wait_runs = {}) {
|
|
236
|
+
const root = build_tree(tl, ledger, gc_makers);
|
|
237
|
+
if (!root) return root;
|
|
238
|
+
if (Object.keys(owner_runs).length || Object.keys(wait_runs).length) {
|
|
239
|
+
const rows = /* @__PURE__ */ new Map();
|
|
240
|
+
const collect = (n, parent_kind) => {
|
|
241
|
+
if ((n.kind === "cpu" || n.kind === "wait") && (parent_kind === "phase" || parent_kind === "lane" || parent_kind === "more")) {
|
|
242
|
+
const k = n.kind + "\0" + n.label;
|
|
243
|
+
(rows.get(k) ?? rows.set(k, []).get(k)).push(n);
|
|
244
|
+
}
|
|
245
|
+
for (const c of n.children ?? []) collect(c, n.kind);
|
|
246
|
+
};
|
|
247
|
+
collect(root, "render");
|
|
248
|
+
for (const [k, list] of rows) {
|
|
249
|
+
const label = k.slice(k.indexOf("\0") + 1);
|
|
250
|
+
if (list[0].kind === "wait") {
|
|
251
|
+
const w = wait_runs[label];
|
|
252
|
+
if (list.length === 1 && w && w.length >= 2) list[0].runs = [r2(Math.min(...w)), r2(Math.max(...w))];
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const per = owner_runs[label];
|
|
256
|
+
if (list.length !== 1 || !per || per.length < 2) continue;
|
|
257
|
+
list[0].runs = [Math.min(...per), Math.max(...per)];
|
|
258
|
+
const cold = cold_owners.get(label);
|
|
259
|
+
if (cold !== void 0 && cold >= list[0].runs[1] * 1.5 && cold - list[0].runs[1] >= 5) list[0].cold = r2(cold);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (patterns.length) tag_why(root, patterns);
|
|
263
|
+
const per_item = new Set(patterns.filter((p) => p.kind === "render-per-item").flatMap((p) => p.sites.map((s) => s.fn_name ?? "")));
|
|
264
|
+
const walk = (n) => {
|
|
265
|
+
if (n.kind === "cpu") {
|
|
266
|
+
const count = renders_of.get(n.label);
|
|
267
|
+
if (count && count > 1) n.calls = count;
|
|
268
|
+
if (per_item.has(n.label) && !n.why?.includes("render-per-item")) n.why = [...n.why ?? [], "render-per-item"];
|
|
269
|
+
}
|
|
270
|
+
for (const c of n.children ?? []) walk(c);
|
|
271
|
+
};
|
|
272
|
+
walk(root);
|
|
273
|
+
return root;
|
|
274
|
+
}
|
|
275
|
+
function build_tree(tl, ledger, gc_makers) {
|
|
276
|
+
const gc_lines = (() => {
|
|
277
|
+
const by = /* @__PURE__ */ new Map();
|
|
278
|
+
const hot_line = (path, line) => {
|
|
279
|
+
const rows = ledger.filter((l) => l.path === path && l.fn && (l.fn.endsWith(`${path}:${line}`) || l.line === line));
|
|
280
|
+
return (rows.find((l) => l.mem_in_fn) ?? rows.sort((a, b) => b.cpu_ms - a.cpu_ms)[0])?.line ?? line;
|
|
281
|
+
};
|
|
282
|
+
for (const m of gc_makers) {
|
|
283
|
+
if (m.gc_ms <= 0) continue;
|
|
284
|
+
const at = m.at ? `${short_path(m.at.path)}:${hot_line(m.at.path, m.at.line)}` : m.url ? `${short_path(m.url)}:${m.line}` : m.name;
|
|
285
|
+
by.set(at, (by.get(at) ?? 0) + m.gc_ms);
|
|
286
|
+
}
|
|
287
|
+
const total = [...by.values()].reduce((s, v) => s + v, 0);
|
|
288
|
+
return total > 0 ? [...by].map(([at, ms]) => ({
|
|
289
|
+
at,
|
|
290
|
+
share: ms / total
|
|
291
|
+
})) : [];
|
|
292
|
+
})();
|
|
293
|
+
const segs = tl.segments.filter((s) => s.t1 > s.t0 && s.category !== "profiler");
|
|
294
|
+
if (!segs.length) return void 0;
|
|
295
|
+
const phases = /* @__PURE__ */ new Map();
|
|
296
|
+
const lane_of = (texts) => {
|
|
297
|
+
for (const t of texts) {
|
|
298
|
+
const l = t ? load_lane_of(t) : null;
|
|
299
|
+
if (l) return l.file;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
/** A CALL'S OWN CLOCK, once per call (a call spans several segments): until its headers, then its
|
|
303
|
+
* body; of the headers wait, what the other side's Server-Timing claims. Their entries often
|
|
304
|
+
* nest (`render 30` holding `db 21`), so past the wait itself the largest is their whole. */
|
|
305
|
+
const add_split = (g, c) => {
|
|
306
|
+
if (!is_http(c.label)) return;
|
|
307
|
+
const id = c.label + "\0" + (c.caller ?? "") + "\0" + c.ms;
|
|
308
|
+
if ((g.split_seen ??= /* @__PURE__ */ new Set()).has(id)) return;
|
|
309
|
+
g.split_seen.add(id);
|
|
310
|
+
const body = Math.min(c.body_ms ?? 0, c.ms);
|
|
311
|
+
const headers = c.ms - body;
|
|
312
|
+
const sp = g.split ??= {
|
|
313
|
+
network_ms: 0,
|
|
314
|
+
body_ms: 0,
|
|
315
|
+
calls: 0
|
|
316
|
+
};
|
|
317
|
+
sp.calls++;
|
|
318
|
+
sp.body_ms += body;
|
|
319
|
+
const t = c.timings?.filter((x) => x.ms > 0) ?? [];
|
|
320
|
+
if (t.length) {
|
|
321
|
+
const sum = t.reduce((s, x) => s + x.ms, 0);
|
|
322
|
+
const largest = Math.max(...t.map((x) => x.ms));
|
|
323
|
+
const theirs = Math.min(headers, sum > headers ? largest : sum);
|
|
324
|
+
sp.theirs_ms = (sp.theirs_ms ?? 0) + theirs;
|
|
325
|
+
sp.told = (sp.told ?? 0) + 1;
|
|
326
|
+
sp.network_ms += headers - theirs;
|
|
327
|
+
for (const x of t) (g.told_by ??= /* @__PURE__ */ new Map()).set(x.desc ?? x.name, (g.told_by.get(x.desc ?? x.name) ?? 0) + x.ms);
|
|
328
|
+
} else sp.network_ms += headers;
|
|
329
|
+
};
|
|
330
|
+
for (const s of segs) {
|
|
331
|
+
const len = s.t1 - s.t0;
|
|
332
|
+
const ph = phases.get(s.phase) ?? phases.set(s.phase, /* @__PURE__ */ new Map()).get(s.phase);
|
|
333
|
+
const in_load = s.phase === "load";
|
|
334
|
+
if (s.kind === "wait" && s.calls?.length) {
|
|
335
|
+
const each = len / s.calls.length;
|
|
336
|
+
const keyed = s.calls.map((c) => {
|
|
337
|
+
const lane = in_load ? lane_of([...c.callers ?? [], c.caller]) : void 0;
|
|
338
|
+
return {
|
|
339
|
+
c,
|
|
340
|
+
lane,
|
|
341
|
+
key: "w\0" + call_group(c.label) + "\0" + (lane ?? "")
|
|
342
|
+
};
|
|
343
|
+
});
|
|
344
|
+
const alone = keyed.every((k) => k.key === keyed[0].key);
|
|
345
|
+
for (const { c, lane, key } of keyed) {
|
|
346
|
+
const g = ph.get(key) ?? ph.set(key, {
|
|
347
|
+
node: {
|
|
348
|
+
label: call_group(c.label),
|
|
349
|
+
ms: 0,
|
|
350
|
+
kind: "wait",
|
|
351
|
+
calls: 0,
|
|
352
|
+
alone: 0
|
|
353
|
+
},
|
|
354
|
+
callers: /* @__PURE__ */ new Map(),
|
|
355
|
+
...lane ? { lane } : {}
|
|
356
|
+
}).get(key);
|
|
357
|
+
g.node.ms += each;
|
|
358
|
+
if (alone) g.node.alone += each;
|
|
359
|
+
add_split(g, c);
|
|
360
|
+
if (c.caller) {
|
|
361
|
+
g.callers.set(c.caller, (g.callers.get(c.caller) ?? 0) + each);
|
|
362
|
+
const outer = outer_of(c.caller, c.callers);
|
|
363
|
+
if (outer) {
|
|
364
|
+
const m = (g.outers ??= /* @__PURE__ */ new Map()).get(c.caller) ?? g.outers.set(c.caller, /* @__PURE__ */ new Map()).get(c.caller);
|
|
365
|
+
m.set(outer, (m.get(outer) ?? 0) + each);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const label = s.kind === "cpu" ? owner_group(s) : s.label;
|
|
372
|
+
const file = s.kind === "gap" ? pending_place(s.pending) : s.file;
|
|
373
|
+
const lane = in_load ? s.lane ?? lane_of([file]) : void 0;
|
|
374
|
+
const key = s.kind[0] + "\0" + label + "\0" + (lane ?? "");
|
|
375
|
+
const g = ph.get(key) ?? ph.set(key, {
|
|
376
|
+
node: {
|
|
377
|
+
label,
|
|
378
|
+
ms: 0,
|
|
379
|
+
kind: s.kind
|
|
380
|
+
},
|
|
381
|
+
...file ? { file } : {},
|
|
382
|
+
callers: /* @__PURE__ */ new Map(),
|
|
383
|
+
lib: s.kind === "cpu" && s.category === "dependency",
|
|
384
|
+
...lane ? { lane } : {}
|
|
385
|
+
}).get(key);
|
|
386
|
+
g.node.ms += len;
|
|
387
|
+
if (label !== s.label) {
|
|
388
|
+
const fn = sub_fn(s.label);
|
|
389
|
+
const f = (g.fns ??= /* @__PURE__ */ new Map()).get(fn) ?? g.fns.set(fn, {
|
|
390
|
+
ms: 0,
|
|
391
|
+
...s.file ? { file: s.file } : {}
|
|
392
|
+
}).get(fn);
|
|
393
|
+
f.ms += len;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const seen = /* @__PURE__ */ new Map();
|
|
397
|
+
for (const s of segs) for (const c of s.calls ?? []) {
|
|
398
|
+
const lane = s.phase === "load" ? lane_of([...c.callers ?? [], c.caller]) : void 0;
|
|
399
|
+
const k = s.phase + "\0" + call_group(c.label) + "\0" + (lane ?? "");
|
|
400
|
+
(seen.get(k) ?? seen.set(k, /* @__PURE__ */ new Set()).get(k)).add(c.label + "\0" + (c.caller ?? "") + "\0" + c.ms);
|
|
401
|
+
}
|
|
402
|
+
/** the ledger rows of one function. A function's ledger key is `name /abs/path`, an arrow's
|
|
403
|
+
* `(anonymous) /abs/path:line`, a component's `C:Name` */
|
|
404
|
+
const rows_of = (f) => {
|
|
405
|
+
const own = split_place(f.file);
|
|
406
|
+
const anon = f.name.startsWith("(");
|
|
407
|
+
return ledger.filter((l) => {
|
|
408
|
+
if (!l.fn || l.cpu_ms <= 0) return false;
|
|
409
|
+
if (l.fn === "C:" + f.name) return true;
|
|
410
|
+
const sp = anon ? l.fn.indexOf(") ") + 1 : l.fn.lastIndexOf(" ");
|
|
411
|
+
if (sp <= 0 || l.fn.slice(0, sp) !== f.name) return false;
|
|
412
|
+
const def = anon ? split_place(l.fn.slice(sp + 1)) : {
|
|
413
|
+
parts: split_place(l.fn.slice(sp + 1) + ":").parts,
|
|
414
|
+
line: own.line
|
|
415
|
+
};
|
|
416
|
+
return def.line === own.line && same_file(def.parts, own.parts);
|
|
417
|
+
});
|
|
418
|
+
};
|
|
419
|
+
/** a function's time as its lines' shares: split by its ledger rows, else its own start line */
|
|
420
|
+
const shares_of = (f, weight, into) => {
|
|
421
|
+
const rows = rows_of(f);
|
|
422
|
+
const total = rows.reduce((s, l) => s + l.cpu_ms, 0);
|
|
423
|
+
if (total > 0) for (const l of rows) into.set(`${l.file}:${l.line}`, (into.get(`${l.file}:${l.line}`) ?? 0) + weight * l.cpu_ms / total);
|
|
424
|
+
else into.set(f.file, (into.get(f.file) ?? 0) + weight);
|
|
425
|
+
};
|
|
426
|
+
const lines_of = (fn) => {
|
|
427
|
+
const into = /* @__PURE__ */ new Map();
|
|
428
|
+
const inner = tl.inner?.[fn];
|
|
429
|
+
const inner_total = inner?.reduce((s, f) => s + f.ms, 0) ?? 0;
|
|
430
|
+
if (inner && inner_total > 0) for (const f of inner) shares_of(f, f.ms / inner_total, into);
|
|
431
|
+
else {
|
|
432
|
+
const rows = ledger.filter((l) => l.fn && (l.fn.split(" ")[0] === fn || l.fn === "C:" + fn) && l.cpu_ms > 0);
|
|
433
|
+
const total = rows.reduce((s, l) => s + l.cpu_ms, 0);
|
|
434
|
+
for (const l of rows) into.set(`${l.file}:${l.line}`, (into.get(`${l.file}:${l.line}`) ?? 0) + l.cpu_ms / total);
|
|
435
|
+
}
|
|
436
|
+
return [...into].map(([at, share]) => ({
|
|
437
|
+
at,
|
|
438
|
+
share
|
|
439
|
+
}));
|
|
440
|
+
};
|
|
441
|
+
const callers_of_pkg = (pkg) => {
|
|
442
|
+
const rows = ledger.map((l) => ({
|
|
443
|
+
l,
|
|
444
|
+
ms: (l.libs ?? []).filter((x) => x.pkg === pkg).reduce((s, x) => s + x.ms, 0)
|
|
445
|
+
})).filter((r) => r.ms > 0);
|
|
446
|
+
const total = rows.reduce((s, r) => s + r.ms, 0);
|
|
447
|
+
return total > 0 ? rows.map((r) => ({
|
|
448
|
+
at: `${r.l.file}:${r.l.line}`,
|
|
449
|
+
share: r.ms / total
|
|
450
|
+
})) : [];
|
|
451
|
+
};
|
|
452
|
+
/** `fetchStock (routes/x.ts:25)` → `routes/x.ts:25`: the place, without the function name */
|
|
453
|
+
const place = (caller) => {
|
|
454
|
+
const open = caller.lastIndexOf("(");
|
|
455
|
+
return open !== -1 && caller.endsWith(")") ? caller.slice(open + 1, -1) : caller;
|
|
456
|
+
};
|
|
457
|
+
const phase_nodes = [];
|
|
458
|
+
for (const [phase, groups] of phases) {
|
|
459
|
+
const kids = [];
|
|
460
|
+
const lane_kids = /* @__PURE__ */ new Map();
|
|
461
|
+
for (const [key, g] of groups) {
|
|
462
|
+
const n = g.node;
|
|
463
|
+
n.ms = r2(n.ms);
|
|
464
|
+
if (n.alone !== void 0) n.alone = r2(n.alone);
|
|
465
|
+
if (n.kind === "wait") {
|
|
466
|
+
n.calls = seen.get(phase + "\0" + n.label + "\0" + (g.lane ?? ""))?.size ?? 0;
|
|
467
|
+
if (g.split) {
|
|
468
|
+
const sp = g.split;
|
|
469
|
+
const top = g.told_by ? [...g.told_by].sort((x, y) => y[1] - x[1]).slice(0, 3).map(([name, ms]) => ({
|
|
470
|
+
name,
|
|
471
|
+
ms: r2(ms)
|
|
472
|
+
})) : void 0;
|
|
473
|
+
n.split = {
|
|
474
|
+
calls: sp.calls,
|
|
475
|
+
...sp.theirs_ms !== void 0 ? {
|
|
476
|
+
theirs_ms: r2(sp.theirs_ms),
|
|
477
|
+
told: sp.told
|
|
478
|
+
} : {},
|
|
479
|
+
network_ms: r2(sp.network_ms),
|
|
480
|
+
body_ms: r2(sp.body_ms),
|
|
481
|
+
...top?.length ? { top } : {}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const callers = [...g.callers].map(([caller, ms]) => {
|
|
485
|
+
const line = {
|
|
486
|
+
label: caller,
|
|
487
|
+
ms: r2(ms),
|
|
488
|
+
kind: "line",
|
|
489
|
+
at: place(caller)
|
|
490
|
+
};
|
|
491
|
+
const outers = g.outers?.get(caller);
|
|
492
|
+
const covered = outers ? [...outers.values()].reduce((s, v) => s + v, 0) : 0;
|
|
493
|
+
if (outers?.size && covered >= ms * .99) line.children = fold([...outers].map(([o, oms]) => ({
|
|
494
|
+
label: o,
|
|
495
|
+
ms: r2(oms),
|
|
496
|
+
kind: "line",
|
|
497
|
+
at: place(o)
|
|
498
|
+
})), line.ms);
|
|
499
|
+
return line;
|
|
500
|
+
});
|
|
501
|
+
if (callers.length) n.children = fold(callers, n.ms);
|
|
502
|
+
} else if (n.kind === "cpu") {
|
|
503
|
+
if (g.file) n.at = g.file;
|
|
504
|
+
const pkg_lines = g.lib ? callers_of_pkg(n.label) : [];
|
|
505
|
+
const gc = n.label === "garbage collection" ? gc_lines : [];
|
|
506
|
+
const lines = gc.length ? gc : pkg_lines.length ? pkg_lines : key.startsWith("c\0") && !g.lib ? lines_of(n.label) : [];
|
|
507
|
+
if (pkg_lines.length) delete n.at;
|
|
508
|
+
if (lines.length > 1) n.children = fold(lines.map((l) => ({
|
|
509
|
+
label: l.at,
|
|
510
|
+
ms: r2(n.ms * l.share),
|
|
511
|
+
kind: "line",
|
|
512
|
+
at: l.at
|
|
513
|
+
})), n.ms);
|
|
514
|
+
else {
|
|
515
|
+
if (lines.length === 1) n.at = lines[0].at;
|
|
516
|
+
if (g.fns && g.fns.size > 1) n.children = fold([...g.fns].map(([fn, f]) => ({
|
|
517
|
+
label: fn,
|
|
518
|
+
ms: r2(f.ms),
|
|
519
|
+
kind: "cpu",
|
|
520
|
+
...f.file ? { at: f.file } : {}
|
|
521
|
+
})), n.ms);
|
|
522
|
+
}
|
|
523
|
+
} else if (n.kind === "gap" && g.file) n.at = g.file;
|
|
524
|
+
if (g.lane) (lane_kids.get(g.lane) ?? lane_kids.set(g.lane, []).get(g.lane)).push(n);
|
|
525
|
+
else kids.push(n);
|
|
526
|
+
}
|
|
527
|
+
for (const [lane, rows] of lane_kids) {
|
|
528
|
+
const ms = r2(rows.reduce((s, k) => s + k.ms, 0));
|
|
529
|
+
kids.push({
|
|
530
|
+
label: lane,
|
|
531
|
+
ms,
|
|
532
|
+
kind: "lane",
|
|
533
|
+
at: lane,
|
|
534
|
+
children: fold(rows, ms)
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
const ms = r2(kids.reduce((s, k) => s + k.ms, 0));
|
|
538
|
+
phase_nodes.push({
|
|
539
|
+
label: PHASE_LABEL[phase] ?? phase,
|
|
540
|
+
ms,
|
|
541
|
+
kind: "phase",
|
|
542
|
+
children: fold(kids, ms)
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const total = r2(phase_nodes.reduce((s, p) => s + p.ms, 0));
|
|
546
|
+
return {
|
|
547
|
+
label: "render",
|
|
548
|
+
ms: total,
|
|
549
|
+
kind: "render",
|
|
550
|
+
children: fold(phase_nodes, total)
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
export { at_line, build_drill, call_group, tag_fills, unread_rows };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE MAPS THE BUILD WROTE INTO THE CODE (vite/profiler-maps.ts), read back: the module map and
|
|
3
|
+
* every server chunk's sourcemap, by chunk file relative to the server output. Loaded once, on the
|
|
4
|
+
* first resolve, from `virtual:ogygia/profiler-maps` — a dynamic import, so it ships with whatever
|
|
5
|
+
* the adapter ships and costs a request nothing. Null outside a profiler-on server build.
|
|
6
|
+
*/
|
|
7
|
+
export interface EmbeddedMaps {
|
|
8
|
+
modules: Record<string, [number, number, string][]>;
|
|
9
|
+
maps: Record<string, string>;
|
|
10
|
+
/** a build without maps: the app's source files by module id (`src/lib/x.ts`) */
|
|
11
|
+
sources?: Record<string, string>;
|
|
12
|
+
/** ...and the text of the chunks they are in, by chunk file */
|
|
13
|
+
chunks?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export declare function load_embedded_maps(): Promise<EmbeddedMaps | null>;
|
|
16
|
+
/** the maps once loaded (synchronous readers: the module map lookup), else null */
|
|
17
|
+
export declare const embedded_maps: () => EmbeddedMaps | null;
|
|
18
|
+
/** a script's key in the payload: its path under the server output (`chunks/format.js`), whether it
|
|
19
|
+
* runs from Kit's output itself (a host that copies it, like Vercel's) or is named as a map source
|
|
20
|
+
* by an adapter that re-bundled it (adapter-node: `…/.svelte-kit/output/server/chunks/x.js`) */
|
|
21
|
+
export declare function embedded_key(path: string): string | undefined;
|
|
22
|
+
/** the build's map of a chunk, by its path: the text the build wrote, or undefined */
|
|
23
|
+
export declare function embedded_map_of(path: string): string | undefined;
|
|
24
|
+
/** a built chunk's text the build carried (a build without maps, for a host that re-bundled it) */
|
|
25
|
+
export declare function embedded_chunk(path: string): string | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* AN APP SOURCE FILE'S TEXT FROM THE MAPS (`sourcesContent`): the only copy on a deployed host, where
|
|
28
|
+
* `src/` is not there. What the source-reading checks (a load read line by line, a component's
|
|
29
|
+
* `{#each}`, a late island's data) read when the file is not on disk. `file` is src-relative or has
|
|
30
|
+
* a leading `src/`; undefined when no map carries it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function embedded_source(file: string): string | undefined;
|
|
33
|
+
/** every app source file the maps carry, src-relative */
|
|
34
|
+
export declare function embedded_files(): string[];
|
|
35
|
+
/** the module at a chunk line, from the embedded module map (a host that dropped the file beside the
|
|
36
|
+
* chunks) */
|
|
37
|
+
export declare function embedded_module_at(path: string, line: number): string | undefined;
|