@memlab/mcp-server 2.18.1 → 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 +30 -16
- package/bin/.eslintrc.js +26 -0
- package/bin/memlab-cli.js +313 -0
- 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/artifact-classes.d.ts +86 -0
- package/dist/artifact-classes.d.ts.map +1 -0
- package/dist/artifact-classes.js +261 -0
- package/dist/artifact-classes.js.map +1 -0
- package/dist/capture-mode.d.ts +60 -0
- package/dist/capture-mode.d.ts.map +1 -0
- package/dist/capture-mode.js +39 -0
- package/dist/capture-mode.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/guardrail.d.ts.map +1 -1
- package/dist/guardrail.js +13 -0
- package/dist/guardrail.js.map +1 -1
- 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 +109 -2
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +194 -3
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +102 -1
- package/dist/index.js.map +1 -1
- package/dist/progress.d.ts +25 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +46 -0
- package/dist/progress.js.map +1 -0
- 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/result-handles.d.ts +11 -0
- package/dist/result-handles.d.ts.map +1 -0
- package/dist/result-handles.js +77 -0
- package/dist/result-handles.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 +55 -0
- package/dist/string-index.d.ts.map +1 -0
- package/dist/string-index.js +99 -0
- package/dist/string-index.js.map +1 -0
- package/dist/tool-registry.d.ts +42 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +20 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/analyze-run.d.ts +12 -0
- package/dist/tools/analyze-run.d.ts.map +1 -0
- package/dist/tools/analyze-run.js +404 -0
- package/dist/tools/analyze-run.js.map +1 -0
- 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 +30 -0
- package/dist/tools/app-heap.d.ts.map +1 -0
- package/dist/tools/app-heap.js +106 -0
- package/dist/tools/app-heap.js.map +1 -0
- 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 +12 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +196 -0
- package/dist/tools/batch.js.map +1 -0
- 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 +240 -14
- 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/class-histogram.d.ts.map +1 -1
- package/dist/tools/class-histogram.js +14 -3
- package/dist/tools/class-histogram.js.map +1 -1
- 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 +55 -0
- package/dist/tools/collection-trend.d.ts.map +1 -0
- package/dist/tools/collection-trend.js +315 -0
- package/dist/tools/collection-trend.js.map +1 -0
- package/dist/tools/detached-dom.d.ts +5 -0
- package/dist/tools/detached-dom.d.ts.map +1 -1
- package/dist/tools/detached-dom.js +368 -22
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/dev-artifacts.d.ts +62 -6
- package/dist/tools/dev-artifacts.d.ts.map +1 -1
- package/dist/tools/dev-artifacts.js +685 -24
- 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/dominator-attribution.d.ts +12 -0
- package/dist/tools/dominator-attribution.d.ts.map +1 -0
- package/dist/tools/dominator-attribution.js +189 -0
- package/dist/tools/dominator-attribution.js.map +1 -0
- package/dist/tools/dominator-chain.d.ts +12 -0
- package/dist/tools/dominator-chain.d.ts.map +1 -0
- package/dist/tools/dominator-chain.js +92 -0
- package/dist/tools/dominator-chain.js.map +1 -0
- package/dist/tools/duplicate-objects.d.ts +12 -0
- package/dist/tools/duplicate-objects.d.ts.map +1 -0
- package/dist/tools/duplicate-objects.js +172 -0
- package/dist/tools/duplicate-objects.js.map +1 -0
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +49 -40
- 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 +79 -0
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +2523 -197
- 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 +12 -0
- package/dist/tools/explain-delta.d.ts.map +1 -0
- package/dist/tools/explain-delta.js +221 -0
- package/dist/tools/explain-delta.js.map +1 -0
- package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
- package/dist/tools/find-nodes-by-class.js +112 -13
- package/dist/tools/find-nodes-by-class.js.map +1 -1
- package/dist/tools/finding-index.d.ts +203 -0
- package/dist/tools/finding-index.d.ts.map +1 -0
- package/dist/tools/finding-index.js +566 -0
- package/dist/tools/finding-index.js.map +1 -0
- package/dist/tools/for-each.d.ts.map +1 -1
- package/dist/tools/for-each.js +15 -3
- package/dist/tools/for-each.js.map +1 -1
- package/dist/tools/get-referrers.d.ts.map +1 -1
- package/dist/tools/get-referrers.js +17 -0
- package/dist/tools/get-referrers.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/hunt-report.d.ts +12 -0
- package/dist/tools/hunt-report.d.ts.map +1 -0
- package/dist/tools/hunt-report.js +186 -0
- package/dist/tools/hunt-report.js.map +1 -0
- package/dist/tools/hypothesis.d.ts +12 -0
- package/dist/tools/hypothesis.d.ts.map +1 -0
- package/dist/tools/hypothesis.js +280 -0
- package/dist/tools/hypothesis.js.map +1 -0
- 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 +116 -50
- 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 +33 -0
- package/dist/tools/ladder.d.ts.map +1 -0
- package/dist/tools/ladder.js +266 -0
- package/dist/tools/ladder.js.map +1 -0
- package/dist/tools/largest-objects.d.ts.map +1 -1
- package/dist/tools/largest-objects.js +6 -2
- package/dist/tools/largest-objects.js.map +1 -1
- package/dist/tools/leak-report.d.ts +35 -0
- package/dist/tools/leak-report.d.ts.map +1 -0
- package/dist/tools/leak-report.js +398 -0
- package/dist/tools/leak-report.js.map +1 -0
- package/dist/tools/load-snapshot.d.ts +29 -0
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +294 -23
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/map-entries.d.ts +12 -0
- package/dist/tools/map-entries.d.ts.map +1 -0
- package/dist/tools/map-entries.js +139 -0
- package/dist/tools/map-entries.js.map +1 -0
- package/dist/tools/match-object.d.ts +12 -0
- package/dist/tools/match-object.d.ts.map +1 -0
- package/dist/tools/match-object.js +165 -0
- package/dist/tools/match-object.js.map +1 -0
- 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/object-shape.d.ts.map +1 -1
- package/dist/tools/object-shape.js +53 -5
- package/dist/tools/object-shape.js.map +1 -1
- package/dist/tools/population-diff.d.ts +57 -0
- package/dist/tools/population-diff.d.ts.map +1 -0
- package/dist/tools/population-diff.js +338 -0
- package/dist/tools/population-diff.js.map +1 -0
- 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-layers.d.ts +23 -0
- package/dist/tools/retainer-layers.d.ts.map +1 -0
- package/dist/tools/retainer-layers.js +179 -0
- package/dist/tools/retainer-layers.js.map +1 -0
- package/dist/tools/retainer-summary.d.ts +18 -0
- package/dist/tools/retainer-summary.d.ts.map +1 -1
- package/dist/tools/retainer-summary.js +210 -51
- 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 +14 -2
- 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/search-nodes.d.ts.map +1 -1
- package/dist/tools/search-nodes.js +5 -1
- package/dist/tools/search-nodes.js.map +1 -1
- package/dist/tools/search-strings.d.ts.map +1 -1
- package/dist/tools/search-strings.js +53 -7
- package/dist/tools/search-strings.js.map +1 -1
- package/dist/tools/sequence-analysis.d.ts +53 -0
- package/dist/tools/sequence-analysis.d.ts.map +1 -1
- package/dist/tools/sequence-analysis.js +313 -89
- 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/shape-histogram.d.ts.map +1 -1
- package/dist/tools/shape-histogram.js +9 -2
- package/dist/tools/shape-histogram.js.map +1 -1
- 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 +7 -5
- package/dist/tools/string-patterns.js.map +1 -1
- package/dist/tools/tools-index.d.ts +12 -0
- package/dist/tools/tools-index.d.ts.map +1 -0
- package/dist/tools/tools-index.js +492 -0
- package/dist/tools/tools-index.js.map +1 -0
- 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 +23 -0
- package/dist/tools/verify-fix.d.ts.map +1 -0
- package/dist/tools/verify-fix.js +219 -0
- package/dist/tools/verify-fix.js.map +1 -0
- package/dist/tools/weakmap-entries.d.ts.map +1 -1
- package/dist/tools/weakmap-entries.js +6 -1
- package/dist/tools/weakmap-entries.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 +238 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +507 -15
- package/dist/utils.js.map +1 -1
- package/package.json +7 -6
package/dist/guardrail.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { beginAnalysisBudget, endAnalysisBudget, getAnalysisTimeoutMs, activeElapsedMs, ScanTimeoutError, } from './analysis-budget.js';
|
|
11
11
|
import { toolResult } from './utils.js';
|
|
12
|
+
import { recordToolHandler } from './tool-registry.js';
|
|
12
13
|
/**
|
|
13
14
|
* Install a process-wide wall-clock guardrail around every tool call.
|
|
14
15
|
*
|
|
@@ -29,6 +30,18 @@ export function installAnalysisGuardrail(server) {
|
|
|
29
30
|
const handler = toolArgs[lastIdx];
|
|
30
31
|
if (typeof handler === 'function') {
|
|
31
32
|
const inner = handler;
|
|
33
|
+
// Index the raw handler plus its zod shape so tools can dispatch to each
|
|
34
|
+
// other in-process without re-entering the budget, and without losing the
|
|
35
|
+
// schema defaults the SDK would normally apply (see tool-registry.ts).
|
|
36
|
+
// Registration is tool(name, description?, shape?, handler): the shape is
|
|
37
|
+
// whatever plain object sits immediately before the handler.
|
|
38
|
+
const maybeShape = lastIdx > 0 ? toolArgs[lastIdx - 1] : undefined;
|
|
39
|
+
const shape = maybeShape != null &&
|
|
40
|
+
typeof maybeShape === 'object' &&
|
|
41
|
+
!Array.isArray(maybeShape)
|
|
42
|
+
? maybeShape
|
|
43
|
+
: null;
|
|
44
|
+
recordToolHandler(name, inner, shape);
|
|
32
45
|
toolArgs[lastIdx] = async (...hArgs) => {
|
|
33
46
|
// The SDK calls handler(args, extra) for schema tools, handler(extra)
|
|
34
47
|
// otherwise. Read an optional per-call timeout_ms off the params.
|
package/dist/guardrail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guardrail.js","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"guardrail.js","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
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 { IHeapSnapshot } from '@memlab/core';
|
|
11
|
+
import type { ArtifactKind } from './artifact-classes.js';
|
|
12
|
+
import type { DevOnlyTotals, DevRootCategory } from './tools/dev-artifacts.js';
|
|
13
|
+
export interface HeapBudget {
|
|
14
|
+
total: number;
|
|
15
|
+
app: number;
|
|
16
|
+
appNodes: number;
|
|
17
|
+
bundle: number;
|
|
18
|
+
code: number;
|
|
19
|
+
devOnly: number;
|
|
20
|
+
artifact: number;
|
|
21
|
+
/** Known-artifact self bytes split by family (warmup / ax / cdp-* / …). */
|
|
22
|
+
artifactByKind: Map<ArtifactKind, number>;
|
|
23
|
+
/** Dev-only totals split by root family, or null when no dev roots exist. */
|
|
24
|
+
devOnlyTotals: DevOnlyTotals | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function computeHeapBudget(snapshot: IHeapSnapshot): HeapBudget;
|
|
27
|
+
export declare function devFamilyBytes(budget: HeapBudget): Array<{
|
|
28
|
+
family: DevRootCategory;
|
|
29
|
+
nodes: number;
|
|
30
|
+
selfBytes: number;
|
|
31
|
+
}>;
|
|
32
|
+
//# sourceMappingURL=heap-budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heap-budget.d.ts","sourceRoot":"","sources":["../src/heap-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAY,aAAa,EAAC,MAAM,cAAc,CAAC;AAE3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAMxD,OAAO,KAAK,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,0BAA0B,CAAC;AAmB7E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,cAAc,EAAE,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,GAAG,UAAU,CA2DrE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,GACjB,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAAC,CAapE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
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 { classifyArtifact } from './artifact-classes.js';
|
|
11
|
+
import { collectDevRoots, computeReachableWithoutDevRoots, summarizeDevOnly, } from './tools/dev-artifacts.js';
|
|
12
|
+
/**
|
|
13
|
+
* The one bucket split of a heap into "app" and the several distinct reasons a
|
|
14
|
+
* byte might not be the app.
|
|
15
|
+
*
|
|
16
|
+
* Extracted so `memlab_app_heap` and `memlab_artifact_budget` cannot drift: they
|
|
17
|
+
* are two views of the same partition, and two implementations of "what counts
|
|
18
|
+
* as the app" that disagree by a few percent is worse than either one alone,
|
|
19
|
+
* because the disagreement is invisible in each tool's own output.
|
|
20
|
+
*/
|
|
21
|
+
const CODE_TYPES = new Set(['code']);
|
|
22
|
+
// Bundle source text and the V8 structures that hold it. These exist because
|
|
23
|
+
// the app was *loaded*, not because it did anything.
|
|
24
|
+
const BUNDLE_NAME_RE = /ExternalStringData|InstructionStream|BytecodeArray|SharedFunctionInfo|ScopeInfo|UncompiledData|FeedbackVector|FeedbackMetadata|FeedbackCell|ClosureFeedbackCellArray|\(constant pool\)|ConstantPool/;
|
|
25
|
+
export function computeHeapBudget(snapshot) {
|
|
26
|
+
const devRoots = collectDevRoots(snapshot);
|
|
27
|
+
const reached = devRoots.byId.size > 0
|
|
28
|
+
? computeReachableWithoutDevRoots(snapshot, devRoots)
|
|
29
|
+
: null;
|
|
30
|
+
let total = 0;
|
|
31
|
+
let code = 0;
|
|
32
|
+
let bundle = 0;
|
|
33
|
+
let devOnly = 0;
|
|
34
|
+
let artifact = 0;
|
|
35
|
+
let app = 0;
|
|
36
|
+
let appNodes = 0;
|
|
37
|
+
const artifactByKind = new Map();
|
|
38
|
+
const isDevOnly = (node) => reached != null && reached[node.nodeIndex] === 0;
|
|
39
|
+
snapshot.nodes.forEach((node) => {
|
|
40
|
+
if (node.id <= 3)
|
|
41
|
+
return;
|
|
42
|
+
const size = node.self_size;
|
|
43
|
+
total += size;
|
|
44
|
+
// Precedence matters: a node is counted once, in the most specific bucket
|
|
45
|
+
// that explains why it is NOT app memory.
|
|
46
|
+
if (isDevOnly(node)) {
|
|
47
|
+
devOnly += size;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (CODE_TYPES.has(node.type)) {
|
|
51
|
+
code += size;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (BUNDLE_NAME_RE.test(node.name)) {
|
|
55
|
+
bundle += size;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const kind = classifyArtifact(node.name);
|
|
59
|
+
if (kind != null) {
|
|
60
|
+
artifact += size;
|
|
61
|
+
artifactByKind.set(kind, (artifactByKind.get(kind) ?? 0) + size);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
app += size;
|
|
65
|
+
appNodes++;
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
total,
|
|
69
|
+
app,
|
|
70
|
+
appNodes,
|
|
71
|
+
bundle,
|
|
72
|
+
code,
|
|
73
|
+
devOnly,
|
|
74
|
+
artifact,
|
|
75
|
+
artifactByKind,
|
|
76
|
+
devOnlyTotals: reached != null ? summarizeDevOnly(snapshot, devRoots, reached) : null,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function devFamilyBytes(budget) {
|
|
80
|
+
const out = [];
|
|
81
|
+
const byCategory = budget.devOnlyTotals?.byCategory;
|
|
82
|
+
if (byCategory == null)
|
|
83
|
+
return out;
|
|
84
|
+
for (const [family, v] of byCategory) {
|
|
85
|
+
out.push({ family, nodes: v.nodes, selfBytes: v.selfBytes });
|
|
86
|
+
}
|
|
87
|
+
out.sort((a, b) => b.selfBytes - a.selfBytes);
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=heap-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heap-budget.js","sourceRoot":"","sources":["../src/heap-budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* V8 elements-backing-store primitives, in one place.
|
|
12
|
+
*
|
|
13
|
+
* Reading an object's elements store correctly needs five separate facts, and
|
|
14
|
+
* each of them was got WRONG once before it was got right. They are stated here
|
|
15
|
+
* so no tool has to rediscover them:
|
|
16
|
+
*
|
|
17
|
+
* 1. A plain `Object` with integer keys emits an `element` edge per non-hole
|
|
18
|
+
* slot ON THE OWNER, small-integer values included (they point at a shared
|
|
19
|
+
* `smi number` node).
|
|
20
|
+
* 2. A `JSArray` frequently emits nothing on the owner and instead emits
|
|
21
|
+
* `internal` numeric edges ON THE STORE — but only for slots holding a
|
|
22
|
+
* heap object, so an all-SMI array reads as empty from there.
|
|
23
|
+
* 3. Therefore, when both sides read zero the occupancy is UNKNOWABLE: a
|
|
24
|
+
* `new Array(34)` of holes and an array of 34 timestamps are byte-identical
|
|
25
|
+
* in a snapshot. Scoring those as empty ranked 4,301 all-SMI index arrays
|
|
26
|
+
* as the second-largest "finding" in one run.
|
|
27
|
+
* 4. Capacity is `(storeBytes - 8) / slotBytes`, and `slotBytes` must be
|
|
28
|
+
* MEASURED. Wrong by 2x, it either invents slack that does not exist or
|
|
29
|
+
* classifies every dense store as a dictionary.
|
|
30
|
+
* 5. `maxIndex + 1 > capacity` means dictionary mode, where a hole costs
|
|
31
|
+
* nothing and "waste" is not defined.
|
|
32
|
+
*/
|
|
33
|
+
import type { IHeapNode, IHeapSnapshot } from '@memlab/core';
|
|
34
|
+
/**
|
|
35
|
+
* Bytes of the FixedArray header preceding the first slot. Same on a
|
|
36
|
+
* pointer-compressed and an uncompressed heap (map + length), so only the slot
|
|
37
|
+
* width has to be calibrated.
|
|
38
|
+
*/
|
|
39
|
+
export declare const STORE_HEADER_BYTES = 8;
|
|
40
|
+
/**
|
|
41
|
+
* V8 grows an elements store to `n + (n >> 1) + kMinAddedElementsCapacity`,
|
|
42
|
+
* with `kMinAddedElementsCapacity == 16`, so EVERY array built by `push`
|
|
43
|
+
* carries up to 16 slots of tail slack no application change can remove.
|
|
44
|
+
* Charging it turns a one-element array into a "94% empty" finding.
|
|
45
|
+
*
|
|
46
|
+
* https://github.com/v8/v8/blob/main/src/objects/js-objects.h
|
|
47
|
+
*/
|
|
48
|
+
export declare const FORGIVEN_TAIL_SLOTS = 16;
|
|
49
|
+
export type SlotBytes = 4 | 8;
|
|
50
|
+
export interface ElementsInfo {
|
|
51
|
+
storeId: number;
|
|
52
|
+
storeBytes: number;
|
|
53
|
+
slotBytes: SlotBytes;
|
|
54
|
+
/** Slots the backing store is sized for. */
|
|
55
|
+
capacity: number;
|
|
56
|
+
/** Slots holding a value. LOWER BOUND — see fact 3 above. */
|
|
57
|
+
used: number;
|
|
58
|
+
maxIndex: number;
|
|
59
|
+
/** `maxIndex + 1` — how far into the store the written keys reach. */
|
|
60
|
+
span: number;
|
|
61
|
+
/** Interior holes: written keys are sparse within their own span. */
|
|
62
|
+
holes: number;
|
|
63
|
+
/** Raw tail slack past the last written key, before any forgiveness. */
|
|
64
|
+
slack: number;
|
|
65
|
+
mode: 'dense' | 'dictionary';
|
|
66
|
+
/**
|
|
67
|
+
* `false` when nothing readable is in the store — it may be all holes or all
|
|
68
|
+
* small integers, and a snapshot cannot tell those apart. Callers must not
|
|
69
|
+
* count these as waste.
|
|
70
|
+
*/
|
|
71
|
+
measurable: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** The raw two-sided read, before capacity is derived from a slot width. */
|
|
74
|
+
export interface RawElements {
|
|
75
|
+
store: IHeapNode;
|
|
76
|
+
/** Union occupancy: the owner's element edges are a superset of the store's. */
|
|
77
|
+
used: number;
|
|
78
|
+
maxIndex: number;
|
|
79
|
+
}
|
|
80
|
+
/** Read a node's elements store and its occupancy, or `null` if it has none. */
|
|
81
|
+
export declare function readRawElements(node: IHeapNode): RawElements | null;
|
|
82
|
+
/**
|
|
83
|
+
* Decide the slot width from evidence rather than assumption.
|
|
84
|
+
*
|
|
85
|
+
* A store whose largest written index fits in `(bytes - 8) / 4` slots but NOT
|
|
86
|
+
* in `(bytes - 8) / 8` can only be 4-byte-slotted. Dictionary-mode stores
|
|
87
|
+
* overflow both, so they cannot fake the signal. Pass any collection of
|
|
88
|
+
* observed `(storeBytes, maxIndex)` pairs; one witness is enough, and a real
|
|
89
|
+
* browser capture produces thousands.
|
|
90
|
+
*/
|
|
91
|
+
export declare function calibrateSlotBytes(samples: Iterable<{
|
|
92
|
+
storeBytes: number;
|
|
93
|
+
maxIndex: number;
|
|
94
|
+
}>): SlotBytes;
|
|
95
|
+
/**
|
|
96
|
+
* Memoized per-snapshot slot width for tools that do not already make their own
|
|
97
|
+
* pass. Stops as soon as it has enough witnesses, so on a real heap it reads a
|
|
98
|
+
* small prefix rather than the whole graph.
|
|
99
|
+
*/
|
|
100
|
+
export declare function getSlotBytes(snapshot: IHeapSnapshot): SlotBytes;
|
|
101
|
+
/** Derive the full picture from a raw read and a slot width. */
|
|
102
|
+
export declare function describeElements(raw: RawElements, slotBytes: SlotBytes): ElementsInfo | null;
|
|
103
|
+
/**
|
|
104
|
+
* Every node that owns an elements store, as parallel typed arrays.
|
|
105
|
+
*
|
|
106
|
+
* Built once per snapshot and memoized. Four tools ask the same structural
|
|
107
|
+
* questions of the same nodes (does this own an elements store? how many
|
|
108
|
+
* element edges? what is the largest index? how big is the store?), and each
|
|
109
|
+
* was paying its own full pass — on a 7.1M-node / 41.7M-edge capture that is
|
|
110
|
+
* the dominant cost of the call, and tuning one tool's parameters re-pays it
|
|
111
|
+
* every time.
|
|
112
|
+
*
|
|
113
|
+
* Typed arrays rather than objects: on the capture above this is ~370k entries,
|
|
114
|
+
* which is 6 MB as four typed arrays and several times that as objects. The
|
|
115
|
+
* index is keyed by the snapshot, so a `keep_previous` A/B keeps one per arm and
|
|
116
|
+
* both are released when the snapshot is.
|
|
117
|
+
*/
|
|
118
|
+
export interface ElementsIndex {
|
|
119
|
+
/**
|
|
120
|
+
* Node ids that own an elements store, ascending by scan order.
|
|
121
|
+
*
|
|
122
|
+
* Unsigned: ids, byte counts and occupancies cannot be negative, and a
|
|
123
|
+
* signed 32-bit lane wraps anything past 2^31-1 to a negative number. For
|
|
124
|
+
* `ownerIds` that failure is silent rather than loud — `getNodeById(-…)`
|
|
125
|
+
* returns null, so the entry is skipped by every consumer instead of
|
|
126
|
+
* throwing. `maxIndex` stays signed because -1 is its "the store holds no
|
|
127
|
+
* numeric slot" sentinel, and a real element index above 2^31-1 would need a
|
|
128
|
+
* sparse array indexed past two billion.
|
|
129
|
+
*
|
|
130
|
+
* The unsigned lanes have their own ceiling at 2^32-1, and it is assumed
|
|
131
|
+
* rather than checked: V8 hands out snapshot node ids by increment, so
|
|
132
|
+
* exceeding it means one isolate allocated over four billion objects — far
|
|
133
|
+
* past the point where the snapshot itself is loadable here. A capture that
|
|
134
|
+
* did would truncate an id and quietly drop that entry, so if this ever needs
|
|
135
|
+
* to hold arbitrarily large captures, widen to `Float64Array` (ids stay exact
|
|
136
|
+
* to 2^53) rather than adding a guard.
|
|
137
|
+
*/
|
|
138
|
+
ownerIds: Uint32Array;
|
|
139
|
+
storeBytes: Uint32Array;
|
|
140
|
+
used: Uint32Array;
|
|
141
|
+
maxIndex: Int32Array;
|
|
142
|
+
slotBytes: SlotBytes;
|
|
143
|
+
count: number;
|
|
144
|
+
}
|
|
145
|
+
export declare function getElementsIndex(snapshot: IHeapSnapshot): ElementsIndex;
|
|
146
|
+
/** One-shot read for a single node, calibrating the snapshot if needed. */
|
|
147
|
+
export declare function readElements(snapshot: IHeapSnapshot, node: IHeapNode): ElementsInfo | null;
|
|
148
|
+
//# sourceMappingURL=heap-shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heap-shapes.d.ts","sourceRoot":"","sources":["../src/heap-shapes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;AAE9B,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;IAC7B;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,IAAI,CA4BnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAAC,GACxD,SAAS,CAWX;AAOD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,CA6B/D;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,SAAS,GACnB,YAAY,GAAG,IAAI,CAmBrB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,WAAW,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,CA4CvE;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,SAAS,GACd,YAAY,GAAG,IAAI,CAIrB"}
|
|
@@ -0,0 +1,193 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* Bytes of the FixedArray header preceding the first slot. Same on a
|
|
12
|
+
* pointer-compressed and an uncompressed heap (map + length), so only the slot
|
|
13
|
+
* width has to be calibrated.
|
|
14
|
+
*/
|
|
15
|
+
export const STORE_HEADER_BYTES = 8;
|
|
16
|
+
/**
|
|
17
|
+
* V8 grows an elements store to `n + (n >> 1) + kMinAddedElementsCapacity`,
|
|
18
|
+
* with `kMinAddedElementsCapacity == 16`, so EVERY array built by `push`
|
|
19
|
+
* carries up to 16 slots of tail slack no application change can remove.
|
|
20
|
+
* Charging it turns a one-element array into a "94% empty" finding.
|
|
21
|
+
*
|
|
22
|
+
* https://github.com/v8/v8/blob/main/src/objects/js-objects.h
|
|
23
|
+
*/
|
|
24
|
+
export const FORGIVEN_TAIL_SLOTS = 16;
|
|
25
|
+
/** Read a node's elements store and its occupancy, or `null` if it has none. */
|
|
26
|
+
export function readRawElements(node) {
|
|
27
|
+
let store = null;
|
|
28
|
+
let ownerSlots = 0;
|
|
29
|
+
let maxIndex = -1;
|
|
30
|
+
for (const edge of node.references) {
|
|
31
|
+
if (edge.type === 'element') {
|
|
32
|
+
ownerSlots++;
|
|
33
|
+
const index = Number(edge.name_or_index);
|
|
34
|
+
if (index > maxIndex)
|
|
35
|
+
maxIndex = index;
|
|
36
|
+
}
|
|
37
|
+
else if (edge.type === 'internal' &&
|
|
38
|
+
String(edge.name_or_index) === 'elements') {
|
|
39
|
+
store = edge.toNode;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!store)
|
|
43
|
+
return null;
|
|
44
|
+
let storeSlots = 0;
|
|
45
|
+
for (const edge of store.references) {
|
|
46
|
+
const name = String(edge.name_or_index);
|
|
47
|
+
// Numeric edge names on the store are slot indices; `map` and friends are
|
|
48
|
+
// header fields, not contents.
|
|
49
|
+
if (!/^\d+$/.test(name))
|
|
50
|
+
continue;
|
|
51
|
+
storeSlots++;
|
|
52
|
+
const index = Number(name);
|
|
53
|
+
if (index > maxIndex)
|
|
54
|
+
maxIndex = index;
|
|
55
|
+
}
|
|
56
|
+
return { store, used: Math.max(ownerSlots, storeSlots), maxIndex };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Decide the slot width from evidence rather than assumption.
|
|
60
|
+
*
|
|
61
|
+
* A store whose largest written index fits in `(bytes - 8) / 4` slots but NOT
|
|
62
|
+
* in `(bytes - 8) / 8` can only be 4-byte-slotted. Dictionary-mode stores
|
|
63
|
+
* overflow both, so they cannot fake the signal. Pass any collection of
|
|
64
|
+
* observed `(storeBytes, maxIndex)` pairs; one witness is enough, and a real
|
|
65
|
+
* browser capture produces thousands.
|
|
66
|
+
*/
|
|
67
|
+
export function calibrateSlotBytes(samples) {
|
|
68
|
+
for (const s of samples) {
|
|
69
|
+
const slots = s.maxIndex + 1;
|
|
70
|
+
if (slots <= 0)
|
|
71
|
+
continue;
|
|
72
|
+
const at8 = (s.storeBytes - STORE_HEADER_BYTES) / 8;
|
|
73
|
+
const at4 = (s.storeBytes - STORE_HEADER_BYTES) / 4;
|
|
74
|
+
if (slots > at8 && slots <= at4)
|
|
75
|
+
return 4;
|
|
76
|
+
}
|
|
77
|
+
// Default to 4: every browser capture is pointer-compressed, and a heap with
|
|
78
|
+
// no witness either way is one where the difference changes no ranking.
|
|
79
|
+
return 4;
|
|
80
|
+
}
|
|
81
|
+
/** Witnesses needed before the scan stops early; more than enough to be sure. */
|
|
82
|
+
const CALIBRATION_WITNESSES = 32;
|
|
83
|
+
const slotBytesBySnapshot = new WeakMap();
|
|
84
|
+
/**
|
|
85
|
+
* Memoized per-snapshot slot width for tools that do not already make their own
|
|
86
|
+
* pass. Stops as soon as it has enough witnesses, so on a real heap it reads a
|
|
87
|
+
* small prefix rather than the whole graph.
|
|
88
|
+
*/
|
|
89
|
+
export function getSlotBytes(snapshot) {
|
|
90
|
+
const cached = slotBytesBySnapshot.get(snapshot);
|
|
91
|
+
if (cached != null)
|
|
92
|
+
return cached;
|
|
93
|
+
const samples = [];
|
|
94
|
+
snapshot.nodes.forEach(node => {
|
|
95
|
+
// `false` is memlab's documented stop signal for this walk; a bare `return`
|
|
96
|
+
// only skips the current node, so returning undefined here kept iterating
|
|
97
|
+
// all 7M nodes of a large capture long after the 32nd witness. Every other
|
|
98
|
+
// `return` below is a per-node skip and must stay undefined.
|
|
99
|
+
if (samples.length >= CALIBRATION_WITNESSES)
|
|
100
|
+
return false;
|
|
101
|
+
if (node.type !== 'object' &&
|
|
102
|
+
node.type !== 'array' &&
|
|
103
|
+
node.type !== 'hidden')
|
|
104
|
+
return;
|
|
105
|
+
const raw = readRawElements(node);
|
|
106
|
+
if (!raw || raw.maxIndex < 0)
|
|
107
|
+
return;
|
|
108
|
+
const bytes = raw.store.self_size;
|
|
109
|
+
if (bytes <= STORE_HEADER_BYTES)
|
|
110
|
+
return;
|
|
111
|
+
const slots = raw.maxIndex + 1;
|
|
112
|
+
// Only witnesses that DISCRIMINATE are worth collecting.
|
|
113
|
+
if (slots > (bytes - STORE_HEADER_BYTES) / 8) {
|
|
114
|
+
samples.push({ storeBytes: bytes, maxIndex: raw.maxIndex });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const resolved = calibrateSlotBytes(samples);
|
|
118
|
+
slotBytesBySnapshot.set(snapshot, resolved);
|
|
119
|
+
return resolved;
|
|
120
|
+
}
|
|
121
|
+
/** Derive the full picture from a raw read and a slot width. */
|
|
122
|
+
export function describeElements(raw, slotBytes) {
|
|
123
|
+
const storeBytes = raw.store.self_size;
|
|
124
|
+
if (storeBytes <= STORE_HEADER_BYTES)
|
|
125
|
+
return null;
|
|
126
|
+
const capacity = Math.floor((storeBytes - STORE_HEADER_BYTES) / slotBytes);
|
|
127
|
+
const span = raw.maxIndex + 1;
|
|
128
|
+
const dictionary = span > capacity;
|
|
129
|
+
return {
|
|
130
|
+
storeId: raw.store.id,
|
|
131
|
+
storeBytes,
|
|
132
|
+
slotBytes,
|
|
133
|
+
capacity,
|
|
134
|
+
used: raw.used,
|
|
135
|
+
maxIndex: raw.maxIndex,
|
|
136
|
+
span,
|
|
137
|
+
holes: dictionary ? 0 : Math.max(0, span - raw.used),
|
|
138
|
+
slack: dictionary ? 0 : Math.max(0, capacity - span),
|
|
139
|
+
mode: dictionary ? 'dictionary' : 'dense',
|
|
140
|
+
measurable: raw.used > 0,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const elementsIndexBySnapshot = new WeakMap();
|
|
144
|
+
export function getElementsIndex(snapshot) {
|
|
145
|
+
const cached = elementsIndexBySnapshot.get(snapshot);
|
|
146
|
+
if (cached != null)
|
|
147
|
+
return cached;
|
|
148
|
+
const ownerIds = [];
|
|
149
|
+
const storeBytes = [];
|
|
150
|
+
const used = [];
|
|
151
|
+
const maxIndex = [];
|
|
152
|
+
snapshot.nodes.forEach(node => {
|
|
153
|
+
if (node.type !== 'object' &&
|
|
154
|
+
node.type !== 'array' &&
|
|
155
|
+
node.type !== 'hidden') {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const raw = readRawElements(node);
|
|
159
|
+
if (!raw)
|
|
160
|
+
return;
|
|
161
|
+
const bytes = raw.store.self_size;
|
|
162
|
+
if (bytes <= STORE_HEADER_BYTES)
|
|
163
|
+
return;
|
|
164
|
+
ownerIds.push(node.id);
|
|
165
|
+
storeBytes.push(bytes);
|
|
166
|
+
used.push(raw.used);
|
|
167
|
+
maxIndex.push(raw.maxIndex);
|
|
168
|
+
});
|
|
169
|
+
const index = {
|
|
170
|
+
ownerIds: Uint32Array.from(ownerIds),
|
|
171
|
+
storeBytes: Uint32Array.from(storeBytes),
|
|
172
|
+
used: Uint32Array.from(used),
|
|
173
|
+
maxIndex: Int32Array.from(maxIndex),
|
|
174
|
+
// Calibrating from the entries just collected costs nothing extra and is
|
|
175
|
+
// strictly better evidence than the early-exit prefix scan.
|
|
176
|
+
slotBytes: calibrateSlotBytes(ownerIds.map((_, i) => ({
|
|
177
|
+
storeBytes: storeBytes[i],
|
|
178
|
+
maxIndex: maxIndex[i],
|
|
179
|
+
}))),
|
|
180
|
+
count: ownerIds.length,
|
|
181
|
+
};
|
|
182
|
+
elementsIndexBySnapshot.set(snapshot, index);
|
|
183
|
+
slotBytesBySnapshot.set(snapshot, index.slotBytes);
|
|
184
|
+
return index;
|
|
185
|
+
}
|
|
186
|
+
/** One-shot read for a single node, calibrating the snapshot if needed. */
|
|
187
|
+
export function readElements(snapshot, node) {
|
|
188
|
+
const raw = readRawElements(node);
|
|
189
|
+
if (!raw)
|
|
190
|
+
return null;
|
|
191
|
+
return describeElements(raw, getSlotBytes(snapshot));
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=heap-shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heap-shapes.js","sourceRoot":"","sources":["../src/heap-shapes.ts"],"names":[],"mappings":"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"}
|