@buoy-gg/js-top 7.0.41 → 7.0.42
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/README.md +12 -71
- package/lib/commonjs/index.js +1 -99
- package/lib/commonjs/js-top/components/BusySparkline.js +1 -56
- package/lib/commonjs/js-top/components/JsTopHudOverlay.js +1 -79
- package/lib/commonjs/js-top/components/JsTopModal.js +1 -349
- package/lib/commonjs/js-top/components/TaskDetailView.js +1 -330
- package/lib/commonjs/js-top/components/TaskTable.js +1 -360
- package/lib/commonjs/js-top/engine/JsTopController.js +1 -350
- package/lib/commonjs/js-top/engine/aggregator.js +1 -148
- package/lib/commonjs/js-top/engine/busyProbe.js +1 -101
- package/lib/commonjs/js-top/engine/frameStack.js +1 -133
- package/lib/commonjs/js-top/engine/longtasks.js +1 -141
- package/lib/commonjs/js-top/engine/now.js +1 -38
- package/lib/commonjs/js-top/engine/originRegistry.js +1 -402
- package/lib/commonjs/js-top/engine/patches/bridge.js +1 -60
- package/lib/commonjs/js-top/engine/patches/microtasks.js +1 -27
- package/lib/commonjs/js-top/engine/patches/promises.js +1 -65
- package/lib/commonjs/js-top/engine/patches/timers.js +1 -66
- package/lib/commonjs/js-top/engine/state.js +1 -63
- package/lib/commonjs/js-top/engine/symbolicate.js +1 -95
- package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js +1 -74
- package/lib/commonjs/js-top/types/index.js +1 -46
- package/lib/commonjs/js-top/utils/preferences.js +1 -31
- package/lib/commonjs/preset.js +1 -75
- package/lib/module/index.js +1 -49
- package/lib/module/js-top/components/BusySparkline.js +1 -52
- package/lib/module/js-top/components/JsTopHudOverlay.js +1 -75
- package/lib/module/js-top/components/JsTopModal.js +1 -345
- package/lib/module/js-top/components/TaskDetailView.js +1 -326
- package/lib/module/js-top/components/TaskTable.js +1 -353
- package/lib/module/js-top/engine/JsTopController.js +1 -347
- package/lib/module/js-top/engine/aggregator.js +1 -136
- package/lib/module/js-top/engine/busyProbe.js +1 -94
- package/lib/module/js-top/engine/frameStack.js +1 -126
- package/lib/module/js-top/engine/longtasks.js +1 -133
- package/lib/module/js-top/engine/now.js +1 -33
- package/lib/module/js-top/engine/originRegistry.js +1 -388
- package/lib/module/js-top/engine/patches/bridge.js +1 -56
- package/lib/module/js-top/engine/patches/microtasks.js +1 -23
- package/lib/module/js-top/engine/patches/promises.js +1 -62
- package/lib/module/js-top/engine/patches/timers.js +1 -62
- package/lib/module/js-top/engine/state.js +1 -54
- package/lib/module/js-top/engine/symbolicate.js +1 -91
- package/lib/module/js-top/sync/jsTopSyncAdapter.js +1 -70
- package/lib/module/js-top/types/index.js +1 -42
- package/lib/module/js-top/utils/preferences.js +1 -26
- package/lib/module/preset.js +1 -71
- package/lib/web/index.mjs +2 -3
- package/package.json +2 -2
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/js-top/components/BusySparkline.js.map +0 -1
- package/lib/commonjs/js-top/components/JsTopHudOverlay.js.map +0 -1
- package/lib/commonjs/js-top/components/JsTopModal.js.map +0 -1
- package/lib/commonjs/js-top/components/TaskDetailView.js.map +0 -1
- package/lib/commonjs/js-top/components/TaskTable.js.map +0 -1
- package/lib/commonjs/js-top/engine/JsTopController.js.map +0 -1
- package/lib/commonjs/js-top/engine/aggregator.js.map +0 -1
- package/lib/commonjs/js-top/engine/busyProbe.js.map +0 -1
- package/lib/commonjs/js-top/engine/frameStack.js.map +0 -1
- package/lib/commonjs/js-top/engine/longtasks.js.map +0 -1
- package/lib/commonjs/js-top/engine/now.js.map +0 -1
- package/lib/commonjs/js-top/engine/originRegistry.js.map +0 -1
- package/lib/commonjs/js-top/engine/patches/bridge.js.map +0 -1
- package/lib/commonjs/js-top/engine/patches/microtasks.js.map +0 -1
- package/lib/commonjs/js-top/engine/patches/promises.js.map +0 -1
- package/lib/commonjs/js-top/engine/patches/timers.js.map +0 -1
- package/lib/commonjs/js-top/engine/state.js.map +0 -1
- package/lib/commonjs/js-top/engine/symbolicate.js.map +0 -1
- package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js.map +0 -1
- package/lib/commonjs/js-top/types/index.js.map +0 -1
- package/lib/commonjs/js-top/utils/preferences.js.map +0 -1
- package/lib/commonjs/preset.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/js-top/components/BusySparkline.js.map +0 -1
- package/lib/module/js-top/components/JsTopHudOverlay.js.map +0 -1
- package/lib/module/js-top/components/JsTopModal.js.map +0 -1
- package/lib/module/js-top/components/TaskDetailView.js.map +0 -1
- package/lib/module/js-top/components/TaskTable.js.map +0 -1
- package/lib/module/js-top/engine/JsTopController.js.map +0 -1
- package/lib/module/js-top/engine/aggregator.js.map +0 -1
- package/lib/module/js-top/engine/busyProbe.js.map +0 -1
- package/lib/module/js-top/engine/frameStack.js.map +0 -1
- package/lib/module/js-top/engine/longtasks.js.map +0 -1
- package/lib/module/js-top/engine/now.js.map +0 -1
- package/lib/module/js-top/engine/originRegistry.js.map +0 -1
- package/lib/module/js-top/engine/patches/bridge.js.map +0 -1
- package/lib/module/js-top/engine/patches/microtasks.js.map +0 -1
- package/lib/module/js-top/engine/patches/promises.js.map +0 -1
- package/lib/module/js-top/engine/patches/timers.js.map +0 -1
- package/lib/module/js-top/engine/state.js.map +0 -1
- package/lib/module/js-top/engine/symbolicate.js.map +0 -1
- package/lib/module/js-top/sync/jsTopSyncAdapter.js.map +0 -1
- package/lib/module/js-top/types/index.js.map +0 -1
- package/lib/module/js-top/utils/preferences.js.map +0 -1
- package/lib/module/preset.js.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/js-top/components/BusySparkline.d.ts.map +0 -1
- package/lib/typescript/js-top/components/JsTopHudOverlay.d.ts.map +0 -1
- package/lib/typescript/js-top/components/JsTopModal.d.ts.map +0 -1
- package/lib/typescript/js-top/components/TaskDetailView.d.ts.map +0 -1
- package/lib/typescript/js-top/components/TaskTable.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/JsTopController.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/aggregator.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/busyProbe.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/frameStack.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/longtasks.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/now.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/originRegistry.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/patches/bridge.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/patches/microtasks.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/patches/promises.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/patches/timers.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/state.d.ts.map +0 -1
- package/lib/typescript/js-top/engine/symbolicate.d.ts.map +0 -1
- package/lib/typescript/js-top/sync/jsTopSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/js-top/types/index.d.ts.map +0 -1
- package/lib/typescript/js-top/utils/preferences.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
|
@@ -1,126 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* wrapTask — the single wrapper every patched entry point uses, plus the
|
|
5
|
-
* frame stack that makes nested wrapped calls book EXCLUSIVE time.
|
|
6
|
-
*
|
|
7
|
-
* The no-double-count rule: every wrapper at any depth books
|
|
8
|
-
* `(end − start) − childrenMs` to its own origin and adds its TOTAL to its
|
|
9
|
-
* parent frame's childrenMs. Thread occupancy is then the sum of exclusive
|
|
10
|
-
* time at all depths, which equals the union of wrapped wall intervals —
|
|
11
|
-
* nesting (e.g. rAF callbacks fired inside a wrapped bridge call-in) can
|
|
12
|
-
* never inflate totals.
|
|
13
|
-
*
|
|
14
|
-
* Naming: exported/inner functions carry a `buoyJsTop` prefix on purpose —
|
|
15
|
-
* Hermes dev stacks only show function names + bundle offsets, and the
|
|
16
|
-
* registry's stack parser filters engine frames by that prefix.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { now } from "./now";
|
|
20
|
-
import { isActive, WRAPPED_TAG } from "./state";
|
|
21
|
-
import { buoyJsTopBookExclusive, buoyJsTopOriginExists, buoyJsTopScheduleOrigin } from "./originRegistry";
|
|
22
|
-
const DEPTH_CAP = 32;
|
|
23
|
-
const stack = [];
|
|
24
|
-
|
|
25
|
-
/** Depth-0 completed intervals ≥ this feed the longtask correlator. */
|
|
26
|
-
const NOTABLE_INTERVAL_MS = 20;
|
|
27
|
-
const INTERVAL_RING_SIZE = 64;
|
|
28
|
-
const intervalRing = new Array(INTERVAL_RING_SIZE).fill(null);
|
|
29
|
-
let intervalRingIndex = 0;
|
|
30
|
-
|
|
31
|
-
/** Recent depth-0 wrapped intervals, unordered — consumers scan all slots. */
|
|
32
|
-
export function recentIntervals() {
|
|
33
|
-
return intervalRing;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
|
|
38
|
-
/** Push a frame (unless depth-capped), run `invoke`, book on the way out. */
|
|
39
|
-
function buoyJsTopRunFrame(originKey, invoke) {
|
|
40
|
-
const start = now();
|
|
41
|
-
const parent = stack.length > 0 ? stack[stack.length - 1] : null;
|
|
42
|
-
let frame = null;
|
|
43
|
-
if (stack.length < DEPTH_CAP) {
|
|
44
|
-
frame = {
|
|
45
|
-
originKey,
|
|
46
|
-
start,
|
|
47
|
-
childrenMs: 0
|
|
48
|
-
};
|
|
49
|
-
stack.push(frame);
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
// The user code runs OUTSIDE any catch of ours: errors propagate to the
|
|
53
|
-
// runtime's normal unhandled-error path untouched.
|
|
54
|
-
return invoke();
|
|
55
|
-
} finally {
|
|
56
|
-
try {
|
|
57
|
-
if (frame) {
|
|
58
|
-
stack.pop();
|
|
59
|
-
const end = now();
|
|
60
|
-
const total = end - start;
|
|
61
|
-
const exclusive = Math.max(0, total - frame.childrenMs);
|
|
62
|
-
if (parent) parent.childrenMs += total;
|
|
63
|
-
buoyJsTopBookExclusive(originKey, exclusive, start, end);
|
|
64
|
-
if (!parent && total >= NOTABLE_INTERVAL_MS) {
|
|
65
|
-
intervalRing[intervalRingIndex] = {
|
|
66
|
-
originKey,
|
|
67
|
-
start,
|
|
68
|
-
end
|
|
69
|
-
};
|
|
70
|
-
intervalRingIndex = (intervalRingIndex + 1) % INTERVAL_RING_SIZE;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
} catch {
|
|
74
|
-
// Bookkeeping must never break the app.
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Wrap a callback at schedule time. ALWAYS wraps once patches are installed
|
|
81
|
-
* (installation itself only happens on first engine start): a long-lived
|
|
82
|
-
* callback — the classic forgotten setInterval — must stay attributable
|
|
83
|
-
* even when it was scheduled while the engine was off, or after clear()
|
|
84
|
-
* deleted its origin record. Identity is therefore resolved eagerly at
|
|
85
|
-
* schedule time when possible (best stack context) and re-resolved lazily
|
|
86
|
-
* at fire time otherwise. Inactive-engine cost per fire: one boolean.
|
|
87
|
-
*/
|
|
88
|
-
export function buoyJsTopWrapTask(fn, api) {
|
|
89
|
-
if (typeof fn !== "function") return fn;
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
91
|
-
if (fn[WRAPPED_TAG]) return fn;
|
|
92
|
-
let originKey = isActive() ? buoyJsTopScheduleOrigin(api, fn, now()) : null;
|
|
93
|
-
|
|
94
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
|
-
const buoyJsTopTaskWrapper = function (...args) {
|
|
96
|
-
if (!isActive()) return fn.apply(this, args);
|
|
97
|
-
if (originKey === null || !buoyJsTopOriginExists(originKey)) {
|
|
98
|
-
// Scheduled while the engine was off, or stats cleared since —
|
|
99
|
-
// (re)resolve identity now, without stack capture (see scheduleOrigin).
|
|
100
|
-
originKey = buoyJsTopScheduleOrigin(api, fn, now(), false);
|
|
101
|
-
}
|
|
102
|
-
return buoyJsTopRunFrame(originKey, () => fn.apply(this, args));
|
|
103
|
-
};
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
-
buoyJsTopTaskWrapper[WRAPPED_TAG] = true;
|
|
106
|
-
return buoyJsTopTaskWrapper;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Run a thunk as a named task frame — for entry points that aren't
|
|
111
|
-
* schedule-a-callback shaped (e.g. bridge call-ins, where the "origin" is
|
|
112
|
-
* the module.method being invoked right now).
|
|
113
|
-
*/
|
|
114
|
-
export function buoyJsTopRunAs(api, name, thunk) {
|
|
115
|
-
if (!isActive()) return thunk();
|
|
116
|
-
const originKey = buoyJsTopScheduleOrigin(api, {
|
|
117
|
-
name
|
|
118
|
-
}, now());
|
|
119
|
-
return buoyJsTopRunFrame(originKey, thunk);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Test-only: current nesting depth. */
|
|
123
|
-
export function debugDepth() {
|
|
124
|
-
return stack.length;
|
|
125
|
-
}
|
|
126
|
-
//# sourceMappingURL=frameStack.js.map
|
|
1
|
+
"use strict";import{now as s}from"./now";import{isActive as c,WRAPPED_TAG as f}from"./state";import{buoyJsTopBookExclusive as x,buoyJsTopOriginExists as A,buoyJsTopScheduleOrigin as p}from"./originRegistry";const b=32;const e=[];const g=20;const y=64;const T=new Array(y).fill(null);let a=0;export function recentIntervals(){return T}function h(t,i){const n=s();const r=e.length>0?e[e.length-1]:null;let o=null;if(e.length<b){o={originKey:t,start:n,childrenMs:0};e.push(o)}try{return i()}finally{try{if(o){e.pop();const u=s();const l=u-n;const m=Math.max(0,l-o.childrenMs);if(r)r.childrenMs+=l;x(t,m,n,u);if(!r&&l>=g){T[a]={originKey:t,start:n,end:u};a=(a+1)%y}}}catch{}}}export function buoyJsTopWrapTask(t,i){if(typeof t!=="function")return t;if(t[f])return t;let n=c()?p(i,t,s()):null;const r=function(...o){if(!c())return t.apply(this,o);if(n===null||!A(n)){n=p(i,t,s(),false)}return h(n,()=>t.apply(this,o))};r[f]=true;return r}export function buoyJsTopRunAs(t,i,n){if(!c())return n();const r=p(t,{name:i},s());return h(r,n)}export function debugDepth(){return e.length}
|
|
@@ -1,133 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Freeze tracking. RN ships a real `PerformanceObserver('longtask')` (C++
|
|
5
|
-
* TurboModule, present in Expo Go and release): entries fire for any task
|
|
6
|
-
* that blocks the JS event loop ≥ 50ms — what a user feels as a dropped tap
|
|
7
|
-
* or stuttered animation — but carry NO attribution. We supply it: each
|
|
8
|
-
* entry is overlap-matched against the ring of recent depth-0 wrapped
|
|
9
|
-
* intervals; the biggest overlap names the offender.
|
|
10
|
-
*
|
|
11
|
-
* Freeze data doesn't get its own UI section — it decorates the places you
|
|
12
|
-
* already look: per-row ⚠ badges in the task table and a summary chip in
|
|
13
|
-
* the header, both fed by getFreezeStats() (trailing 60s window). The raw
|
|
14
|
-
* entry list is still exported for the desktop panel and MCP payloads.
|
|
15
|
-
*
|
|
16
|
-
* The observer installs once and stays connected (uninstalling/reinstalling
|
|
17
|
-
* observers has its own churn); its handler early-outs when the engine is
|
|
18
|
-
* inactive — longtasks only fire on 50ms+ blocks, so the idle cost is nil.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { g, isActive } from "./state";
|
|
22
|
-
import { recentIntervals } from "./frameStack";
|
|
23
|
-
import { labelForOrigin } from "./originRegistry";
|
|
24
|
-
import { bookLongtaskRange } from "./aggregator";
|
|
25
|
-
const MAX_ENTRIES = 40;
|
|
26
|
-
/** Freeze badges/summary only consider the trailing window. */
|
|
27
|
-
const FREEZE_WINDOW_MS = 60_000;
|
|
28
|
-
|
|
29
|
-
/** Per-origin key for freezes we couldn't attribute to a wrapped callback. */
|
|
30
|
-
export const SYSTEM_FREEZE_KEY = "unattributed";
|
|
31
|
-
let installed = false;
|
|
32
|
-
let supported = false;
|
|
33
|
-
const entries = [];
|
|
34
|
-
function correlate(start, duration) {
|
|
35
|
-
const end = start + duration;
|
|
36
|
-
let bestKey = null;
|
|
37
|
-
let bestOverlap = 0;
|
|
38
|
-
for (const interval of recentIntervals()) {
|
|
39
|
-
if (!interval) continue;
|
|
40
|
-
const overlap = Math.min(end, interval.end) - Math.max(start, interval.start);
|
|
41
|
-
if (overlap > bestOverlap) {
|
|
42
|
-
bestOverlap = overlap;
|
|
43
|
-
bestKey = interval.originKey;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return bestKey;
|
|
47
|
-
}
|
|
48
|
-
export function installLongtaskObserver() {
|
|
49
|
-
if (installed) return {
|
|
50
|
-
longtask: supported
|
|
51
|
-
};
|
|
52
|
-
installed = true;
|
|
53
|
-
const PerformanceObserverCtor = g.PerformanceObserver;
|
|
54
|
-
if (typeof PerformanceObserverCtor !== "function") {
|
|
55
|
-
return {
|
|
56
|
-
longtask: false
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
-
const observer = new PerformanceObserverCtor(list => {
|
|
62
|
-
if (!isActive()) return;
|
|
63
|
-
try {
|
|
64
|
-
for (const entry of list.getEntries()) {
|
|
65
|
-
if (entry.entryType !== "longtask") continue;
|
|
66
|
-
const start = entry.startTime;
|
|
67
|
-
const duration = entry.duration;
|
|
68
|
-
bookLongtaskRange(start, start + duration);
|
|
69
|
-
entries.push({
|
|
70
|
-
start,
|
|
71
|
-
duration,
|
|
72
|
-
at: Date.now(),
|
|
73
|
-
originKey: correlate(start, duration)
|
|
74
|
-
});
|
|
75
|
-
if (entries.length > MAX_ENTRIES) entries.shift();
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
// Never let observation break the app.
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
observer.observe({
|
|
82
|
-
entryTypes: ["longtask"]
|
|
83
|
-
});
|
|
84
|
-
supported = true;
|
|
85
|
-
} catch {
|
|
86
|
-
supported = false;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
longtask: supported
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Raw recent entries (desktop panel + MCP payload shape). */
|
|
94
|
-
export function getLongtasks() {
|
|
95
|
-
return entries.map(e => ({
|
|
96
|
-
start: e.start,
|
|
97
|
-
duration: e.duration,
|
|
98
|
-
at: e.at,
|
|
99
|
-
originLabel: e.originKey ? labelForOrigin(e.originKey) : null
|
|
100
|
-
}));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Windowed per-origin freeze aggregation for badges + header summary. */
|
|
104
|
-
export function getFreezeStats(now) {
|
|
105
|
-
const byOrigin = {};
|
|
106
|
-
let count = 0;
|
|
107
|
-
let worstMs = 0;
|
|
108
|
-
for (const e of entries) {
|
|
109
|
-
if (e.at > 0 && now - e.at > FREEZE_WINDOW_MS) continue;
|
|
110
|
-
count++;
|
|
111
|
-
if (e.duration > worstMs) worstMs = e.duration;
|
|
112
|
-
const key = e.originKey ?? SYSTEM_FREEZE_KEY;
|
|
113
|
-
const s = byOrigin[key];
|
|
114
|
-
if (s) {
|
|
115
|
-
s.count++;
|
|
116
|
-
if (e.duration > s.maxMs) s.maxMs = e.duration;
|
|
117
|
-
} else {
|
|
118
|
-
byOrigin[key] = {
|
|
119
|
-
count: 1,
|
|
120
|
-
maxMs: e.duration
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
count,
|
|
126
|
-
worstMs,
|
|
127
|
-
byOrigin
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
export function clearLongtasks() {
|
|
131
|
-
entries.length = 0;
|
|
132
|
-
}
|
|
133
|
-
//# sourceMappingURL=longtasks.js.map
|
|
1
|
+
"use strict";import{g as f,isActive as l}from"./state";import{recentIntervals as g}from"./frameStack";import{labelForOrigin as p}from"./originRegistry";import{bookLongtaskRange as m}from"./aggregator";const y=40;const d=6e4;export const SYSTEM_FREEZE_KEY="unattributed";let u=false;let c=false;const a=[];function b(n,o){const i=n+o;let r=null;let t=0;for(const e of g()){if(!e)continue;const s=Math.min(i,e.end)-Math.max(n,e.start);if(s>t){t=s;r=e.originKey}}return r}export function installLongtaskObserver(){if(u)return{longtask:c};u=true;const n=f.PerformanceObserver;if(typeof n!=="function"){return{longtask:false}}try{const o=new n(i=>{if(!l())return;try{for(const r of i.getEntries()){if(r.entryType!=="longtask")continue;const t=r.startTime;const e=r.duration;m(t,t+e);a.push({start:t,duration:e,at:Date.now(),originKey:b(t,e)});if(a.length>y)a.shift()}}catch{}});o.observe({entryTypes:["longtask"]});c=true}catch{c=false}return{longtask:c}}export function getLongtasks(){return a.map(n=>({start:n.start,duration:n.duration,at:n.at,originLabel:n.originKey?p(n.originKey):null}))}export function getFreezeStats(n){const o={};let i=0;let r=0;for(const t of a){if(t.at>0&&n-t.at>d)continue;i++;if(t.duration>r)r=t.duration;const e=t.originKey??SYSTEM_FREEZE_KEY;const s=o[e];if(s){s.count++;if(t.duration>s.maxMs)s.maxMs=t.duration}else{o[e]={count:1,maxMs:t.duration}}}return{count:i,worstMs:r,byOrigin:o}}export function clearLongtasks(){a.length=0}
|
|
@@ -1,33 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* High-res monotonic clock for the engine's hot path. Resolved once at module
|
|
5
|
-
* load: `nativePerformanceNow` (JSI global, cheapest) → `performance.now` →
|
|
6
|
-
* `Date.now`. All engine timestamps share this single time base.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
-
const g =
|
|
11
|
-
// eslint-disable-next-line no-restricted-globals
|
|
12
|
-
typeof globalThis !== "undefined" ? globalThis : undefined;
|
|
13
|
-
const resolved = (() => {
|
|
14
|
-
if (typeof g?.nativePerformanceNow === "function") {
|
|
15
|
-
const native = g.nativePerformanceNow;
|
|
16
|
-
return () => native();
|
|
17
|
-
}
|
|
18
|
-
if (typeof g?.performance?.now === "function") {
|
|
19
|
-
const perf = g.performance;
|
|
20
|
-
return () => perf.now();
|
|
21
|
-
}
|
|
22
|
-
return () => Date.now();
|
|
23
|
-
})();
|
|
24
|
-
let clock = resolved;
|
|
25
|
-
export function now() {
|
|
26
|
-
return clock();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Test-only: swap the engine clock for a controllable one. */
|
|
30
|
-
export function setNowForTests(fn) {
|
|
31
|
-
clock = fn ?? resolved;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=now.js.map
|
|
1
|
+
"use strict";const n=typeof globalThis!=="undefined"?globalThis:void 0;const o=(()=>{if(typeof n?.nativePerformanceNow==="function"){const e=n.nativePerformanceNow;return()=>e()}if(typeof n?.performance?.now==="function"){const e=n.performance;return()=>e.now()}return()=>Date.now()})();let t=o;export function now(){return t()}export function setNowForTests(e){t=e??o}
|