memorydetective 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -1
- package/LICENSE +201 -21
- package/NOTICE +19 -0
- package/README.md +15 -11
- package/USAGE.md +259 -0
- package/dist/cli.js +49 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers/shortenClassName.d.ts +45 -0
- package/dist/parsers/shortenClassName.js +155 -0
- package/dist/parsers/shortenClassName.js.map +1 -0
- package/dist/tools/analyzeMemgraph.d.ts +11 -2
- package/dist/tools/analyzeMemgraph.js +37 -9
- package/dist/tools/analyzeMemgraph.js.map +1 -1
- package/dist/tools/findCycles.d.ts +6 -2
- package/dist/tools/findCycles.js +11 -6
- package/dist/tools/findCycles.js.map +1 -1
- package/dist/tools/reachableFromCycle.d.ts +61 -0
- package/dist/tools/reachableFromCycle.js +116 -0
- package/dist/tools/reachableFromCycle.js.map +1 -0
- package/dist/tools/renderCycleGraph.d.ts +1 -1
- package/package.json +5 -3
package/dist/tools/findCycles.js
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { resolve as resolvePath } from "node:path";
|
|
4
4
|
import { runCommand } from "../runtime/exec.js";
|
|
5
5
|
import { parseLeaksOutput, rootCyclesOnly, walkCycles, } from "../parsers/leaksOutput.js";
|
|
6
|
+
import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
|
|
6
7
|
export const findCyclesSchema = z.object({
|
|
7
8
|
path: z.string().min(1).describe("Absolute path to a `.memgraph` file."),
|
|
8
9
|
className: z
|
|
@@ -15,8 +16,12 @@ export const findCyclesSchema = z.object({
|
|
|
15
16
|
.positive()
|
|
16
17
|
.default(10)
|
|
17
18
|
.describe("Truncate chains beyond this depth (default 10)."),
|
|
19
|
+
verbosity: z
|
|
20
|
+
.enum(["compact", "normal", "full"])
|
|
21
|
+
.default("compact")
|
|
22
|
+
.describe("Class-name verbosity. `compact` shortens SwiftUI generic names aggressively; `full` returns demangled names verbatim."),
|
|
18
23
|
});
|
|
19
|
-
function flattenChain(node, maxDepth) {
|
|
24
|
+
function flattenChain(node, maxDepth, verbosity) {
|
|
20
25
|
const out = [];
|
|
21
26
|
for (const { node: n, depth } of walkCycles([node])) {
|
|
22
27
|
if (depth > maxDepth)
|
|
@@ -25,7 +30,7 @@ function flattenChain(node, maxDepth) {
|
|
|
25
30
|
depth,
|
|
26
31
|
edge: n.edge,
|
|
27
32
|
retainKind: n.retainKind,
|
|
28
|
-
className: n.className,
|
|
33
|
+
className: shortenForVerbosity(n.className, verbosity),
|
|
29
34
|
address: n.address,
|
|
30
35
|
count: n.count,
|
|
31
36
|
size: n.size,
|
|
@@ -36,16 +41,16 @@ function flattenChain(node, maxDepth) {
|
|
|
36
41
|
return out;
|
|
37
42
|
}
|
|
38
43
|
/** Pure function: parse `leaks` output and return the cycles array. */
|
|
39
|
-
export function extractCycles(leaksText, path, filter, maxDepth = 10) {
|
|
44
|
+
export function extractCycles(leaksText, path, filter, maxDepth = 10, verbosity = "compact") {
|
|
40
45
|
const report = parseLeaksOutput(leaksText);
|
|
41
46
|
const roots = rootCyclesOnly(report.cycles);
|
|
42
47
|
const cycles = roots.map((c) => {
|
|
43
|
-
const chain = flattenChain(c, maxDepth);
|
|
48
|
+
const chain = flattenChain(c, maxDepth, verbosity);
|
|
44
49
|
const matched = filter
|
|
45
50
|
? chain.some((entry) => entry.className.includes(filter))
|
|
46
51
|
: true;
|
|
47
52
|
return {
|
|
48
|
-
rootClass: c.className,
|
|
53
|
+
rootClass: shortenForVerbosity(c.className, verbosity),
|
|
49
54
|
rootAddress: c.address,
|
|
50
55
|
count: c.count,
|
|
51
56
|
size: c.size,
|
|
@@ -73,6 +78,6 @@ export async function findCycles(input) {
|
|
|
73
78
|
if (result.code !== 0 && result.code !== 1) {
|
|
74
79
|
throw new Error(`leaks failed (code ${result.code}): ${result.stderr || result.stdout}`);
|
|
75
80
|
}
|
|
76
|
-
return extractCycles(result.stdout, path, input.className, input.maxDepth ?? 10);
|
|
81
|
+
return extractCycles(result.stdout, path, input.className, input.maxDepth ?? 10, input.verbosity ?? "compact");
|
|
77
82
|
}
|
|
78
83
|
//# sourceMappingURL=findCycles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findCycles.js","sourceRoot":"","sources":["../../src/tools/findCycles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,UAAU,GACX,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"findCycles.js","sourceRoot":"","sources":["../../src/tools/findCycles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { LeaksReport } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Cycle-scoped reachability + class counting.
|
|
5
|
+
*
|
|
6
|
+
* Answers questions like:
|
|
7
|
+
* "How many `NSURLSessionConfiguration` instances are reachable from the
|
|
8
|
+
* cycle rooted at `DetailViewModel`?"
|
|
9
|
+
*
|
|
10
|
+
* Where global `countAlive` would say "4495 NSURLSessionConfiguration", this
|
|
11
|
+
* tool says "1100 reachable from each of the 4 cycles, so the cycle root is
|
|
12
|
+
* the actual culprit pinning them in memory."
|
|
13
|
+
*
|
|
14
|
+
* API shape inspired by Meta's `memlab` predicate-based queries.
|
|
15
|
+
*/
|
|
16
|
+
export declare const reachableFromCycleSchema: z.ZodObject<{
|
|
17
|
+
path: z.ZodString;
|
|
18
|
+
cycleIndex: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
rootClassName: z.ZodOptional<z.ZodString>;
|
|
20
|
+
className: z.ZodOptional<z.ZodString>;
|
|
21
|
+
topN: z.ZodDefault<z.ZodNumber>;
|
|
22
|
+
verbosity: z.ZodDefault<z.ZodEnum<["compact", "normal", "full"]>>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
path: string;
|
|
25
|
+
verbosity: "compact" | "normal" | "full";
|
|
26
|
+
topN: number;
|
|
27
|
+
className?: string | undefined;
|
|
28
|
+
cycleIndex?: number | undefined;
|
|
29
|
+
rootClassName?: string | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
path: string;
|
|
32
|
+
className?: string | undefined;
|
|
33
|
+
verbosity?: "compact" | "normal" | "full" | undefined;
|
|
34
|
+
topN?: number | undefined;
|
|
35
|
+
cycleIndex?: number | undefined;
|
|
36
|
+
rootClassName?: string | undefined;
|
|
37
|
+
}>;
|
|
38
|
+
export type ReachableFromCycleInput = z.infer<typeof reachableFromCycleSchema>;
|
|
39
|
+
export interface ClassCount {
|
|
40
|
+
className: string;
|
|
41
|
+
count: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ReachableFromCycleResult {
|
|
44
|
+
ok: boolean;
|
|
45
|
+
path: string;
|
|
46
|
+
/** The cycle that was scoped to. */
|
|
47
|
+
cycle: {
|
|
48
|
+
index: number;
|
|
49
|
+
rootClass: string;
|
|
50
|
+
rootAddress: string;
|
|
51
|
+
/** Total reachable nodes from this cycle root (including descendants). */
|
|
52
|
+
totalReachable: number;
|
|
53
|
+
};
|
|
54
|
+
/** When `className` filter is provided, only that class shows up. Otherwise top N. */
|
|
55
|
+
counts: ClassCount[];
|
|
56
|
+
/** Total unique classes in the cycle's reachable set. */
|
|
57
|
+
uniqueClasses: number;
|
|
58
|
+
}
|
|
59
|
+
/** Pure: compute the result from a parsed report. Exposed for testing. */
|
|
60
|
+
export declare function reachableFromReport(report: LeaksReport, path: string, input: ReachableFromCycleInput): ReachableFromCycleResult;
|
|
61
|
+
export declare function reachableFromCycle(input: ReachableFromCycleInput): Promise<ReachableFromCycleResult>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { runLeaksAndParse } from "../runtime/leaks.js";
|
|
3
|
+
import { rootCyclesOnly } from "../parsers/leaksOutput.js";
|
|
4
|
+
import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
|
|
5
|
+
/**
|
|
6
|
+
* Cycle-scoped reachability + class counting.
|
|
7
|
+
*
|
|
8
|
+
* Answers questions like:
|
|
9
|
+
* "How many `NSURLSessionConfiguration` instances are reachable from the
|
|
10
|
+
* cycle rooted at `DetailViewModel`?"
|
|
11
|
+
*
|
|
12
|
+
* Where global `countAlive` would say "4495 NSURLSessionConfiguration", this
|
|
13
|
+
* tool says "1100 reachable from each of the 4 cycles, so the cycle root is
|
|
14
|
+
* the actual culprit pinning them in memory."
|
|
15
|
+
*
|
|
16
|
+
* API shape inspired by Meta's `memlab` predicate-based queries.
|
|
17
|
+
*/
|
|
18
|
+
export const reachableFromCycleSchema = z.object({
|
|
19
|
+
path: z.string().min(1).describe("Absolute path to a `.memgraph` file."),
|
|
20
|
+
cycleIndex: z
|
|
21
|
+
.number()
|
|
22
|
+
.int()
|
|
23
|
+
.nonnegative()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Zero-based index of the ROOT CYCLE to scope to. Mutually exclusive with `rootClassName`. When neither is given, defaults to cycle index 0."),
|
|
26
|
+
rootClassName: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Substring of the root cycle's class name (e.g. \"DetailViewModel\"). Picks the first ROOT CYCLE whose root matches. Mutually exclusive with `cycleIndex`."),
|
|
30
|
+
className: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Optional filter — only count nodes whose className contains this substring. When omitted, returns the full per-class breakdown."),
|
|
34
|
+
topN: z
|
|
35
|
+
.number()
|
|
36
|
+
.int()
|
|
37
|
+
.positive()
|
|
38
|
+
.max(100)
|
|
39
|
+
.default(20)
|
|
40
|
+
.describe("Cap on per-class entries returned (default 20)."),
|
|
41
|
+
verbosity: z
|
|
42
|
+
.enum(["compact", "normal", "full"])
|
|
43
|
+
.default("compact")
|
|
44
|
+
.describe("Class-name verbosity for the response. See analyzeMemgraph for the same flag."),
|
|
45
|
+
});
|
|
46
|
+
/** Pure: walk the tree from root, count nodes by className. */
|
|
47
|
+
function countReachableFromNode(root, verbosity) {
|
|
48
|
+
const counts = new Map();
|
|
49
|
+
let total = 0;
|
|
50
|
+
const visit = (n) => {
|
|
51
|
+
total += 1;
|
|
52
|
+
if (n.className) {
|
|
53
|
+
const short = shortenForVerbosity(n.className, verbosity);
|
|
54
|
+
counts.set(short, (counts.get(short) ?? 0) + 1);
|
|
55
|
+
}
|
|
56
|
+
for (const child of n.children)
|
|
57
|
+
visit(child);
|
|
58
|
+
};
|
|
59
|
+
visit(root);
|
|
60
|
+
return { byClass: counts, total };
|
|
61
|
+
}
|
|
62
|
+
function pickCycle(report, input) {
|
|
63
|
+
const roots = rootCyclesOnly(report.cycles);
|
|
64
|
+
if (roots.length === 0)
|
|
65
|
+
return null;
|
|
66
|
+
if (input.rootClassName) {
|
|
67
|
+
const idx = roots.findIndex((r) => r.className.includes(input.rootClassName));
|
|
68
|
+
if (idx >= 0)
|
|
69
|
+
return { node: roots[idx], index: idx };
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const idx = input.cycleIndex ?? 0;
|
|
73
|
+
if (idx >= roots.length)
|
|
74
|
+
return null;
|
|
75
|
+
return { node: roots[idx], index: idx };
|
|
76
|
+
}
|
|
77
|
+
/** Pure: compute the result from a parsed report. Exposed for testing. */
|
|
78
|
+
export function reachableFromReport(report, path, input) {
|
|
79
|
+
const picked = pickCycle(report, input);
|
|
80
|
+
if (!picked) {
|
|
81
|
+
throw new Error(input.rootClassName
|
|
82
|
+
? `No ROOT CYCLE found whose root class contains "${input.rootClassName}".`
|
|
83
|
+
: `No ROOT CYCLE at index ${input.cycleIndex ?? 0}. Available roots: ${rootCyclesOnly(report.cycles).length}.`);
|
|
84
|
+
}
|
|
85
|
+
const verbosity = input.verbosity ?? "compact";
|
|
86
|
+
const { byClass, total } = countReachableFromNode(picked.node, verbosity);
|
|
87
|
+
let entries = Array.from(byClass.entries()).map(([n, c]) => ({
|
|
88
|
+
className: n,
|
|
89
|
+
count: c,
|
|
90
|
+
}));
|
|
91
|
+
if (input.className) {
|
|
92
|
+
entries = entries.filter((e) => e.className.includes(input.className));
|
|
93
|
+
}
|
|
94
|
+
entries.sort((a, b) => b.count - a.count);
|
|
95
|
+
entries = entries.slice(0, input.topN ?? 20);
|
|
96
|
+
return {
|
|
97
|
+
ok: true,
|
|
98
|
+
path,
|
|
99
|
+
cycle: {
|
|
100
|
+
index: picked.index,
|
|
101
|
+
rootClass: shortenForVerbosity(picked.node.className, verbosity),
|
|
102
|
+
rootAddress: picked.node.address,
|
|
103
|
+
totalReachable: total,
|
|
104
|
+
},
|
|
105
|
+
counts: entries,
|
|
106
|
+
uniqueClasses: byClass.size,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export async function reachableFromCycle(input) {
|
|
110
|
+
if (input.cycleIndex !== undefined && input.rootClassName !== undefined) {
|
|
111
|
+
throw new Error("Provide either `cycleIndex` or `rootClassName`, not both.");
|
|
112
|
+
}
|
|
113
|
+
const { report, resolvedPath } = await runLeaksAndParse(input.path);
|
|
114
|
+
return reachableFromReport(report, resolvedPath, input);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=reachableFromCycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reachableFromCycle.js","sourceRoot":"","sources":["../../src/tools/reachableFromCycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@ export declare const renderCycleGraphSchema: z.ZodObject<{
|
|
|
7
7
|
maxDepth: z.ZodDefault<z.ZodNumber>;
|
|
8
8
|
truncateClassName: z.ZodDefault<z.ZodNumber>;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
path: string;
|
|
11
10
|
maxDepth: number;
|
|
11
|
+
path: string;
|
|
12
12
|
cycleIndex: number;
|
|
13
13
|
format: "mermaid" | "dot";
|
|
14
14
|
truncateClassName: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorydetective",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "MCP server for iOS leak hunting and performance investigation. Reads .memgraph + .trace files, captures new ones via xctrace and leaks(1), classifies retain cycles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md",
|
|
13
13
|
"LICENSE",
|
|
14
|
-
"
|
|
14
|
+
"NOTICE",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"USAGE.md"
|
|
15
17
|
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"build": "tsc && chmod +x dist/index.js",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
"performance"
|
|
35
37
|
],
|
|
36
38
|
"author": "Carlos Henrique",
|
|
37
|
-
"license": "
|
|
39
|
+
"license": "Apache-2.0",
|
|
38
40
|
"homepage": "https://github.com/carloshpdoc/memorydetective#readme",
|
|
39
41
|
"repository": {
|
|
40
42
|
"type": "git",
|