@ifc-lite/load-trace 0.0.0-stage → 0.1.0
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 +373 -0
- package/README.md +120 -2
- package/dist/call-meter.d.ts +16 -0
- package/dist/call-meter.d.ts.map +1 -0
- package/dist/call-meter.js +50 -0
- package/dist/call-meter.js.map +1 -0
- package/dist/chrome-trace.d.ts +23 -0
- package/dist/chrome-trace.d.ts.map +1 -0
- package/dist/chrome-trace.js +53 -0
- package/dist/chrome-trace.js.map +1 -0
- package/dist/counters.d.ts +34 -0
- package/dist/counters.d.ts.map +1 -0
- package/dist/counters.js +69 -0
- package/dist/counters.js.map +1 -0
- package/dist/frames.d.ts +69 -0
- package/dist/frames.d.ts.map +1 -0
- package/dist/frames.js +85 -0
- package/dist/frames.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/load-trace.d.ts +62 -0
- package/dist/load-trace.d.ts.map +1 -0
- package/dist/load-trace.js +199 -0
- package/dist/load-trace.js.map +1 -0
- package/dist/messages.d.ts +38 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +116 -0
- package/dist/messages.js.map +1 -0
- package/dist/perf-sink.d.ts +15 -0
- package/dist/perf-sink.d.ts.map +1 -0
- package/dist/perf-sink.js +37 -0
- package/dist/perf-sink.js.map +1 -0
- package/dist/tree.d.ts +11 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +25 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/worker-phases.d.ts +39 -0
- package/dist/worker-phases.d.ts.map +1 -0
- package/dist/worker-phases.js +60 -0
- package/dist/worker-phases.js.map +1 -0
- package/dist/worker.d.ts +68 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +112 -0
- package/dist/worker.js.map +1 -0
- package/package.json +46 -3
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural perf counters (#6957): plain named sums (messages, bytes copied,
|
|
3
|
+
* GPU buffers, setState calls, ...) that any package bumps without knowing
|
|
4
|
+
* which load is running. A load trace reads the registry when the load starts
|
|
5
|
+
* and again when it ends, so each load reports the delta (`LoadTraceSnapshot.counters`).
|
|
6
|
+
*
|
|
7
|
+
* OFF until `enable()`: every bump is then one boolean test, so the call sites
|
|
8
|
+
* in hot paths (renderer, store, worker message wrapper) cost nothing
|
|
9
|
+
* measurable in production. The viewer enables it only under `?perfTrace=1`
|
|
10
|
+
* and in benchmark runs.
|
|
11
|
+
*/
|
|
12
|
+
export type CounterValues = Record<string, number>;
|
|
13
|
+
export interface PerfCounterRegistry {
|
|
14
|
+
readonly enabled: boolean;
|
|
15
|
+
enable(): void;
|
|
16
|
+
add(name: string, n?: number): void;
|
|
17
|
+
/** Copy of every counter's running total. */
|
|
18
|
+
read(): CounterValues;
|
|
19
|
+
/** Increments since the previous `drain` (or since enable), or `null` when nothing moved. */
|
|
20
|
+
drain(): CounterValues | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function createPerfCounters(): PerfCounterRegistry;
|
|
23
|
+
export declare const perfCounters: PerfCounterRegistry;
|
|
24
|
+
/** Bump `name` by `n` (default 1) when counters are on. */
|
|
25
|
+
export declare function perfCount(name: string, n?: number): void;
|
|
26
|
+
/** Bump `<name>.count` by one and `<name>.<unit>` by `amount` (e.g. a copy and its bytes). */
|
|
27
|
+
export declare function perfTally(name: string, amount: number, unit?: string): void;
|
|
28
|
+
/** Count a full copy of a buffer as `copy.<kind>` and hand the copy back unchanged. */
|
|
29
|
+
export declare function countCopy<T extends ArrayBufferLike | ArrayBufferView>(kind: string, copy: T): T;
|
|
30
|
+
/** `after - before` per name, dropping zeros (counters only grow). */
|
|
31
|
+
export declare function diffCounters(after: CounterValues, before: CounterValues): CounterValues;
|
|
32
|
+
/** Add `delta` into `into` in place. */
|
|
33
|
+
export declare function addCounters(into: CounterValues, delta: Readonly<CounterValues>): void;
|
|
34
|
+
//# sourceMappingURL=counters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counters.d.ts","sourceRoot":"","sources":["../src/counters.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,MAAM,IAAI,IAAI,CAAC;IACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,6CAA6C;IAC7C,IAAI,IAAI,aAAa,CAAC;IACtB,6FAA6F;IAC7F,KAAK,IAAI,aAAa,GAAG,IAAI,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,CAoBxD;AAUD,eAAO,MAAM,YAAY,EAAE,mBAAkE,CAAC;AAE9F,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,IAAI,CAEnD;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,SAAU,GAAG,IAAI,CAI5E;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAG/F;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,aAAa,CAOvF;AAED,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,IAAI,CAErF"}
|
package/dist/counters.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export function createPerfCounters() {
|
|
5
|
+
const totals = new Map();
|
|
6
|
+
let pending = new Map();
|
|
7
|
+
let enabled = false;
|
|
8
|
+
return {
|
|
9
|
+
get enabled() { return enabled; },
|
|
10
|
+
enable() { enabled = true; },
|
|
11
|
+
add(name, n = 1) {
|
|
12
|
+
if (!enabled)
|
|
13
|
+
return;
|
|
14
|
+
totals.set(name, (totals.get(name) ?? 0) + n);
|
|
15
|
+
pending.set(name, (pending.get(name) ?? 0) + n);
|
|
16
|
+
},
|
|
17
|
+
read: () => Object.fromEntries(totals),
|
|
18
|
+
drain() {
|
|
19
|
+
if (pending.size === 0)
|
|
20
|
+
return null;
|
|
21
|
+
const out = Object.fromEntries(pending);
|
|
22
|
+
pending = new Map();
|
|
23
|
+
return out;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* One registry per JS realm, kept on `globalThis` so two bundled copies of
|
|
29
|
+
* this package (a published package's `dist` plus the app's source) still
|
|
30
|
+
* share it. Each worker has its own realm and therefore its own registry; it
|
|
31
|
+
* reaches the main thread through `createWorkerTraceHost`.
|
|
32
|
+
*/
|
|
33
|
+
const REGISTRY_KEY = Symbol.for('ifc-lite.perf-counters');
|
|
34
|
+
const realm = globalThis;
|
|
35
|
+
export const perfCounters = realm[REGISTRY_KEY] ??= createPerfCounters();
|
|
36
|
+
/** Bump `name` by `n` (default 1) when counters are on. */
|
|
37
|
+
export function perfCount(name, n = 1) {
|
|
38
|
+
if (perfCounters.enabled)
|
|
39
|
+
perfCounters.add(name, n);
|
|
40
|
+
}
|
|
41
|
+
/** Bump `<name>.count` by one and `<name>.<unit>` by `amount` (e.g. a copy and its bytes). */
|
|
42
|
+
export function perfTally(name, amount, unit = 'bytes') {
|
|
43
|
+
if (!perfCounters.enabled)
|
|
44
|
+
return;
|
|
45
|
+
perfCounters.add(`${name}.count`);
|
|
46
|
+
perfCounters.add(`${name}.${unit}`, amount);
|
|
47
|
+
}
|
|
48
|
+
/** Count a full copy of a buffer as `copy.<kind>` and hand the copy back unchanged. */
|
|
49
|
+
export function countCopy(kind, copy) {
|
|
50
|
+
if (perfCounters.enabled)
|
|
51
|
+
perfTally(`copy.${kind}`, copy.byteLength);
|
|
52
|
+
return copy;
|
|
53
|
+
}
|
|
54
|
+
/** `after - before` per name, dropping zeros (counters only grow). */
|
|
55
|
+
export function diffCounters(after, before) {
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const [name, value] of Object.entries(after)) {
|
|
58
|
+
const delta = value - (before[name] ?? 0);
|
|
59
|
+
if (delta !== 0)
|
|
60
|
+
out[name] = delta;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/** Add `delta` into `into` in place. */
|
|
65
|
+
export function addCounters(into, delta) {
|
|
66
|
+
for (const [name, value] of Object.entries(delta))
|
|
67
|
+
into[name] = (into[name] ?? 0) + value;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=counters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counters.js","sourceRoot":"","sources":["../src/counters.ts"],"names":[],"mappings":"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"}
|
package/dist/frames.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { TraceSpan } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Main-thread health (#6957): `long-animation-frame` (LoAF) and `longtask`
|
|
4
|
+
* entries, kept in a bounded log and summarised per load window. Both entry
|
|
5
|
+
* types are feature-detected; an engine without them reports `supported:
|
|
6
|
+
* false` and empty stats rather than zeros that look like a healthy load.
|
|
7
|
+
*/
|
|
8
|
+
export type FrameEntryType = 'loaf' | 'longtask';
|
|
9
|
+
export interface FrameEntry {
|
|
10
|
+
type: FrameEntryType;
|
|
11
|
+
start: number;
|
|
12
|
+
duration: number;
|
|
13
|
+
/** LoAF `blockingDuration`; for a long task, the part over 50 ms. */
|
|
14
|
+
blocking: number;
|
|
15
|
+
}
|
|
16
|
+
export interface FrameMonitor {
|
|
17
|
+
readonly supported: Readonly<Record<FrameEntryType, boolean>>;
|
|
18
|
+
/** Every retained entry, after flushing the observers' undelivered records. */
|
|
19
|
+
entries(): readonly FrameEntry[];
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
22
|
+
export interface FrameStats {
|
|
23
|
+
count: number;
|
|
24
|
+
/** Entries longer than 50 ms (every LoAF is, by definition). */
|
|
25
|
+
over50: number;
|
|
26
|
+
totalMs: number;
|
|
27
|
+
blockingMs: number;
|
|
28
|
+
longestMs: number;
|
|
29
|
+
}
|
|
30
|
+
export interface SpanFrameStats {
|
|
31
|
+
count: number;
|
|
32
|
+
blockingMs: number;
|
|
33
|
+
durationMs: number;
|
|
34
|
+
}
|
|
35
|
+
export interface FrameSummary {
|
|
36
|
+
supported: Record<FrameEntryType, boolean>;
|
|
37
|
+
loaf: FrameStats;
|
|
38
|
+
longtask: FrameStats;
|
|
39
|
+
/**
|
|
40
|
+
* LoAF blocking time by the innermost main-thread span open at the frame's
|
|
41
|
+
* start (`load` when none is). Long tasks fall back here when LoAF is absent.
|
|
42
|
+
*/
|
|
43
|
+
bySpan: Record<string, SpanFrameStats>;
|
|
44
|
+
}
|
|
45
|
+
interface ObserverEntry {
|
|
46
|
+
startTime: number;
|
|
47
|
+
duration: number;
|
|
48
|
+
blockingDuration?: number;
|
|
49
|
+
}
|
|
50
|
+
interface ObserverLike {
|
|
51
|
+
observe(options: {
|
|
52
|
+
type: string;
|
|
53
|
+
buffered?: boolean;
|
|
54
|
+
}): void;
|
|
55
|
+
takeRecords(): Array<ObserverEntry>;
|
|
56
|
+
disconnect(): void;
|
|
57
|
+
}
|
|
58
|
+
export interface ObserverCtor {
|
|
59
|
+
new (cb: (list: {
|
|
60
|
+
getEntries(): ObserverEntry[];
|
|
61
|
+
}) => void): ObserverLike;
|
|
62
|
+
readonly supportedEntryTypes?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
/** Start observing both entry types; `max` bounds the log (oldest dropped). */
|
|
65
|
+
export declare function startFrameMonitor(Observer?: ObserverCtor | undefined, max?: number): FrameMonitor;
|
|
66
|
+
/** Summarise the entries that START inside `[start, end)`, attributing each to a span of `spans`. */
|
|
67
|
+
export declare function summarizeFrames(entries: readonly FrameEntry[], supported: Readonly<Record<FrameEntryType, boolean>>, start: number, end: number, spans: readonly TraceSpan[]): FrameSummary;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../src/frames.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9D,+EAA+E;IAC/E,OAAO,IAAI,SAAS,UAAU,EAAE,CAAC;IACjC,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAEzF,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACxC;AAID,UAAU,aAAa;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE;AAC1F,UAAU,YAAY;IACpB,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7D,WAAW,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;IACpC,UAAU,IAAI,IAAI,CAAC;CACpB;AACD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE;QAAE,UAAU,IAAI,aAAa,EAAE,CAAA;KAAE,KAAK,IAAI,GAAG,YAAY,CAAC;IAC1E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAID,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,YAAY,GAAG,SAAsF,EAC/G,GAAG,SAAS,GACX,YAAY,CA8Bd;AAKD,qGAAqG;AACrG,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,EACpD,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,SAAS,EAAE,GAC1B,YAAY,CA6Bd"}
|
package/dist/frames.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
const LONG_TASK_MS = 50;
|
|
5
|
+
const ENTRY_TYPES = [['loaf', 'long-animation-frame'], ['longtask', 'longtask']];
|
|
6
|
+
/** Start observing both entry types; `max` bounds the log (oldest dropped). */
|
|
7
|
+
export function startFrameMonitor(Observer = globalThis.PerformanceObserver, max = 20_000) {
|
|
8
|
+
const log = [];
|
|
9
|
+
const observers = [];
|
|
10
|
+
const supported = { loaf: false, longtask: false };
|
|
11
|
+
const push = (type, list) => {
|
|
12
|
+
for (const e of list) {
|
|
13
|
+
const blocking = type === 'loaf' ? (e.blockingDuration ?? 0) : Math.max(0, e.duration - LONG_TASK_MS);
|
|
14
|
+
log.push({ type, start: e.startTime, duration: e.duration, blocking });
|
|
15
|
+
}
|
|
16
|
+
if (log.length > max)
|
|
17
|
+
log.splice(0, log.length - max);
|
|
18
|
+
};
|
|
19
|
+
for (const [type, entryType] of ENTRY_TYPES) {
|
|
20
|
+
if (!Observer?.supportedEntryTypes?.includes(entryType))
|
|
21
|
+
continue;
|
|
22
|
+
try {
|
|
23
|
+
const observer = new Observer((list) => push(type, list.getEntries()));
|
|
24
|
+
observer.observe({ type: entryType, buffered: true });
|
|
25
|
+
observers.push([type, observer]);
|
|
26
|
+
supported[type] = true;
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.warn(`[load-trace] could not observe ${entryType}; it is reported as unsupported`, err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
supported,
|
|
34
|
+
entries() {
|
|
35
|
+
for (const [type, o] of observers)
|
|
36
|
+
push(type, o.takeRecords());
|
|
37
|
+
return log;
|
|
38
|
+
},
|
|
39
|
+
stop() { for (const [, o] of observers)
|
|
40
|
+
o.disconnect(); },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const emptyStats = () => ({ count: 0, over50: 0, totalMs: 0, blockingMs: 0, longestMs: 0 });
|
|
44
|
+
const round = (ms) => Math.round(ms * 10) / 10;
|
|
45
|
+
/** Summarise the entries that START inside `[start, end)`, attributing each to a span of `spans`. */
|
|
46
|
+
export function summarizeFrames(entries, supported, start, end, spans) {
|
|
47
|
+
const stats = { loaf: emptyStats(), longtask: emptyStats() };
|
|
48
|
+
const bySpan = {};
|
|
49
|
+
const attributeType = supported.loaf ? 'loaf' : 'longtask';
|
|
50
|
+
const owners = spans.filter((s) => s.thread === 'main' && !s.milestone);
|
|
51
|
+
for (const e of entries) {
|
|
52
|
+
if (e.start < start || e.start >= end)
|
|
53
|
+
continue;
|
|
54
|
+
const s = stats[e.type];
|
|
55
|
+
s.count++;
|
|
56
|
+
if (e.duration > LONG_TASK_MS)
|
|
57
|
+
s.over50++;
|
|
58
|
+
s.totalMs += e.duration;
|
|
59
|
+
s.blockingMs += e.blocking;
|
|
60
|
+
s.longestMs = Math.max(s.longestMs, e.duration);
|
|
61
|
+
if (e.type !== attributeType)
|
|
62
|
+
continue;
|
|
63
|
+
// Innermost = the latest-starting span still open at the frame's start.
|
|
64
|
+
let owner;
|
|
65
|
+
for (const span of owners) {
|
|
66
|
+
if (span.start <= e.start && (span.end === null || span.end > e.start) && (!owner || span.start >= owner.start))
|
|
67
|
+
owner = span;
|
|
68
|
+
}
|
|
69
|
+
const slot = (bySpan[owner?.name ?? 'load'] ??= { count: 0, blockingMs: 0, durationMs: 0 });
|
|
70
|
+
slot.count++;
|
|
71
|
+
slot.blockingMs += e.blocking;
|
|
72
|
+
slot.durationMs += e.duration;
|
|
73
|
+
}
|
|
74
|
+
for (const s of [stats.loaf, stats.longtask]) {
|
|
75
|
+
s.totalMs = round(s.totalMs);
|
|
76
|
+
s.blockingMs = round(s.blockingMs);
|
|
77
|
+
s.longestMs = round(s.longestMs);
|
|
78
|
+
}
|
|
79
|
+
for (const slot of Object.values(bySpan)) {
|
|
80
|
+
slot.blockingMs = round(slot.blockingMs);
|
|
81
|
+
slot.durationMs = round(slot.durationMs);
|
|
82
|
+
}
|
|
83
|
+
return { supported: { ...supported }, ...stats, bySpan };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../src/frames.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createLoadTracer, NOOP_LOAD_TRACE, type LoadTrace, type LoadTracer, type LoadTracerOptions, } from './load-trace.js';
|
|
2
|
+
export type { PerfSink } from './perf-sink.js';
|
|
3
|
+
export { createWorkerTraceHost, enableWorkerTrace, isTraceSpansMessage, type TraceSpansMessage, type WorkerTraceHost, type WorkerTraceHostOptions, } from './worker.js';
|
|
4
|
+
export { createWorkerPhaseTrace, type WorkerPhaseTrace } from './worker-phases.js';
|
|
5
|
+
export { toChromeTrace, type ChromeTrace, type ChromeTraceEvent } from './chrome-trace.js';
|
|
6
|
+
export { buildSpanTree, type SpanTreeNode } from './tree.js';
|
|
7
|
+
export type { LoadTraceAttributes, LoadTraceSnapshot, TraceAttrs, TraceAttrValue, TraceSpan, WorkerSpan, WorkerTracePayload, } from './types.js';
|
|
8
|
+
export { addCounters, countCopy, createPerfCounters, diffCounters, perfCount, perfCounters, perfTally, type CounterValues, type PerfCounterRegistry, } from './counters.js';
|
|
9
|
+
export { startFrameMonitor, summarizeFrames, type FrameEntry, type FrameEntryType, type FrameMonitor, type FrameStats, type FrameSummary, type ObserverCtor, type SpanFrameStats, } from './frames.js';
|
|
10
|
+
export { accountWorkerMessages, estimateCloneBytes, type CloneEstimate, type MessageEndpoint } from './messages.js';
|
|
11
|
+
export { meterTypedArrayArgs } from './call-meter.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE7D,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,EACV,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACpH,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export { createLoadTracer, NOOP_LOAD_TRACE, } from './load-trace.js';
|
|
5
|
+
export { createWorkerTraceHost, enableWorkerTrace, isTraceSpansMessage, } from './worker.js';
|
|
6
|
+
export { createWorkerPhaseTrace } from './worker-phases.js';
|
|
7
|
+
export { toChromeTrace } from './chrome-trace.js';
|
|
8
|
+
export { buildSpanTree } from './tree.js';
|
|
9
|
+
export { addCounters, countCopy, createPerfCounters, diffCounters, perfCount, perfCounters, perfTally, } from './counters.js';
|
|
10
|
+
export { startFrameMonitor, summarizeFrames, } from './frames.js';
|
|
11
|
+
export { accountWorkerMessages, estimateCloneBytes } from './messages.js';
|
|
12
|
+
export { meterTypedArrayArgs } from './call-meter.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EACL,gBAAgB,EAChB,eAAe,GAIhB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GAIpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,sBAAsB,EAAyB,MAAM,oBAAoB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAA2C,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAqB,MAAM,WAAW,CAAC;AAY7D,OAAO,EACL,WAAW,EACX,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,GAGV,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,eAAe,GAQhB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAA4C,MAAM,eAAe,CAAC;AACpH,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type PerfCounterRegistry } from './counters.js';
|
|
2
|
+
import { type FrameMonitor } from './frames.js';
|
|
3
|
+
import { type PerfSink } from './perf-sink.js';
|
|
4
|
+
import type { LoadTraceAttributes, LoadTraceSnapshot, TraceAttrs, WorkerTracePayload } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* One load's trace. Every method is safe to call when tracing is OFF: the
|
|
7
|
+
* disabled implementation keeps only the start time (so `milestone`/`finish`
|
|
8
|
+
* still return elapsed ms) and every other call is an empty function, so an
|
|
9
|
+
* instrumented call site costs one monomorphic no-op call and no allocation.
|
|
10
|
+
*/
|
|
11
|
+
export interface LoadTrace {
|
|
12
|
+
readonly enabled: boolean;
|
|
13
|
+
readonly loadId: string;
|
|
14
|
+
/** Load start on the main `performance.now()` clock. */
|
|
15
|
+
readonly start: number;
|
|
16
|
+
setAttrs(attrs: LoadTraceAttributes): void;
|
|
17
|
+
/** Open a span; returns a token for `end` (`-1` when disabled). */
|
|
18
|
+
begin(name: string, attrs?: TraceAttrs, parent?: number): number;
|
|
19
|
+
end(token: number, attrs?: TraceAttrs): void;
|
|
20
|
+
/** Time `fn`; a returned promise ends the span when it settles. Returns `fn`'s result unchanged. */
|
|
21
|
+
span<T>(name: string, fn: () => T, attrs?: TraceAttrs, parent?: number): T;
|
|
22
|
+
/** Record an interval the caller already measured. */
|
|
23
|
+
record(name: string, start: number, end: number, attrs?: TraceAttrs, parent?: number): void;
|
|
24
|
+
/**
|
|
25
|
+
* Mark a milestone `atMs` after the load start (default: now). The span runs
|
|
26
|
+
* from the load start, so its measure duration IS the time-to-milestone. The
|
|
27
|
+
* first call per name is recorded; every call returns the elapsed ms.
|
|
28
|
+
*/
|
|
29
|
+
milestone(name: string, atMs?: number | null): number;
|
|
30
|
+
/** Fold a worker's spans onto this timeline (clock-aligned via `timeOrigin`). */
|
|
31
|
+
merge(payload: WorkerTracePayload, parent?: number): void;
|
|
32
|
+
/** End the load root (first call wins); returns elapsed ms since the start. */
|
|
33
|
+
finish(attrs?: LoadTraceAttributes): number;
|
|
34
|
+
snapshot(): LoadTraceSnapshot | null;
|
|
35
|
+
}
|
|
36
|
+
export interface LoadTracerOptions {
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
now?: () => number;
|
|
39
|
+
timeOrigin?: number;
|
|
40
|
+
/** `null` disables the User Timing mirror (the span tree is still kept). */
|
|
41
|
+
sink?: PerfSink | null;
|
|
42
|
+
/** Most recent loads retained; older ones are dropped. Default 16. */
|
|
43
|
+
maxLoads?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Structural counters attributed to each load (#6957). Defaults to the
|
|
46
|
+
* realm-wide `perfCounters`, which an enabled tracer switches on; `null`
|
|
47
|
+
* records none.
|
|
48
|
+
*/
|
|
49
|
+
counters?: PerfCounterRegistry | null;
|
|
50
|
+
/** Long-frame log summarised per load (#6957); omitted = no `mainThread`. */
|
|
51
|
+
frames?: FrameMonitor | null;
|
|
52
|
+
}
|
|
53
|
+
export interface LoadTracer {
|
|
54
|
+
readonly enabled: boolean;
|
|
55
|
+
startLoad(loadId: string, attrs?: LoadTraceAttributes, start?: number): LoadTrace;
|
|
56
|
+
snapshots(): LoadTraceSnapshot[];
|
|
57
|
+
latest(): LoadTraceSnapshot | null;
|
|
58
|
+
}
|
|
59
|
+
export declare function createLoadTracer(options: LoadTracerOptions): LoadTracer;
|
|
60
|
+
/** A disabled trace with no clock of its own, for callers given no trace at all. */
|
|
61
|
+
export declare const NOOP_LOAD_TRACE: LoadTrace;
|
|
62
|
+
//# sourceMappingURL=load-trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-trace.d.ts","sourceRoot":"","sources":["../src/load-trace.ts"],"names":[],"mappings":"AAIA,OAAO,EAA+D,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACtH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EAEV,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC3C,mEAAmE;IACnE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7C,oGAAoG;IACpG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IAC3E,sDAAsD;IACtD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5F;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;IACtD,iFAAiF;IACjF,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1D,+EAA+E;IAC/E,MAAM,CAAC,KAAK,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAC5C,QAAQ,IAAI,iBAAiB,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACtC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClF,SAAS,IAAI,iBAAiB,EAAE,CAAC;IACjC,MAAM,IAAI,iBAAiB,GAAG,IAAI,CAAC;CACpC;AAqKD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAuBvE;AAED,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,SAAqD,CAAC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { addCounters, diffCounters, perfCounters } from './counters.js';
|
|
5
|
+
import { summarizeFrames } from './frames.js';
|
|
6
|
+
import { createPerfSink, MEASURE_PREFIX } from './perf-sink.js';
|
|
7
|
+
const defaultNow = () => globalThis.performance?.now() ?? Date.now();
|
|
8
|
+
const defaultTimeOrigin = () => globalThis.performance?.timeOrigin ?? 0;
|
|
9
|
+
class DisabledLoadTrace {
|
|
10
|
+
loadId;
|
|
11
|
+
start;
|
|
12
|
+
now;
|
|
13
|
+
enabled = false;
|
|
14
|
+
constructor(loadId, start, now) {
|
|
15
|
+
this.loadId = loadId;
|
|
16
|
+
this.start = start;
|
|
17
|
+
this.now = now;
|
|
18
|
+
}
|
|
19
|
+
setAttrs() { }
|
|
20
|
+
begin() { return -1; }
|
|
21
|
+
end() { }
|
|
22
|
+
span(_name, fn) { return fn(); }
|
|
23
|
+
record() { }
|
|
24
|
+
milestone(_name, atMs) { return atMs ?? this.now() - this.start; }
|
|
25
|
+
merge() { }
|
|
26
|
+
finish() { return this.now() - this.start; }
|
|
27
|
+
snapshot() { return null; }
|
|
28
|
+
}
|
|
29
|
+
class RecordingLoadTrace {
|
|
30
|
+
loadId;
|
|
31
|
+
start;
|
|
32
|
+
now;
|
|
33
|
+
timeOrigin;
|
|
34
|
+
sink;
|
|
35
|
+
counters;
|
|
36
|
+
frames;
|
|
37
|
+
enabled = true;
|
|
38
|
+
spans = [];
|
|
39
|
+
milestones = new Set();
|
|
40
|
+
attrs;
|
|
41
|
+
end_ = null;
|
|
42
|
+
counterBase;
|
|
43
|
+
counterEnd = null;
|
|
44
|
+
windowEnd = null;
|
|
45
|
+
workerCounters = {};
|
|
46
|
+
constructor(loadId, start, attrs, now, timeOrigin, sink, counters = null, frames = null) {
|
|
47
|
+
this.loadId = loadId;
|
|
48
|
+
this.start = start;
|
|
49
|
+
this.now = now;
|
|
50
|
+
this.timeOrigin = timeOrigin;
|
|
51
|
+
this.sink = sink;
|
|
52
|
+
this.counters = counters;
|
|
53
|
+
this.frames = frames;
|
|
54
|
+
this.attrs = { ...attrs };
|
|
55
|
+
this.counterBase = counters?.read() ?? null;
|
|
56
|
+
}
|
|
57
|
+
/** A newer load started: freeze this load's counter and frame window. */
|
|
58
|
+
closeWindow(at) {
|
|
59
|
+
if (this.windowEnd !== null)
|
|
60
|
+
return;
|
|
61
|
+
this.windowEnd = at;
|
|
62
|
+
this.counterEnd = this.counters?.read() ?? null;
|
|
63
|
+
}
|
|
64
|
+
setAttrs(attrs) {
|
|
65
|
+
Object.assign(this.attrs, attrs);
|
|
66
|
+
}
|
|
67
|
+
begin(name, attrs, parent) {
|
|
68
|
+
return this.push(name, 'main', this.now(), null, attrs, parent);
|
|
69
|
+
}
|
|
70
|
+
end(token, attrs) {
|
|
71
|
+
const span = this.spans[token];
|
|
72
|
+
if (!span || span.end !== null)
|
|
73
|
+
return;
|
|
74
|
+
span.end = this.now();
|
|
75
|
+
if (attrs)
|
|
76
|
+
span.attrs = { ...span.attrs, ...attrs };
|
|
77
|
+
this.emit(span);
|
|
78
|
+
}
|
|
79
|
+
span(name, fn, attrs, parent) {
|
|
80
|
+
const token = this.begin(name, attrs, parent);
|
|
81
|
+
let result;
|
|
82
|
+
try {
|
|
83
|
+
result = fn();
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
this.end(token, { error: true });
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
if (isThenable(result)) {
|
|
90
|
+
// The derived promise only observes settlement; the caller still owns
|
|
91
|
+
// (and handles) the original promise returned below.
|
|
92
|
+
result.then(() => this.end(token), () => this.end(token, { error: true }));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.end(token);
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
record(name, start, end, attrs, parent) {
|
|
100
|
+
this.emit(this.spans[this.push(name, 'main', start, end, attrs, parent)]);
|
|
101
|
+
}
|
|
102
|
+
milestone(name, atMs) {
|
|
103
|
+
const at = atMs ?? this.now() - this.start;
|
|
104
|
+
if (!this.milestones.has(name)) {
|
|
105
|
+
this.milestones.add(name);
|
|
106
|
+
const span = this.spans[this.push(name, 'main', this.start, this.start + at)];
|
|
107
|
+
span.milestone = true;
|
|
108
|
+
this.emit(span);
|
|
109
|
+
}
|
|
110
|
+
return at;
|
|
111
|
+
}
|
|
112
|
+
merge(payload, parent) {
|
|
113
|
+
if (payload.counters)
|
|
114
|
+
addCounters(this.workerCounters[payload.thread] ??= {}, payload.counters);
|
|
115
|
+
const shift = payload.timeOrigin - this.timeOrigin;
|
|
116
|
+
for (const s of payload.spans) {
|
|
117
|
+
this.emit(this.spans[this.push(s.name, payload.thread, s.start + shift, s.end + shift, s.attrs, parent)]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
finish(attrs) {
|
|
121
|
+
if (this.end_ === null) {
|
|
122
|
+
this.end_ = this.now();
|
|
123
|
+
if (attrs)
|
|
124
|
+
this.setAttrs(attrs);
|
|
125
|
+
this.sink?.measure(`${MEASURE_PREFIX}load`, this.start, this.end_, { loadId: this.loadId });
|
|
126
|
+
}
|
|
127
|
+
return this.end_ - this.start;
|
|
128
|
+
}
|
|
129
|
+
snapshot() {
|
|
130
|
+
return {
|
|
131
|
+
loadId: this.loadId,
|
|
132
|
+
attrs: { ...this.attrs },
|
|
133
|
+
timeOrigin: this.timeOrigin,
|
|
134
|
+
start: this.start,
|
|
135
|
+
end: this.end_,
|
|
136
|
+
spans: this.spans.map((s) => ({ ...s, ...(s.attrs ? { attrs: { ...s.attrs } } : {}) })),
|
|
137
|
+
...this.counterSnapshot(),
|
|
138
|
+
...(this.frames
|
|
139
|
+
? { mainThread: summarizeFrames(this.frames.entries(), this.frames.supported, this.start, this.windowEnd ?? this.now(), this.spans) }
|
|
140
|
+
: {}),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
counterSnapshot() {
|
|
144
|
+
if (!this.counters || !this.counterBase)
|
|
145
|
+
return {};
|
|
146
|
+
const counters = diffCounters(this.counterEnd ?? this.counters.read(), this.counterBase);
|
|
147
|
+
const workerCounters = {};
|
|
148
|
+
for (const [thread, values] of Object.entries(this.workerCounters)) {
|
|
149
|
+
workerCounters[thread] = { ...values };
|
|
150
|
+
addCounters(counters, values);
|
|
151
|
+
}
|
|
152
|
+
return { counters, workerCounters };
|
|
153
|
+
}
|
|
154
|
+
push(name, thread, start, end, attrs, parent) {
|
|
155
|
+
const id = this.spans.length;
|
|
156
|
+
const parentId = parent !== undefined && parent >= 0 && parent < id ? parent : null;
|
|
157
|
+
this.spans.push({ id, name, thread, start, end, parentId, ...(attrs ? { attrs: { ...attrs } } : {}) });
|
|
158
|
+
return id;
|
|
159
|
+
}
|
|
160
|
+
emit(span) {
|
|
161
|
+
if (span.end === null || !this.sink)
|
|
162
|
+
return;
|
|
163
|
+
this.sink.measure(`${MEASURE_PREFIX}${span.name}`, span.start, span.end, {
|
|
164
|
+
loadId: this.loadId, thread: span.thread, ...span.attrs,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function isThenable(value) {
|
|
169
|
+
return typeof value === 'object' && value !== null && typeof value.then === 'function';
|
|
170
|
+
}
|
|
171
|
+
export function createLoadTracer(options) {
|
|
172
|
+
const now = options.now ?? defaultNow;
|
|
173
|
+
const maxLoads = Math.max(1, options.maxLoads ?? 16);
|
|
174
|
+
const enabled = options.enabled;
|
|
175
|
+
const timeOrigin = options.timeOrigin ?? defaultTimeOrigin();
|
|
176
|
+
const sink = options.sink === undefined ? (enabled ? createPerfSink() : null) : options.sink;
|
|
177
|
+
const counters = enabled ? (options.counters === undefined ? perfCounters : options.counters) : null;
|
|
178
|
+
counters?.enable();
|
|
179
|
+
const frames = enabled ? options.frames ?? null : null;
|
|
180
|
+
const loads = [];
|
|
181
|
+
return {
|
|
182
|
+
enabled,
|
|
183
|
+
startLoad(loadId, attrs = {}, start = now()) {
|
|
184
|
+
if (!enabled)
|
|
185
|
+
return new DisabledLoadTrace(loadId, start, now);
|
|
186
|
+
loads[loads.length - 1]?.closeWindow(start);
|
|
187
|
+
const trace = new RecordingLoadTrace(loadId, start, attrs, now, timeOrigin, sink, counters, frames);
|
|
188
|
+
loads.push(trace);
|
|
189
|
+
if (loads.length > maxLoads)
|
|
190
|
+
loads.splice(0, loads.length - maxLoads);
|
|
191
|
+
return trace;
|
|
192
|
+
},
|
|
193
|
+
snapshots: () => loads.map((l) => l.snapshot()),
|
|
194
|
+
latest: () => loads[loads.length - 1]?.snapshot() ?? null,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/** A disabled trace with no clock of its own, for callers given no trace at all. */
|
|
198
|
+
export const NOOP_LOAD_TRACE = new DisabledLoadTrace('noop', 0, () => 0);
|
|
199
|
+
//# sourceMappingURL=load-trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-trace.js","sourceRoot":"","sources":["../src/load-trace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type PerfCounterRegistry } from './counters.js';
|
|
2
|
+
/**
|
|
3
|
+
* Worker message accounting (#6957): the ONE wrapper every loader worker
|
|
4
|
+
* boundary goes through. It patches the worker's `postMessage` (main -> worker,
|
|
5
|
+
* `out`) and listens for its messages (worker -> main, `in`), adding per label:
|
|
6
|
+
*
|
|
7
|
+
* msg.<label>.<dir>.count messages
|
|
8
|
+
* msg.<label>.<dir>.cloneBytes estimated structured-clone payload
|
|
9
|
+
* msg.<label>.out.transferBytes ArrayBuffers in the transfer list (moved, not copied)
|
|
10
|
+
* msg.<label>.in.bufferBytes ArrayBuffers received: the receiver cannot
|
|
11
|
+
* tell a transferred buffer from a cloned one
|
|
12
|
+
* msg.<label>.<dir>.sharedBytes SharedArrayBuffers (shared, never copied)
|
|
13
|
+
*
|
|
14
|
+
* With counters off at wrap time it returns the worker untouched, so the
|
|
15
|
+
* production path keeps the native `postMessage`. Load-trace control messages
|
|
16
|
+
* are not counted (they exist only while tracing).
|
|
17
|
+
*/
|
|
18
|
+
export interface MessageEndpoint {
|
|
19
|
+
postMessage(message: unknown, transfer?: unknown): void;
|
|
20
|
+
/** Absent on a bare port double: then only the outbound side is counted. */
|
|
21
|
+
addEventListener?(type: 'message', listener: (event: {
|
|
22
|
+
data: unknown;
|
|
23
|
+
}) => void): void;
|
|
24
|
+
}
|
|
25
|
+
export interface CloneEstimate {
|
|
26
|
+
cloneBytes: number;
|
|
27
|
+
transferBytes: number;
|
|
28
|
+
sharedBytes: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Estimate what structured clone serialises for `value`. Typed-array views
|
|
32
|
+
* count their WHOLE backing buffer once (clone copies the buffer, not the
|
|
33
|
+
* view's window); strings count one byte per code unit; numbers 8. Iterative,
|
|
34
|
+
* so a deep payload cannot overflow the stack.
|
|
35
|
+
*/
|
|
36
|
+
export declare function estimateCloneBytes(value: unknown, transferred?: (buffer: ArrayBuffer) => boolean): CloneEstimate;
|
|
37
|
+
export declare function accountWorkerMessages<W extends MessageEndpoint>(worker: W, label: string | (() => string), registry?: PerfCounterRegistry): W;
|
|
38
|
+
//# sourceMappingURL=messages.d.ts.map
|