@memlab/mcp-server 2.52.0 → 2.86.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/README.md +22 -2
- package/dist/anonymized-snapshot.d.ts +75 -0
- package/dist/anonymized-snapshot.d.ts.map +1 -0
- package/dist/anonymized-snapshot.js +101 -0
- package/dist/anonymized-snapshot.js.map +1 -0
- package/dist/eval-hints.d.ts +41 -0
- package/dist/eval-hints.d.ts.map +1 -0
- package/dist/eval-hints.js +115 -0
- package/dist/eval-hints.js.map +1 -0
- package/dist/heap-budget.d.ts +32 -0
- package/dist/heap-budget.d.ts.map +1 -0
- package/dist/heap-budget.js +90 -0
- package/dist/heap-budget.js.map +1 -0
- package/dist/heap-shapes.d.ts +148 -0
- package/dist/heap-shapes.d.ts.map +1 -0
- package/dist/heap-shapes.js +193 -0
- package/dist/heap-shapes.js.map +1 -0
- package/dist/heap-state.d.ts +20 -0
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +8 -1
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +64 -1
- package/dist/index.js.map +1 -1
- package/dist/react-shapes.d.ts +42 -0
- package/dist/react-shapes.d.ts.map +1 -0
- package/dist/react-shapes.js +149 -0
- package/dist/react-shapes.js.map +1 -0
- package/dist/server-version.d.ts +19 -0
- package/dist/server-version.d.ts.map +1 -0
- package/dist/server-version.js +19 -0
- package/dist/server-version.js.map +1 -0
- package/dist/snapshot-borrow.d.ts +67 -0
- package/dist/snapshot-borrow.d.ts.map +1 -0
- package/dist/snapshot-borrow.js +113 -0
- package/dist/snapshot-borrow.js.map +1 -0
- package/dist/string-index.d.ts.map +1 -1
- package/dist/string-index.js +8 -0
- package/dist/string-index.js.map +1 -1
- package/dist/tools/analyze-run.d.ts.map +1 -1
- package/dist/tools/analyze-run.js +79 -18
- package/dist/tools/analyze-run.js.map +1 -1
- package/dist/tools/anonymize-snapshot.d.ts +12 -0
- package/dist/tools/anonymize-snapshot.d.ts.map +1 -0
- package/dist/tools/anonymize-snapshot.js +159 -0
- package/dist/tools/anonymize-snapshot.js.map +1 -0
- package/dist/tools/app-config.d.ts +12 -0
- package/dist/tools/app-config.d.ts.map +1 -0
- package/dist/tools/app-config.js +217 -0
- package/dist/tools/app-config.js.map +1 -0
- package/dist/tools/app-heap.d.ts +18 -0
- package/dist/tools/app-heap.d.ts.map +1 -1
- package/dist/tools/app-heap.js +12 -46
- package/dist/tools/app-heap.js.map +1 -1
- package/dist/tools/artifact-budget.d.ts +12 -0
- package/dist/tools/artifact-budget.d.ts.map +1 -0
- package/dist/tools/artifact-budget.js +219 -0
- package/dist/tools/artifact-budget.js.map +1 -0
- package/dist/tools/async-census.d.ts +12 -0
- package/dist/tools/async-census.d.ts.map +1 -0
- package/dist/tools/async-census.js +243 -0
- package/dist/tools/async-census.js.map +1 -0
- package/dist/tools/auto-investigate.d.ts.map +1 -1
- package/dist/tools/auto-investigate.js +54 -5
- package/dist/tools/auto-investigate.js.map +1 -1
- package/dist/tools/batch.d.ts.map +1 -1
- package/dist/tools/batch.js +33 -5
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/cache-analysis.d.ts +15 -0
- package/dist/tools/cache-analysis.d.ts.map +1 -1
- package/dist/tools/cache-analysis.js +85 -10
- package/dist/tools/cache-analysis.js.map +1 -1
- package/dist/tools/census-diff.d.ts +55 -0
- package/dist/tools/census-diff.d.ts.map +1 -0
- package/dist/tools/census-diff.js +228 -0
- package/dist/tools/census-diff.js.map +1 -0
- package/dist/tools/chain-walk.d.ts +12 -0
- package/dist/tools/chain-walk.d.ts.map +1 -0
- package/dist/tools/chain-walk.js +184 -0
- package/dist/tools/chain-walk.js.map +1 -0
- package/dist/tools/collection-diff.d.ts +44 -0
- package/dist/tools/collection-diff.d.ts.map +1 -0
- package/dist/tools/collection-diff.js +343 -0
- package/dist/tools/collection-diff.js.map +1 -0
- package/dist/tools/collection-trend.d.ts.map +1 -1
- package/dist/tools/collection-trend.js +2 -2
- package/dist/tools/collection-trend.js.map +1 -1
- package/dist/tools/detached-dom.d.ts +3 -0
- package/dist/tools/detached-dom.d.ts.map +1 -1
- package/dist/tools/detached-dom.js +78 -3
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/dev-artifacts.d.ts.map +1 -1
- package/dist/tools/dev-artifacts.js +221 -3
- package/dist/tools/dev-artifacts.js.map +1 -1
- package/dist/tools/diff-snapshots.d.ts.map +1 -1
- package/dist/tools/diff-snapshots.js +18 -2
- package/dist/tools/diff-snapshots.js.map +1 -1
- package/dist/tools/dom-audit.d.ts +37 -0
- package/dist/tools/dom-audit.d.ts.map +1 -0
- package/dist/tools/dom-audit.js +247 -0
- package/dist/tools/dom-audit.js.map +1 -0
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +3 -2
- package/dist/tools/duplicated-strings.js.map +1 -1
- package/dist/tools/eval-across.d.ts +12 -0
- package/dist/tools/eval-across.d.ts.map +1 -0
- package/dist/tools/eval-across.js +135 -0
- package/dist/tools/eval-across.js.map +1 -0
- package/dist/tools/eval.d.ts +78 -0
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +2270 -701
- package/dist/tools/eval.js.map +1 -1
- package/dist/tools/event-listener-leaks.d.ts.map +1 -1
- package/dist/tools/event-listener-leaks.js +42 -17
- package/dist/tools/event-listener-leaks.js.map +1 -1
- package/dist/tools/event-registry.d.ts.map +1 -1
- package/dist/tools/event-registry.js +42 -8
- package/dist/tools/event-registry.js.map +1 -1
- package/dist/tools/explain-delta.d.ts.map +1 -1
- package/dist/tools/explain-delta.js +61 -10
- package/dist/tools/explain-delta.js.map +1 -1
- package/dist/tools/finding-index.d.ts +181 -0
- package/dist/tools/finding-index.d.ts.map +1 -1
- package/dist/tools/finding-index.js +343 -24
- package/dist/tools/finding-index.js.map +1 -1
- package/dist/tools/get-value.d.ts +16 -0
- package/dist/tools/get-value.d.ts.map +1 -1
- package/dist/tools/get-value.js +96 -2
- package/dist/tools/get-value.js.map +1 -1
- package/dist/tools/hypothesis.d.ts.map +1 -1
- package/dist/tools/hypothesis.js +117 -58
- package/dist/tools/hypothesis.js.map +1 -1
- package/dist/tools/id-space-audit.d.ts +12 -0
- package/dist/tools/id-space-audit.d.ts.map +1 -0
- package/dist/tools/id-space-audit.js +262 -0
- package/dist/tools/id-space-audit.js.map +1 -0
- package/dist/tools/identify.d.ts +12 -0
- package/dist/tools/identify.d.ts.map +1 -0
- package/dist/tools/identify.js +205 -0
- package/dist/tools/identify.js.map +1 -0
- package/dist/tools/identity-diff.d.ts +12 -0
- package/dist/tools/identity-diff.d.ts.map +1 -0
- package/dist/tools/identity-diff.js +188 -0
- package/dist/tools/identity-diff.js.map +1 -0
- package/dist/tools/intern-opportunities.d.ts.map +1 -1
- package/dist/tools/intern-opportunities.js +4 -3
- package/dist/tools/intern-opportunities.js.map +1 -1
- package/dist/tools/ladder-probe.d.ts +65 -0
- package/dist/tools/ladder-probe.d.ts.map +1 -0
- package/dist/tools/ladder-probe.js +445 -0
- package/dist/tools/ladder-probe.js.map +1 -0
- package/dist/tools/ladder.d.ts.map +1 -1
- package/dist/tools/ladder.js +5 -5
- package/dist/tools/ladder.js.map +1 -1
- package/dist/tools/leak-report.d.ts +23 -0
- package/dist/tools/leak-report.d.ts.map +1 -1
- package/dist/tools/leak-report.js +153 -11
- package/dist/tools/leak-report.js.map +1 -1
- package/dist/tools/load-snapshot.d.ts +11 -0
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +83 -10
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/metric.d.ts +13 -0
- package/dist/tools/metric.d.ts.map +1 -0
- package/dist/tools/metric.js +185 -0
- package/dist/tools/metric.js.map +1 -0
- package/dist/tools/module-attribution.d.ts +36 -0
- package/dist/tools/module-attribution.d.ts.map +1 -0
- package/dist/tools/module-attribution.js +235 -0
- package/dist/tools/module-attribution.js.map +1 -0
- package/dist/tools/next-measurement.d.ts +26 -0
- package/dist/tools/next-measurement.d.ts.map +1 -0
- package/dist/tools/next-measurement.js +149 -0
- package/dist/tools/next-measurement.js.map +1 -0
- package/dist/tools/object-cost-breakdown.d.ts.map +1 -1
- package/dist/tools/object-cost-breakdown.js +64 -0
- package/dist/tools/object-cost-breakdown.js.map +1 -1
- package/dist/tools/population-vs-owners.d.ts +12 -0
- package/dist/tools/population-vs-owners.d.ts.map +1 -0
- package/dist/tools/population-vs-owners.js +183 -0
- package/dist/tools/population-vs-owners.js.map +1 -0
- package/dist/tools/property-names.d.ts +29 -0
- package/dist/tools/property-names.d.ts.map +1 -0
- package/dist/tools/property-names.js +131 -0
- package/dist/tools/property-names.js.map +1 -0
- package/dist/tools/quick-diagnosis.d.ts.map +1 -1
- package/dist/tools/quick-diagnosis.js +7 -1
- package/dist/tools/quick-diagnosis.js.map +1 -1
- package/dist/tools/react-owners.d.ts +12 -0
- package/dist/tools/react-owners.d.ts.map +1 -0
- package/dist/tools/react-owners.js +167 -0
- package/dist/tools/react-owners.js.map +1 -0
- package/dist/tools/react-update-queues.d.ts +12 -0
- package/dist/tools/react-update-queues.d.ts.map +1 -0
- package/dist/tools/react-update-queues.js +173 -0
- package/dist/tools/react-update-queues.js.map +1 -0
- package/dist/tools/replicate.d.ts +49 -0
- package/dist/tools/replicate.d.ts.map +1 -0
- package/dist/tools/replicate.js +241 -0
- package/dist/tools/replicate.js.map +1 -0
- package/dist/tools/retainer-diff.d.ts +12 -0
- package/dist/tools/retainer-diff.d.ts.map +1 -0
- package/dist/tools/retainer-diff.js +168 -0
- package/dist/tools/retainer-diff.js.map +1 -0
- package/dist/tools/retainer-summary.d.ts +17 -0
- package/dist/tools/retainer-summary.d.ts.map +1 -1
- package/dist/tools/retainer-summary.js +85 -22
- package/dist/tools/retainer-summary.js.map +1 -1
- package/dist/tools/retainer-trace.d.ts.map +1 -1
- package/dist/tools/retainer-trace.js +11 -1
- package/dist/tools/retainer-trace.js.map +1 -1
- package/dist/tools/round-audit.d.ts +66 -0
- package/dist/tools/round-audit.d.ts.map +1 -0
- package/dist/tools/round-audit.js +258 -0
- package/dist/tools/round-audit.js.map +1 -0
- package/dist/tools/round-digest.d.ts +12 -0
- package/dist/tools/round-digest.d.ts.map +1 -0
- package/dist/tools/round-digest.js +190 -0
- package/dist/tools/round-digest.js.map +1 -0
- package/dist/tools/script-census.d.ts +12 -0
- package/dist/tools/script-census.d.ts.map +1 -0
- package/dist/tools/script-census.js +182 -0
- package/dist/tools/script-census.js.map +1 -0
- package/dist/tools/sequence-analysis.d.ts +4 -0
- package/dist/tools/sequence-analysis.d.ts.map +1 -1
- package/dist/tools/sequence-analysis.js +53 -9
- package/dist/tools/sequence-analysis.js.map +1 -1
- package/dist/tools/server-status.d.ts.map +1 -1
- package/dist/tools/server-status.js +4 -1
- package/dist/tools/server-status.js.map +1 -1
- package/dist/tools/settle-check.d.ts +12 -0
- package/dist/tools/settle-check.d.ts.map +1 -0
- package/dist/tools/settle-check.js +188 -0
- package/dist/tools/settle-check.js.map +1 -0
- package/dist/tools/sliced-strings.d.ts.map +1 -1
- package/dist/tools/sliced-strings.js +2 -1
- package/dist/tools/sliced-strings.js.map +1 -1
- package/dist/tools/snapshots.d.ts.map +1 -1
- package/dist/tools/snapshots.js +24 -6
- package/dist/tools/snapshots.js.map +1 -1
- package/dist/tools/sparse-elements.d.ts +12 -0
- package/dist/tools/sparse-elements.d.ts.map +1 -0
- package/dist/tools/sparse-elements.js +215 -0
- package/dist/tools/sparse-elements.js.map +1 -0
- package/dist/tools/stale-collections.d.ts +17 -0
- package/dist/tools/stale-collections.d.ts.map +1 -1
- package/dist/tools/stale-collections.js +28 -0
- package/dist/tools/stale-collections.js.map +1 -1
- package/dist/tools/string-patterns.d.ts.map +1 -1
- package/dist/tools/string-patterns.js +2 -1
- package/dist/tools/string-patterns.js.map +1 -1
- package/dist/tools/tools-index.d.ts.map +1 -1
- package/dist/tools/tools-index.js +155 -5
- package/dist/tools/tools-index.js.map +1 -1
- package/dist/tools/trace-all.d.ts +42 -0
- package/dist/tools/trace-all.d.ts.map +1 -0
- package/dist/tools/trace-all.js +263 -0
- package/dist/tools/trace-all.js.map +1 -0
- package/dist/tools/unit-cost.d.ts +12 -0
- package/dist/tools/unit-cost.d.ts.map +1 -0
- package/dist/tools/unit-cost.js +219 -0
- package/dist/tools/unit-cost.js.map +1 -0
- package/dist/tools/verify-fix.d.ts.map +1 -1
- package/dist/tools/verify-fix.js +11 -3
- package/dist/tools/verify-fix.js.map +1 -1
- package/dist/tools/weakref-census.d.ts +15 -0
- package/dist/tools/weakref-census.d.ts.map +1 -0
- package/dist/tools/weakref-census.js +147 -0
- package/dist/tools/weakref-census.js.map +1 -0
- package/dist/tools/what-if.d.ts +12 -0
- package/dist/tools/what-if.d.ts.map +1 -0
- package/dist/tools/what-if.js +285 -0
- package/dist/tools/what-if.js.map +1 -0
- package/dist/utils.d.ts +92 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +172 -5
- package/dist/utils.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { getSnapshotByHandle } from '../heap-state.js';
|
|
12
|
+
import { errorResult, formatBytes, formatNumber, markdownTable, toolResult, } from '../utils.js';
|
|
13
|
+
import { normalizeClassName } from './sequence-analysis.js';
|
|
14
|
+
function histogram(snapshot) {
|
|
15
|
+
const hist = new Map();
|
|
16
|
+
snapshot.nodes.forEach(node => {
|
|
17
|
+
if (node.id <= 3)
|
|
18
|
+
return;
|
|
19
|
+
const key = `${node.type}::${normalizeClassName(node.name)}`;
|
|
20
|
+
const e = hist.get(key);
|
|
21
|
+
if (e) {
|
|
22
|
+
e.count++;
|
|
23
|
+
e.selfSize += node.self_size;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
hist.set(key, { count: 1, selfSize: node.self_size });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return hist;
|
|
30
|
+
}
|
|
31
|
+
function classify(base, busy, idle) {
|
|
32
|
+
const grew = busy - base;
|
|
33
|
+
if (grew <= 0)
|
|
34
|
+
return idle > busy ? 'still-growing' : 'held';
|
|
35
|
+
if (idle > busy)
|
|
36
|
+
return 'still-growing';
|
|
37
|
+
const retainedFraction = (idle - base) / grew;
|
|
38
|
+
if (retainedFraction <= 0.1)
|
|
39
|
+
return 'drained';
|
|
40
|
+
if (retainedFraction <= 0.5)
|
|
41
|
+
return 'mostly-drained';
|
|
42
|
+
return 'held';
|
|
43
|
+
}
|
|
44
|
+
// Without a baseline the denominator is the whole population rather than the
|
|
45
|
+
// growth, so a large standing population that barely moves scores the same as
|
|
46
|
+
// a leak. The wording is graded accordingly: only the baseline-relative run
|
|
47
|
+
// gets to say "leak candidate".
|
|
48
|
+
const VERDICT_NOTE = {
|
|
49
|
+
drained: 'in-flight work — NOT a leak',
|
|
50
|
+
'mostly-drained': 'mostly transient; small residue',
|
|
51
|
+
held: 'survives idle + GC — leak candidate',
|
|
52
|
+
'still-growing': 'grew further while idle — background accumulation',
|
|
53
|
+
};
|
|
54
|
+
const VERDICT_NOTE_NO_BASELINE = {
|
|
55
|
+
drained: 'almost entirely reclaimed by settling',
|
|
56
|
+
'mostly-drained': 'largely reclaimed by settling',
|
|
57
|
+
held: 'largely retained — cannot tell growth from standing population here',
|
|
58
|
+
'still-growing': 'larger after idle than during the burst',
|
|
59
|
+
};
|
|
60
|
+
export function registerSettleCheck(server) {
|
|
61
|
+
server.tool('memlab_settle_check', 'Separate RETENTION from in-flight BACKLOG by comparing a busy snapshot against one captured after the app settled (idle + forced GC). ' +
|
|
62
|
+
'This is the measurement that a growth ladder alone cannot make: a burst of activity legitimately inflates promise chains, IndexedDB ' +
|
|
63
|
+
'transactions, scheduler queues and request buffers, and every one of those looks exactly like a leak in a two-rung diff. Only a ' +
|
|
64
|
+
'post-idle rung tells them apart — a class that returns to baseline was work in progress, a class that stays is retention.\n\n' +
|
|
65
|
+
'Give it the busy rung and the settled rung (and optionally a pre-activity baseline, which makes the "how much of the growth came back" ' +
|
|
66
|
+
'fraction meaningful rather than absolute). All snapshots must already be resident: load them with `keep_previous: true`.\n\n' +
|
|
67
|
+
'Capture protocol for the settled rung: stop interacting, wait ~30-60s so timers, network callbacks and storage writes complete, force GC, then capture.', {
|
|
68
|
+
busy_handle: z
|
|
69
|
+
.string()
|
|
70
|
+
.describe('Handle of the snapshot taken at peak activity (immediately after the interaction burst).'),
|
|
71
|
+
settled_handle: z
|
|
72
|
+
.string()
|
|
73
|
+
.describe('Handle of the snapshot taken after the app went idle and GC ran.'),
|
|
74
|
+
baseline_handle: z
|
|
75
|
+
.string()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe('Optional handle of a pre-activity baseline. With it, each class is scored on how much of its GROWTH came back; without it, on how much of its total came back (a harsher and less meaningful test for classes with a large standing population).'),
|
|
78
|
+
limit: z
|
|
79
|
+
.number()
|
|
80
|
+
.optional()
|
|
81
|
+
.default(25)
|
|
82
|
+
.describe('Maximum classes to report (default 25).'),
|
|
83
|
+
min_growth: z.number().optional().default(100),
|
|
84
|
+
}, async ({ busy_handle, settled_handle, baseline_handle, limit, min_growth, }) => {
|
|
85
|
+
try {
|
|
86
|
+
const busy = getSnapshotByHandle(busy_handle);
|
|
87
|
+
const settled = getSnapshotByHandle(settled_handle);
|
|
88
|
+
if (busy == null || settled == null) {
|
|
89
|
+
const missing = [
|
|
90
|
+
busy == null ? busy_handle : null,
|
|
91
|
+
settled == null ? settled_handle : null,
|
|
92
|
+
].filter(Boolean);
|
|
93
|
+
return errorResult(new Error(`Not resident: ${missing.join(', ')}. Load every rung with memlab_load_snapshot({keep_previous: true}); this tool compares snapshots in memory rather than re-reading files.`));
|
|
94
|
+
}
|
|
95
|
+
const baseline = baseline_handle != null ? getSnapshotByHandle(baseline_handle) : null;
|
|
96
|
+
if (baseline_handle != null && baseline == null) {
|
|
97
|
+
return errorResult(new Error(`Not resident: ${baseline_handle}.`));
|
|
98
|
+
}
|
|
99
|
+
const busyHist = histogram(busy);
|
|
100
|
+
const settledHist = histogram(settled);
|
|
101
|
+
const baseHist = baseline != null ? histogram(baseline) : null;
|
|
102
|
+
const rows = [];
|
|
103
|
+
for (const [key, busyStats] of busyHist) {
|
|
104
|
+
const base = baseHist?.get(key)?.count ?? 0;
|
|
105
|
+
const idle = settledHist.get(key)?.count ?? 0;
|
|
106
|
+
const grew = busyStats.count - base;
|
|
107
|
+
if (grew < min_growth)
|
|
108
|
+
continue;
|
|
109
|
+
rows.push({
|
|
110
|
+
key,
|
|
111
|
+
base,
|
|
112
|
+
busy: busyStats.count,
|
|
113
|
+
idle,
|
|
114
|
+
verdict: classify(base, busyStats.count, idle),
|
|
115
|
+
reclaimed: busyStats.count - idle,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (rows.length === 0) {
|
|
119
|
+
return toolResult(`No class grew by at least ${formatNumber(min_growth)} between ${baseline_handle ?? '(no baseline)'} and ${busy_handle}. Lower min_growth, or check that the handles are in the right order (busy, then settled).`);
|
|
120
|
+
}
|
|
121
|
+
rows.sort((a, b) => b.busy - b.idle - (a.busy - a.idle));
|
|
122
|
+
const held = rows.filter(r => r.verdict === 'held' || r.verdict === 'still-growing');
|
|
123
|
+
const drained = rows.filter(r => r.verdict === 'drained');
|
|
124
|
+
const busyTotal = totalSelfSize(busyHist);
|
|
125
|
+
const settledTotal = totalSelfSize(settledHist);
|
|
126
|
+
const lines = [
|
|
127
|
+
'## Settle check',
|
|
128
|
+
'',
|
|
129
|
+
`Busy \`${busy_handle}\` → settled \`${settled_handle}\`${baseline_handle ? ` (baseline \`${baseline_handle}\`)` : ''}.`,
|
|
130
|
+
`Heap self size ${formatBytes(busyTotal)} → ${formatBytes(settledTotal)} (${settledTotal <= busyTotal ? '−' : '+'}${formatBytes(Math.abs(busyTotal - settledTotal))} reclaimed by settling).`,
|
|
131
|
+
'',
|
|
132
|
+
baseline_handle == null
|
|
133
|
+
? `**No baseline given, so this ranks reclamation, not leaks.** ${drained.length} class(es) came back almost entirely (in-flight work) and ${held.length} stayed — but "stayed" here includes every large standing population that was never part of the burst, because without a pre-activity rung there is no growth to measure the reclamation against. Pass \`baseline_handle\` to turn this into a leak verdict.`
|
|
134
|
+
: held.length === 0
|
|
135
|
+
? '**Everything that grew came back.** No class survived idle + GC, so the growth in this round was in-flight work, not retention. There is nothing here to fix.'
|
|
136
|
+
: `**${held.length} class(es) survived idle + GC** and ${drained.length} drained. Only the survivors are leak candidates — the drained ones were backlog and should not be reported as findings.`,
|
|
137
|
+
'',
|
|
138
|
+
];
|
|
139
|
+
const headers = baseline_handle
|
|
140
|
+
? ['Class', 'baseline', 'busy', 'settled', 'reclaimed', 'Verdict']
|
|
141
|
+
: ['Class', 'busy', 'settled', 'reclaimed', 'Verdict'];
|
|
142
|
+
const rightCols = baseline_handle
|
|
143
|
+
? new Set([1, 2, 3, 4])
|
|
144
|
+
: new Set([1, 2, 3]);
|
|
145
|
+
const tableRows = rows.slice(0, limit).map(r => {
|
|
146
|
+
const [type, name] = r.key.split('::');
|
|
147
|
+
const label = `${name} (${type})`;
|
|
148
|
+
const cells = baseline_handle
|
|
149
|
+
? [
|
|
150
|
+
label,
|
|
151
|
+
formatNumber(r.base),
|
|
152
|
+
formatNumber(r.busy),
|
|
153
|
+
formatNumber(r.idle),
|
|
154
|
+
formatNumber(r.reclaimed),
|
|
155
|
+
]
|
|
156
|
+
: [
|
|
157
|
+
label,
|
|
158
|
+
formatNumber(r.busy),
|
|
159
|
+
formatNumber(r.idle),
|
|
160
|
+
formatNumber(r.reclaimed),
|
|
161
|
+
];
|
|
162
|
+
const note = baseline_handle != null
|
|
163
|
+
? VERDICT_NOTE[r.verdict]
|
|
164
|
+
: VERDICT_NOTE_NO_BASELINE[r.verdict];
|
|
165
|
+
return [...cells, `${r.verdict} — ${note}`];
|
|
166
|
+
});
|
|
167
|
+
lines.push(markdownTable(headers, tableRows, rightCols));
|
|
168
|
+
if (rows.length > limit) {
|
|
169
|
+
lines.push('', `_… and ${rows.length - limit} more; raise limit._`);
|
|
170
|
+
}
|
|
171
|
+
lines.push('', '_A "drained" verdict is only as good as the settle: if the capture was taken before timers, network callbacks and storage writes finished, work still in flight will read as retention. Give it 30-60s of true idle and force GC first._');
|
|
172
|
+
if (held.length > 0 && baseline_handle != null) {
|
|
173
|
+
lines.push('', '**Next:** for each survivor, `memlab_retainer_trace` on an example instance in the settled snapshot — that is the trace worth putting in a fix.');
|
|
174
|
+
}
|
|
175
|
+
return toolResult(lines.join('\n'));
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
return errorResult(err);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function totalSelfSize(hist) {
|
|
183
|
+
let total = 0;
|
|
184
|
+
for (const s of hist.values())
|
|
185
|
+
total += s.selfSize;
|
|
186
|
+
return total;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=settle-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settle-check.js","sourceRoot":"","sources":["../../src/tools/settle-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,mBAAmB,EAAC,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAO1D,SAAS,SAAS,CAAC,QAAuB;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC5B,IAAI,IAAI,CAAC,EAAE,IAAI,CAAC;YAAE,OAAO;QACzB,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,CAAC,KAAK,EAAE,CAAC;YACV,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAC,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAID,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY;IACxD,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7D,IAAI,IAAI,GAAG,IAAI;QAAE,OAAO,eAAe,CAAC;IACxC,MAAM,gBAAgB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C,IAAI,gBAAgB,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,gBAAgB,IAAI,GAAG;QAAE,OAAO,gBAAgB,CAAC;IACrD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,gCAAgC;AAChC,MAAM,YAAY,GAA4B;IAC5C,OAAO,EAAE,6BAA6B;IACtC,gBAAgB,EAAE,iCAAiC;IACnD,IAAI,EAAE,qCAAqC;IAC3C,eAAe,EAAE,mDAAmD;CACrE,CAAC;AAEF,MAAM,wBAAwB,GAA4B;IACxD,OAAO,EAAE,uCAAuC;IAChD,gBAAgB,EAAE,+BAA+B;IACjD,IAAI,EAAE,qEAAqE;IAC3E,eAAe,EAAE,yCAAyC;CAC3D,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,wIAAwI;QACtI,sIAAsI;QACtI,kIAAkI;QAClI,+HAA+H;QAC/H,yIAAyI;QACzI,8HAA8H;QAC9H,yJAAyJ,EAC3J;QACE,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,CACP,0FAA0F,CAC3F;QACH,cAAc,EAAE,CAAC;aACd,MAAM,EAAE;aACR,QAAQ,CACP,kEAAkE,CACnE;QACH,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,kPAAkP,CACnP;QACH,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,yCAAyC,CAAC;QACtD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;KAC/C,EACD,KAAK,EAAE,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,KAAK,EACL,UAAU,GACX,EAAE,EAAE;QACH,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,OAAO,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;YACpD,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG;oBACd,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;oBACjC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;iBACxC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAClB,OAAO,WAAW,CAChB,IAAI,KAAK,CACP,iBAAiB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,0IAA0I,CAC9K,CACF,CAAC;YACJ,CAAC;YACD,MAAM,QAAQ,GACZ,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACxE,IAAI,eAAe,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;gBAChD,OAAO,WAAW,CAAC,IAAI,KAAK,CAAC,iBAAiB,eAAe,GAAG,CAAC,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YACvC,MAAM,QAAQ,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAE/D,MAAM,IAAI,GAOL,EAAE,CAAC;YAER,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,GAAG,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;gBAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;gBAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;gBACpC,IAAI,IAAI,GAAG,UAAU;oBAAE,SAAS;gBAChC,IAAI,CAAC,IAAI,CAAC;oBACR,GAAG;oBACH,IAAI;oBACJ,IAAI,EAAE,SAAS,CAAC,KAAK;oBACrB,IAAI;oBACJ,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;oBAC9C,SAAS,EAAE,SAAS,CAAC,KAAK,GAAG,IAAI;iBAClC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,UAAU,CACf,6BAA6B,YAAY,CAAC,UAAU,CAAC,YAAY,eAAe,IAAI,eAAe,QAAQ,WAAW,4FAA4F,CACnN,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CACtB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,KAAK,eAAe,CAC3D,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;YAE1D,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,YAAY,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;YAEhD,MAAM,KAAK,GAAa;gBACtB,iBAAiB;gBACjB,EAAE;gBACF,UAAU,WAAW,kBAAkB,cAAc,KAAK,eAAe,CAAC,CAAC,CAAC,gBAAgB,eAAe,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG;gBACxH,kBAAkB,WAAW,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,YAAY,CAAC,KAAK,YAAY,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC,CAAC,0BAA0B;gBAC7L,EAAE;gBACF,eAAe,IAAI,IAAI;oBACrB,CAAC,CAAC,gEAAgE,OAAO,CAAC,MAAM,6DAA6D,IAAI,CAAC,MAAM,8PAA8P;oBACtZ,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;wBACjB,CAAC,CAAC,+JAA+J;wBACjK,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,uCAAuC,OAAO,CAAC,MAAM,0HAA0H;gBACrM,EAAE;aACH,CAAC;YAEF,MAAM,OAAO,GAAG,eAAe;gBAC7B,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC;gBAClE,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YACzD,MAAM,SAAS,GAAG,eAAe;gBAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvB,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC7C,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvC,MAAM,KAAK,GAAG,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;gBAClC,MAAM,KAAK,GAAG,eAAe;oBAC3B,CAAC,CAAC;wBACE,KAAK;wBACL,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;qBAC1B;oBACH,CAAC,CAAC;wBACE,KAAK;wBACL,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;qBAC1B,CAAC;gBACN,MAAM,IAAI,GACR,eAAe,IAAI,IAAI;oBACrB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;oBACzB,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAC1C,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,MAAM,IAAI,EAAE,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;YAEzD,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,IAAI,CAAC,MAAM,GAAG,KAAK,sBAAsB,CAAC,CAAC;YACtE,CAAC;YACD,KAAK,CAAC,IAAI,CACR,EAAE,EACF,0OAA0O,CAC3O,CAAC;YACF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;gBAC/C,KAAK,CAAC,IAAI,CACR,EAAE,EACF,iJAAiJ,CAClJ,CAAC;YACJ,CAAC;YACD,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAA6B;IAClD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE;QAAE,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC;IACnD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliced-strings.d.ts","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"sliced-strings.d.ts","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAsBvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuK7D"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { getSnapshot } from '../heap-state.js';
|
|
12
|
+
import { withAnonymizedBanner } from '../anonymized-snapshot.js';
|
|
12
13
|
import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
|
|
13
14
|
export function registerSlicedStrings(server) {
|
|
14
15
|
server.tool('memlab_sliced_strings', 'Find V8 sliced and concatenated string nodes and identify the parent strings they reference. Sliced strings share backing storage with a parent string — if the parent is a large string (e.g., a multi-MB CSV response), all slices keep the entire parent alive. This is a common cause of hidden memory leaks where small substring references retain massive parent strings. Shows parent strings ranked by parent string size.', {
|
|
@@ -139,7 +140,7 @@ export function registerSlicedStrings(server) {
|
|
|
139
140
|
lines.push(`**⚠ ${largeMB.length} parent string(s) > 1 MB (${formatBytes(totalLarge)} total).** Small substrings (slices) are keeping these large strings alive. Consider copying substring values instead of slicing, or nullifying references to the source data after extraction.`);
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
|
-
return toolResult(lines.join('\n'));
|
|
143
|
+
return toolResult(withAnonymizedBanner(snapshot, lines.join('\n')));
|
|
143
144
|
}
|
|
144
145
|
catch (err) {
|
|
145
146
|
return errorResult(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliced-strings.js","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sliced-strings.js","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,UAAU,GACX,MAAM,aAAa,CAAC;AAWrB,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IACrD,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,qaAAqa,EACra;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,yDAAyD,CAAC;QACtE,eAAe,EAAE,CAAC;aACf,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,8GAA8G,CAC/G;KACJ,EACD,KAAK,EAAE,EAAC,KAAK,EAAE,eAAe,EAAC,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAE/B,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,eAAe,GAAG,CAAC,CAAC;YACxB,IAAI,eAAe,GAAG,CAAC,CAAC;YAExB,mCAAmC;YACnC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;YAEjD,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;gBAC5B,gEAAgE;gBAChE,gEAAgE;gBAChE,iEAAiE;gBACjE,+BAA+B;gBAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC;gBAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,qBAAqB,CAAC;gBAErD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBAEnC,IAAI,QAAQ,EAAE,CAAC;oBACb,WAAW,EAAE,CAAC;oBACd,eAAe,IAAI,IAAI,CAAC,SAAS,CAAC;gBACpC,CAAC;qBAAM,CAAC;oBACN,WAAW,EAAE,CAAC;oBACd,eAAe,IAAI,IAAI,CAAC,SAAS,CAAC;gBACpC,CAAC;gBAED,mEAAmE;gBACnE,kEAAkE;gBAClE,+DAA+D;gBAC/D,gCAAgC;gBAChC,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBACtB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACnC,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,QAAQ;wBAAE,SAAS;oBACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;oBAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ;wBAAE,SAAS;oBAE/B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAC1C,IAAI,QAAQ,EAAE,CAAC;wBACb,QAAQ,CAAC,gBAAgB,EAAE,CAAC;wBAC5B,QAAQ,CAAC,iBAAiB,IAAI,IAAI,CAAC,SAAS,CAAC;oBAC/C,CAAC;yBAAM,CAAC;wBACN,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE;4BACvB,EAAE,EAAE,MAAM,CAAC,EAAE;4BACb,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,SAAS,EAAE,MAAM,CAAC,SAAS;4BAC3B,aAAa,EAAE,MAAM,CAAC,YAAY;4BAClC,gBAAgB,EAAE,CAAC;4BACnB,iBAAiB,EAAE,IAAI,CAAC,SAAS;yBAClC,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM;gBACR,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,WAAW,KAAK,CAAC,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBAC3C,OAAO,UAAU,CACf,0DAA0D,CAC3D,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3C,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CACxC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,SAAS,EAC7B,CAAC,CACF,CAAC;YAEF,wEAAwE;YACxE,yEAAyE;YACzE,yEAAyE;YACzE,yEAAyE;YACzE,yEAAyE;YACzE,4DAA4D;YAC5D,IAAI,OAAO,GAAG,UAAU,CAAC;YACzB,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,eAAe,CACpC,CAAC;gBACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,OAAO,GAAG,QAAQ,CAAC;gBACrB,CAAC;qBAAM,CAAC;oBACN,YAAY,GAAG,iBAAiB,WAAW,CAAC,eAAe,CAAC,gCAAgC,CAAC;gBAC/F,CAAC;YACH,CAAC;YACD,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;YACjE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAE3C,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CACR,uBAAuB,YAAY,CAAC,WAAW,CAAC,WAAW,WAAW,CAAC,eAAe,CAAC,aAAa,CACrG,CAAC;YACF,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CACR,6BAA6B,YAAY,CAAC,WAAW,CAAC,WAAW,WAAW,CAAC,eAAe,CAAC,aAAa,CAC3G,CAAC;YACJ,CAAC;YACD,KAAK,CAAC,IAAI,CACR,yCAAyC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CACxE,CAAC;YACF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CACR,4CAA4C,WAAW,CAAC,gBAAgB,CAAC,WAAW,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,4FAA4F,CAChN,CAAC;YACJ,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEf,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG;oBACd,WAAW;oBACX,SAAS;oBACT,aAAa;oBACb,UAAU;oBACV,aAAa;oBACb,aAAa;iBACd,CAAC;gBACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACxC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/B,IAAI,CAAC,CAAC,EAAE,EAAE;oBACV,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;oBACnD,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;oBACxB,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC;oBAC5B,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC;oBAChC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC;iBACjC,CAAC,CAAC;gBACH,KAAK,CAAC,IAAI,CACR,gDAAgD,YAAY,EAAE,CAC/D,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;gBAEpD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC;gBACnE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;oBAChE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACf,KAAK,CAAC,IAAI,CACR,OAAO,OAAO,CAAC,MAAM,6BAA6B,WAAW,CAAC,UAAU,CAAC,iMAAiM,CAC3Q,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,OAAO,UAAU,CAAC,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAmBvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuIzD"}
|
package/dist/tools/snapshots.js
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* @oncall memory_lab
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
-
import { listSnapshots, getCurrentHandle, setCurrentSnapshot, removeSnapshot, setSessionConfig, getSessionConfig, } from '../heap-state.js';
|
|
12
|
-
import { formatBytes, formatNumber, errorResult, textResult } from '../utils.js';
|
|
11
|
+
import { listSnapshots, getCurrentHandle, setCurrentSnapshot, removeSnapshot, setSessionConfig, getSessionConfig, resetEmittedNotes, } from '../heap-state.js';
|
|
12
|
+
import { formatBytes, formatNumber, errorResult, resetSuggestionBudget, textResult, } from '../utils.js';
|
|
13
13
|
export function registerSnapshots(server) {
|
|
14
|
-
server.tool('memlab_snapshots', 'Manage the multi-snapshot session: list resident snapshots, switch the active one, or unload one to free memory. Also toggles session-level output controls (quiet header, suppress suggestions) to trim repeated boilerplate tokens. Load several snapshots with memlab_load_snapshot({keep_previous:true}) then switch between them by handle. Node ids are only valid within the snapshot they came from.', {
|
|
14
|
+
server.tool('memlab_snapshots', 'Manage the multi-snapshot session: list resident snapshots, switch the active one, or unload one to free memory. Also toggles session-level output controls (quiet header, suppress suggestions, terse) to trim repeated boilerplate tokens. Load several snapshots with memlab_load_snapshot({keep_previous:true}) then switch between them by handle. Node ids are only valid within the snapshot they came from. `repeat_notes` reprints the standing explanatory notes that tools print once per session.', {
|
|
15
15
|
action: z
|
|
16
16
|
.enum(['list', 'switch', 'unload'])
|
|
17
17
|
.optional()
|
|
@@ -29,18 +29,36 @@ export function registerSnapshots(server) {
|
|
|
29
29
|
.boolean()
|
|
30
30
|
.optional()
|
|
31
31
|
.describe('When set, toggles whether tools omit their "Suggested next steps" trailers.'),
|
|
32
|
-
|
|
32
|
+
terse: z
|
|
33
|
+
.boolean()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("When set, toggles session-wide terse output: high-volume, low-decision sections (long per-property censuses and the like) are cut to a count plus the top few rows. One switch instead of remembering each tool's own summary flag, which is spelled differently in each."),
|
|
36
|
+
repeat_notes: z
|
|
37
|
+
.boolean()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Print the standing explanatory notes in full again. Several tools state a long caveat the first time it applies in a session and a one-line pointer afterwards; this clears that memory, which is what you want after a context reset or when handing the transcript to someone else.'),
|
|
40
|
+
}, async ({ action, handle, quiet, suppress_suggestions, terse, repeat_notes, }) => {
|
|
33
41
|
try {
|
|
34
42
|
const configChanges = [];
|
|
35
|
-
if (
|
|
43
|
+
if (repeat_notes === true) {
|
|
44
|
+
resetEmittedNotes();
|
|
45
|
+
configChanges.push('Standing notes reset — the next tool that has one will print it in full.');
|
|
46
|
+
}
|
|
47
|
+
if (quiet != null || suppress_suggestions != null || terse != null) {
|
|
36
48
|
setSessionConfig({
|
|
37
49
|
...(quiet != null ? { quietHeader: quiet } : {}),
|
|
38
50
|
...(suppress_suggestions != null
|
|
39
51
|
? { suppressSuggestions: suppress_suggestions }
|
|
40
52
|
: {}),
|
|
53
|
+
...(terse != null ? { terse } : {}),
|
|
41
54
|
});
|
|
55
|
+
// Explicitly turning suppression OFF means "I want the trailers
|
|
56
|
+
// back", which has to also clear the automatic budget — otherwise the
|
|
57
|
+
// flag reads as broken once the budget has already run out.
|
|
58
|
+
if (suppress_suggestions === false)
|
|
59
|
+
resetSuggestionBudget();
|
|
42
60
|
const cfg = getSessionConfig();
|
|
43
|
-
configChanges.push(`Output config: quietHeader=${cfg.quietHeader}, suppressSuggestions=${cfg.suppressSuggestions}`);
|
|
61
|
+
configChanges.push(`Output config: quietHeader=${cfg.quietHeader}, suppressSuggestions=${cfg.suppressSuggestions}, terse=${cfg.terse}`);
|
|
44
62
|
}
|
|
45
63
|
if (action === 'switch') {
|
|
46
64
|
if (!handle) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshots.js","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"snapshots.js","sourceRoot":"","sources":["../../src/tools/snapshots.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
export declare function registerSparseElements(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=sparse-elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparse-elements.d.ts","sourceRoot":"","sources":["../../src/tools/sparse-elements.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAqEvE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmO9D"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { getSnapshot, shouldEmitNote } from '../heap-state.js';
|
|
12
|
+
import { errorResult, toolResult, formatBytes, formatNumber, markdownTable, suggestionsSuppressed, nearestNamedOwner, } from '../utils.js';
|
|
13
|
+
// Shared with memlab_cache_analysis on purpose: a pre-sized ring buffer is the
|
|
14
|
+
// one shape that is indistinguishable from an unbounded cache by size alone,
|
|
15
|
+
// and a second copy of that heuristic would drift from the first.
|
|
16
|
+
import { looksLikeRingBuffer } from './cache-analysis.js';
|
|
17
|
+
// The elements-store facts live in one module so cost_breakdown, this tool and
|
|
18
|
+
// `helpers.elements` cannot disagree about the same object's capacity.
|
|
19
|
+
import { STORE_HEADER_BYTES, FORGIVEN_TAIL_SLOTS, getElementsIndex, } from '../heap-shapes.js';
|
|
20
|
+
/** What a reader should DO about the group, from which half of the waste dominates. */
|
|
21
|
+
function diagnose(group) {
|
|
22
|
+
if (group.ring) {
|
|
23
|
+
return 'PRE-SIZED RING BUFFER — the owner carries a write cursor and/or a capacity control, so the empty slots are the design, not a leak; the question is whether the configured capacity is right, not whether to trim it';
|
|
24
|
+
}
|
|
25
|
+
const hole = group.holeSlots;
|
|
26
|
+
const slack = group.slackSlots;
|
|
27
|
+
if (hole > slack * 2) {
|
|
28
|
+
return 'sparse keys — the written indices are strided or scattered, so the store is sized for a range it never fills; re-key densely (or use a Map)';
|
|
29
|
+
}
|
|
30
|
+
if (slack > hole * 2) {
|
|
31
|
+
return group.used === 0
|
|
32
|
+
? 'allocated but never filled — the store is sized and then left empty'
|
|
33
|
+
: 'over-allocated — capacity far exceeds the highest key written; presize to the real length';
|
|
34
|
+
}
|
|
35
|
+
return 'both sparse keys and excess capacity';
|
|
36
|
+
}
|
|
37
|
+
export function registerSparseElements(server) {
|
|
38
|
+
server.tool('memlab_sparse_elements', 'Find integer-keyed objects and arrays whose ELEMENTS BACKING STORE is mostly holes — memory V8 has allocated and the application never uses. This is the waste a class histogram cannot see: the store is a `(object elements)` FixedArray charged to no class, and each instance is individually small, so the cost only appears once instances are grouped by owner. Two distinct causes are separated in the output: sparse/strided keys (indices scattered across a range the store must span) and over-allocation (capacity far past the highest key). Groups are labelled by the nearest named property up the retainer chain (`getterImpl.$$cache`), which is what you can grep for. Complements memlab_cache_analysis (entry counts in Maps/Sets) and memlab_object_cost_breakdown (where one class’s bytes go).', {
|
|
39
|
+
min_capacity: z
|
|
40
|
+
.number()
|
|
41
|
+
.optional()
|
|
42
|
+
.default(32)
|
|
43
|
+
.describe('Ignore backing stores smaller than this many slots (default 32). Below it, V8’s own growth floor dominates and every short array looks empty.'),
|
|
44
|
+
max_occupancy: z
|
|
45
|
+
.number()
|
|
46
|
+
.optional()
|
|
47
|
+
.default(0.5)
|
|
48
|
+
.describe('Only count an instance when at most this fraction of its slots hold a value (default 0.5). Raise toward 1 to include stores that are merely over-allocated.'),
|
|
49
|
+
min_group_bytes: z
|
|
50
|
+
.number()
|
|
51
|
+
.optional()
|
|
52
|
+
.default(4096)
|
|
53
|
+
.describe('Drop groups wasting less than this many bytes in total (default 4096).'),
|
|
54
|
+
limit: z
|
|
55
|
+
.number()
|
|
56
|
+
.optional()
|
|
57
|
+
.default(20)
|
|
58
|
+
.describe('Maximum number of groups to report (default 20).'),
|
|
59
|
+
max_hops: z
|
|
60
|
+
.number()
|
|
61
|
+
.optional()
|
|
62
|
+
.default(6)
|
|
63
|
+
.describe('How far up the retainer chain to look for a named owner before giving up and grouping as unattributed (default 6).'),
|
|
64
|
+
}, async ({ min_capacity, max_occupancy, min_group_bytes, limit, max_hops }) => {
|
|
65
|
+
try {
|
|
66
|
+
const snapshot = getSnapshot();
|
|
67
|
+
// The structural pass is memoized per snapshot (see heap-shapes.ts):
|
|
68
|
+
// repeated calls while tuning min_capacity / max_occupancy — the normal
|
|
69
|
+
// way this tool is used — cost one full walk, not one per call.
|
|
70
|
+
const index = getElementsIndex(snapshot);
|
|
71
|
+
const slotBytes = index.slotBytes;
|
|
72
|
+
const groups = new Map();
|
|
73
|
+
let unmeasurable = 0;
|
|
74
|
+
let unmeasurableBytes = 0;
|
|
75
|
+
let dictionaries = 0;
|
|
76
|
+
let examined = 0;
|
|
77
|
+
for (let i = 0; i < index.count; i++) {
|
|
78
|
+
const storeBytes = index.storeBytes[i];
|
|
79
|
+
const rawUsed = index.used[i];
|
|
80
|
+
const capacity = Math.floor((storeBytes - STORE_HEADER_BYTES) / slotBytes);
|
|
81
|
+
const span = index.maxIndex[i] + 1;
|
|
82
|
+
if (span > capacity) {
|
|
83
|
+
// Keys reach past the dense capacity: this is a NumberDictionary,
|
|
84
|
+
// where a hole costs nothing and "waste" is not defined.
|
|
85
|
+
dictionaries++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (capacity < min_capacity)
|
|
89
|
+
continue;
|
|
90
|
+
examined++;
|
|
91
|
+
if (rawUsed === 0) {
|
|
92
|
+
unmeasurable++;
|
|
93
|
+
unmeasurableBytes += storeBytes;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (rawUsed / capacity > max_occupancy)
|
|
97
|
+
continue;
|
|
98
|
+
const holeSlots = span - rawUsed;
|
|
99
|
+
const slackSlots = Math.max(0, capacity - span - FORGIVEN_TAIL_SLOTS);
|
|
100
|
+
if (holeSlots + slackSlots === 0)
|
|
101
|
+
continue;
|
|
102
|
+
// Resolving the node is deferred to here on purpose: attribution is
|
|
103
|
+
// the expensive part and only the survivors of the filters need it.
|
|
104
|
+
const node = snapshot.getNodeById(index.ownerIds[i]);
|
|
105
|
+
if (node == null)
|
|
106
|
+
continue;
|
|
107
|
+
const attributed = nearestNamedOwner(node, { maxHops: max_hops });
|
|
108
|
+
const key = attributed
|
|
109
|
+
? attributed.label
|
|
110
|
+
: `(unattributed) ${node.name}`;
|
|
111
|
+
let group = groups.get(key);
|
|
112
|
+
if (!group) {
|
|
113
|
+
group = {
|
|
114
|
+
key,
|
|
115
|
+
className: node.name,
|
|
116
|
+
count: 0,
|
|
117
|
+
capacity: 0,
|
|
118
|
+
used: 0,
|
|
119
|
+
holeSlots: 0,
|
|
120
|
+
slackSlots: 0,
|
|
121
|
+
exampleId: node.id,
|
|
122
|
+
exampleCapacity: capacity,
|
|
123
|
+
exampleUsed: rawUsed,
|
|
124
|
+
exampleSpan: span,
|
|
125
|
+
ring: looksLikeRingBuffer(attributed?.ownerNode ?? null),
|
|
126
|
+
};
|
|
127
|
+
groups.set(key, group);
|
|
128
|
+
}
|
|
129
|
+
if (group.className !== node.name)
|
|
130
|
+
group.className = 'mixed';
|
|
131
|
+
group.count++;
|
|
132
|
+
group.capacity += capacity;
|
|
133
|
+
group.used += rawUsed;
|
|
134
|
+
group.holeSlots += holeSlots;
|
|
135
|
+
group.slackSlots += slackSlots;
|
|
136
|
+
// Keep the worst instance as the example so a follow-up trace lands
|
|
137
|
+
// on a representative object rather than the first one scanned.
|
|
138
|
+
const waste = holeSlots + slackSlots;
|
|
139
|
+
const exampleWaste = group.exampleSpan -
|
|
140
|
+
group.exampleUsed +
|
|
141
|
+
Math.max(0, group.exampleCapacity - group.exampleSpan - FORGIVEN_TAIL_SLOTS);
|
|
142
|
+
if (waste > exampleWaste) {
|
|
143
|
+
group.exampleId = node.id;
|
|
144
|
+
group.exampleCapacity = capacity;
|
|
145
|
+
group.exampleUsed = rawUsed;
|
|
146
|
+
group.exampleSpan = span;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const ranked = [...groups.values()]
|
|
150
|
+
.map(g => ({ g, waste: (g.holeSlots + g.slackSlots) * slotBytes }))
|
|
151
|
+
.filter(r => r.waste >= min_group_bytes)
|
|
152
|
+
.sort((a, b) => b.waste - a.waste);
|
|
153
|
+
const dropped = groups.size - ranked.length;
|
|
154
|
+
const shown = ranked.slice(0, limit);
|
|
155
|
+
const totalWaste = ranked.reduce((sum, r) => sum + r.waste, 0);
|
|
156
|
+
const lines = [
|
|
157
|
+
'## Sparse elements backing stores',
|
|
158
|
+
'',
|
|
159
|
+
`Scanned ${formatNumber(index.count)} objects with an elements store; ${formatNumber(examined)} were dense and at least ${formatNumber(min_capacity)} slots. Slot width calibrated to **${slotBytes} bytes** (${slotBytes === 4 ? 'pointer-compressed' : 'uncompressed'} heap).`,
|
|
160
|
+
'',
|
|
161
|
+
];
|
|
162
|
+
if (shown.length === 0) {
|
|
163
|
+
lines.push(`No group wastes ${formatBytes(min_group_bytes)} or more. Lower \`min_group_bytes\`, raise \`max_occupancy\`, or lower \`min_capacity\` to widen the scan.`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
lines.push(`**${formatBytes(totalWaste)}** of unused slots across ${formatNumber(ranked.length)} owner group(s)${dropped > 0 ? `; ${formatNumber(dropped)} smaller group(s) below the ${formatBytes(min_group_bytes)} floor were dropped` : ''}.`, '', markdownTable([
|
|
167
|
+
'Owner',
|
|
168
|
+
'Class',
|
|
169
|
+
'Count',
|
|
170
|
+
'Slots used / cap',
|
|
171
|
+
'Holes',
|
|
172
|
+
'Slack',
|
|
173
|
+
'Wasted',
|
|
174
|
+
], shown.map(({ g, waste }) => [
|
|
175
|
+
g.ring ? `${g.key} (ring)` : g.key,
|
|
176
|
+
g.className,
|
|
177
|
+
formatNumber(g.count),
|
|
178
|
+
`${formatNumber(g.used)} / ${formatNumber(g.capacity)} (${Math.round((g.used / g.capacity) * 100)}%)`,
|
|
179
|
+
formatBytes(g.holeSlots * slotBytes),
|
|
180
|
+
formatBytes(g.slackSlots * slotBytes),
|
|
181
|
+
formatBytes(waste),
|
|
182
|
+
]), new Set([2, 3, 4, 5, 6])), '', '### What to do about each', '');
|
|
183
|
+
for (const { g, waste } of shown) {
|
|
184
|
+
lines.push(`- **${g.key}** — ${formatBytes(waste)} across ${formatNumber(g.count)} instance(s). ${diagnose(g)}. Worst example \`@${g.exampleId}\`: ${formatNumber(g.exampleUsed)} value(s) spread over ${formatNumber(g.exampleSpan)} slot(s) in a ${formatNumber(g.exampleCapacity)}-slot store.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// The per-call NUMBERS stay; the standing EXPLANATION of what
|
|
188
|
+
// "unmeasurable" and "dictionary-mode" mean is the same paragraph every
|
|
189
|
+
// call and is a third of this tool's output. Printed in full once per
|
|
190
|
+
// session, then pointed at (memlab_snapshots({repeat_notes:true})
|
|
191
|
+
// brings it back).
|
|
192
|
+
const longCaveats = shouldEmitNote('sparse-elements:caveats');
|
|
193
|
+
lines.push('', '### Coverage and caveats', '', longCaveats
|
|
194
|
+
? `- ${formatNumber(unmeasurable)} store(s) holding ${formatBytes(unmeasurableBytes)} were skipped as UNMEASURABLE: a slot holding a small integer emits no edge a snapshot can see, so an array of numbers and an array of holes are indistinguishable. Anything storing only numbers is therefore invisible to this tool — not absent from it.`
|
|
195
|
+
: `- UNMEASURABLE (all-SMI or all-hole): ${formatNumber(unmeasurable)} store(s), ${formatBytes(unmeasurableBytes)}.`, longCaveats
|
|
196
|
+
? `- ${formatNumber(dictionaries)} store(s) were dictionary-mode (keys past the dense capacity), where holes cost nothing and are correctly not reported.`
|
|
197
|
+
: `- Dictionary-mode (excluded): ${formatNumber(dictionaries)} store(s).`, ...(longCaveats
|
|
198
|
+
? [
|
|
199
|
+
`- Occupancy is a LOWER bound and waste an UPPER bound for the same reason: a store mixing numbers and objects reads as emptier than it is.`,
|
|
200
|
+
`- Up to ${formatNumber(FORGIVEN_TAIL_SLOTS)} tail slots per instance are forgiven — that is V8’s minimum growth increment, not something the application can give back.`,
|
|
201
|
+
]
|
|
202
|
+
: [
|
|
203
|
+
`- Occupancy is a lower bound; ${formatNumber(FORGIVEN_TAIL_SLOTS)} tail slots per instance are forgiven. _(Full explanation printed once per session — memlab_snapshots({repeat_notes: true}) to see it again.)_`,
|
|
204
|
+
]));
|
|
205
|
+
if (!suggestionsSuppressed() && shown.length > 0) {
|
|
206
|
+
lines.push('', '**Suggested next steps**', `- \`memlab_retainer_trace({node_id: ${shown[0].g.exampleId}})\` — confirm the owner label against the real path.`, `- \`memlab_get_references({node_id: ${shown[0].g.exampleId}})\` — read the actual key layout that produced the holes.`);
|
|
207
|
+
}
|
|
208
|
+
return toolResult(lines.join('\n'));
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
return errorResult(err);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=sparse-elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparse-elements.js","sourceRoot":"","sources":["../../src/tools/sparse-elements.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,5 +8,22 @@
|
|
|
8
8
|
* @oncall memory_lab
|
|
9
9
|
*/
|
|
10
10
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
/**
|
|
12
|
+
* What to say when the scan surfaced nothing.
|
|
13
|
+
*
|
|
14
|
+
* A scan that ran out of budget found nothing YET. Emitting "No stale
|
|
15
|
+
* collections found" over a partial scan states a negative the tool never
|
|
16
|
+
* established — and the verdict is the line a reader keeps, so the PARTIAL
|
|
17
|
+
* warning printed above it does not undo the impression. Measured output that
|
|
18
|
+
* prompted this:
|
|
19
|
+
*
|
|
20
|
+
* ⚠ Scan hit the 45,000ms time budget after 22,528 entries — results are PARTIAL.
|
|
21
|
+
* No stale collections found.
|
|
22
|
+
*
|
|
23
|
+
* The two lines contradict each other. This is precisely the UNANALYZED-vs-
|
|
24
|
+
* no-leak distinction the analysis protocol exists to enforce, so the tool must
|
|
25
|
+
* not blur it in its own output.
|
|
26
|
+
*/
|
|
27
|
+
export declare function emptyScanVerdict(timedOut: boolean, scanned: number): string;
|
|
11
28
|
export declare function registerStaleCollections(server: McpServer): void;
|
|
12
29
|
//# sourceMappingURL=stale-collections.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stale-collections.d.ts","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAoKvE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"stale-collections.d.ts","sourceRoot":"","sources":["../../src/tools/stale-collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAoKvE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS3E;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoQhE"}
|