memorydetective 1.13.0 → 1.14.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 +33 -0
- package/README.md +6 -2
- package/USAGE.md +29 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers/schemaDiscovery.d.ts +88 -0
- package/dist/parsers/schemaDiscovery.js +144 -0
- package/dist/parsers/schemaDiscovery.js.map +1 -0
- package/dist/parsers/xctraceXml.d.ts +5 -0
- package/dist/parsers/xctraceXml.js +3 -0
- package/dist/parsers/xctraceXml.js.map +1 -1
- package/dist/tools/analyzeAllocations.d.ts +5 -1
- package/dist/tools/analyzeAllocations.js +17 -1
- package/dist/tools/analyzeAllocations.js.map +1 -1
- package/dist/tools/analyzeAnimationHitches.d.ts +5 -1
- package/dist/tools/analyzeAnimationHitches.js +17 -1
- package/dist/tools/analyzeAnimationHitches.js.map +1 -1
- package/dist/tools/analyzeAppLaunch.d.ts +3 -0
- package/dist/tools/analyzeAppLaunch.js +17 -1
- package/dist/tools/analyzeAppLaunch.js.map +1 -1
- package/dist/tools/analyzeHangs.d.ts +63 -3
- package/dist/tools/analyzeHangs.js +143 -19
- package/dist/tools/analyzeHangs.js.map +1 -1
- package/dist/tools/analyzeNetworkActivity.d.ts +99 -0
- package/dist/tools/analyzeNetworkActivity.js +312 -0
- package/dist/tools/analyzeNetworkActivity.js.map +1 -0
- package/dist/tools/analyzeTimeProfile.d.ts +10 -1
- package/dist/tools/analyzeTimeProfile.js +63 -8
- package/dist/tools/analyzeTimeProfile.js.map +1 -1
- package/dist/tools/countAlive.d.ts +35 -1
- package/dist/tools/countAlive.js +124 -29
- package/dist/tools/countAlive.js.map +1 -1
- package/dist/tools/inspectTrace.js +112 -18
- package/dist/tools/inspectTrace.js.map +1 -1
- package/dist/tools/recordTimeProfile.d.ts +83 -0
- package/dist/tools/recordTimeProfile.js +135 -0
- package/dist/tools/recordTimeProfile.js.map +1 -1
- package/dist/tools/replayScenario.d.ts +4 -4
- package/dist/tools/summarizeTrace.d.ts +2 -2
- package/dist/tools/verifyFix.d.ts +27 -0
- package/dist/tools/verifyFix.js +78 -4
- package/dist/tools/verifyFix.js.map +1 -1
- package/dist/types.d.ts +28 -0
- package/package.json +2 -2
|
@@ -5,16 +5,19 @@ export declare const countAliveSchema: z.ZodObject<{
|
|
|
5
5
|
className: z.ZodOptional<z.ZodString>;
|
|
6
6
|
topN: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
includeReferenceTree: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
sortBy: z.ZodDefault<z.ZodEnum<["count", "totalBytes"]>>;
|
|
8
9
|
}, "strip", z.ZodTypeAny, {
|
|
9
10
|
path: string;
|
|
10
11
|
topN: number;
|
|
11
12
|
includeReferenceTree: boolean;
|
|
13
|
+
sortBy: "count" | "totalBytes";
|
|
12
14
|
className?: string | undefined;
|
|
13
15
|
}, {
|
|
14
16
|
path: string;
|
|
15
17
|
className?: string | undefined;
|
|
16
18
|
topN?: number | undefined;
|
|
17
19
|
includeReferenceTree?: boolean | undefined;
|
|
20
|
+
sortBy?: "count" | "totalBytes" | undefined;
|
|
18
21
|
}>;
|
|
19
22
|
export type CountAliveInput = z.infer<typeof countAliveSchema>;
|
|
20
23
|
export interface CountAliveEntry {
|
|
@@ -24,6 +27,22 @@ export interface CountAliveEntry {
|
|
|
24
27
|
byCycle?: number;
|
|
25
28
|
/** When `includeReferenceTree: true`, the reference-tree contribution. Often the only non-zero side on `leakCount: 0` memgraphs. */
|
|
26
29
|
byReferenceTree?: number;
|
|
30
|
+
/**
|
|
31
|
+
* v1.14+. Per-instance size in bytes derived from the memgraph. For
|
|
32
|
+
* fixed-size ObjC classes every instance has the same size; for
|
|
33
|
+
* variable-size classes (NSData with payload, etc.) this is an average
|
|
34
|
+
* (totalBytes / instanceCount, rounded). Absent when neither the
|
|
35
|
+
* cycle-side `[N]` annotation nor the reference-tree parens-size
|
|
36
|
+
* carried a number (rare).
|
|
37
|
+
*/
|
|
38
|
+
instanceSizeBytes?: number;
|
|
39
|
+
/**
|
|
40
|
+
* v1.14+. Total bytes attributed to this class: sum of per-instance
|
|
41
|
+
* sizes from the cycle forest plus the reference-tree totals. FLEX
|
|
42
|
+
* surfaces this as the "Size" sort column in its Live Objects view.
|
|
43
|
+
* Useful for "where is my memory going?" investigations.
|
|
44
|
+
*/
|
|
45
|
+
totalBytes?: number;
|
|
27
46
|
}
|
|
28
47
|
export interface CountAliveResult {
|
|
29
48
|
ok: boolean;
|
|
@@ -41,6 +60,21 @@ export interface CountAliveResult {
|
|
|
41
60
|
*/
|
|
42
61
|
actionableCounts?: CountAliveEntry[];
|
|
43
62
|
}
|
|
44
|
-
/** Pure: count node occurrences by exact className across the cycle forest.
|
|
63
|
+
/** Pure: count node occurrences by exact className across the cycle forest.
|
|
64
|
+
* Backwards-compatible API; for v1.14 byte aggregation use
|
|
65
|
+
* {@link countByClassWithBytes}. */
|
|
45
66
|
export declare function countByClass(report: LeaksReport): Map<string, number>;
|
|
67
|
+
/**
|
|
68
|
+
* Pure: aggregate occurrences AND bytes by exact className across the
|
|
69
|
+
* cycle forest. Each node's `instanceSize` is summed into `totalBytes`;
|
|
70
|
+
* the first non-zero `instanceSize` seen is recorded as the canonical
|
|
71
|
+
* `instanceSizeBytes` (ObjC classes are typically fixed-size, so the
|
|
72
|
+
* first value is representative). Nodes without a size annotation
|
|
73
|
+
* contribute to count but not bytes. v1.14.
|
|
74
|
+
*/
|
|
75
|
+
export declare function countByClassWithBytes(report: LeaksReport): Map<string, {
|
|
76
|
+
count: number;
|
|
77
|
+
totalBytes: number;
|
|
78
|
+
instanceSizeBytes?: number;
|
|
79
|
+
}>;
|
|
46
80
|
export declare function countAlive(input: CountAliveInput): Promise<CountAliveResult>;
|
package/dist/tools/countAlive.js
CHANGED
|
@@ -19,8 +19,14 @@ export const countAliveSchema = z.object({
|
|
|
19
19
|
.boolean()
|
|
20
20
|
.default(false)
|
|
21
21
|
.describe("v1.12+. When true, also parse `leaks --referenceTree --groupByType --noContent` output and surface heap-wide instance counts alongside the cycle-side counts. Required to find classes on memgraphs where `leakCount: 0` and the abandoned-memory shape is what's interesting (e.g. orphaned KVO observers reachable from the global registry). Adds a second `leaks` invocation, run in parallel. Default false preserves v1.11 behavior."),
|
|
22
|
+
sortBy: z
|
|
23
|
+
.enum(["count", "totalBytes"])
|
|
24
|
+
.default("count")
|
|
25
|
+
.describe("v1.14+. Ranks the topN by either instance count (default, preserves v1.13 behavior) or total bytes (FLEX's 'Size' sort). totalBytes is `count * instanceSizeBytes` and is the right rank for 'where is my memory going?' investigations vs 'how many instances are alive?'. Per-class instanceSizeBytes + totalBytes are returned regardless of sort key."),
|
|
22
26
|
});
|
|
23
|
-
/** Pure: count node occurrences by exact className across the cycle forest.
|
|
27
|
+
/** Pure: count node occurrences by exact className across the cycle forest.
|
|
28
|
+
* Backwards-compatible API; for v1.14 byte aggregation use
|
|
29
|
+
* {@link countByClassWithBytes}. */
|
|
24
30
|
export function countByClass(report) {
|
|
25
31
|
const counts = new Map();
|
|
26
32
|
for (const { node } of walkCycles(report.cycles)) {
|
|
@@ -30,6 +36,30 @@ export function countByClass(report) {
|
|
|
30
36
|
}
|
|
31
37
|
return counts;
|
|
32
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Pure: aggregate occurrences AND bytes by exact className across the
|
|
41
|
+
* cycle forest. Each node's `instanceSize` is summed into `totalBytes`;
|
|
42
|
+
* the first non-zero `instanceSize` seen is recorded as the canonical
|
|
43
|
+
* `instanceSizeBytes` (ObjC classes are typically fixed-size, so the
|
|
44
|
+
* first value is representative). Nodes without a size annotation
|
|
45
|
+
* contribute to count but not bytes. v1.14.
|
|
46
|
+
*/
|
|
47
|
+
export function countByClassWithBytes(report) {
|
|
48
|
+
const acc = new Map();
|
|
49
|
+
for (const { node } of walkCycles(report.cycles)) {
|
|
50
|
+
if (!node.className)
|
|
51
|
+
continue;
|
|
52
|
+
const cur = acc.get(node.className) ?? { count: 0, totalBytes: 0 };
|
|
53
|
+
cur.count += 1;
|
|
54
|
+
if (node.instanceSize != null) {
|
|
55
|
+
cur.totalBytes += node.instanceSize;
|
|
56
|
+
if (cur.instanceSizeBytes == null)
|
|
57
|
+
cur.instanceSizeBytes = node.instanceSize;
|
|
58
|
+
}
|
|
59
|
+
acc.set(node.className, cur);
|
|
60
|
+
}
|
|
61
|
+
return acc;
|
|
62
|
+
}
|
|
33
63
|
/**
|
|
34
64
|
* Spawn `leaks --referenceTree --groupByType --noContent` and parse the
|
|
35
65
|
* stdout. Non-fatal on failure: returns empty array so the cycle-side
|
|
@@ -41,37 +71,64 @@ async function captureReferenceTreeCounts(path) {
|
|
|
41
71
|
if (result.code !== 0 && result.code !== 1)
|
|
42
72
|
return new Map();
|
|
43
73
|
const entries = parseReferenceTreeText(result.stdout, 5000);
|
|
44
|
-
return new Map(entries.map((e) => [
|
|
74
|
+
return new Map(entries.map((e) => [
|
|
75
|
+
e.className,
|
|
76
|
+
{ count: e.instanceCount, totalBytes: e.totalBytes },
|
|
77
|
+
]));
|
|
45
78
|
}
|
|
46
79
|
export async function countAlive(input) {
|
|
47
80
|
const wantReferenceTree = input.includeReferenceTree ?? false;
|
|
81
|
+
const sortBy = input.sortBy ?? "count";
|
|
48
82
|
const [{ report, resolvedPath }, refTreeCounts] = await Promise.all([
|
|
49
83
|
runLeaksAndParse(input.path),
|
|
50
84
|
wantReferenceTree
|
|
51
85
|
? captureReferenceTreeCounts(input.path)
|
|
52
86
|
: Promise.resolve(new Map()),
|
|
53
87
|
]);
|
|
54
|
-
const
|
|
55
|
-
const totalNodes = Array.from(
|
|
88
|
+
const cycleByClass = countByClassWithBytes(report);
|
|
89
|
+
const totalNodes = Array.from(cycleByClass.values()).reduce((a, b) => a + b.count, 0);
|
|
56
90
|
if (input.className) {
|
|
57
91
|
let cycleMatched = 0;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
92
|
+
let cycleBytesMatched = 0;
|
|
93
|
+
let cycleInstanceSize;
|
|
94
|
+
for (const [name, info] of cycleByClass.entries()) {
|
|
95
|
+
if (!name.includes(input.className))
|
|
96
|
+
continue;
|
|
97
|
+
cycleMatched += info.count;
|
|
98
|
+
cycleBytesMatched += info.totalBytes;
|
|
99
|
+
if (cycleInstanceSize == null && info.instanceSizeBytes != null) {
|
|
100
|
+
cycleInstanceSize = info.instanceSizeBytes;
|
|
101
|
+
}
|
|
61
102
|
}
|
|
62
103
|
let refTreeMatched = 0;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
104
|
+
let refTreeBytesMatched = 0;
|
|
105
|
+
for (const [name, info] of refTreeCounts.entries()) {
|
|
106
|
+
if (!name.includes(input.className))
|
|
107
|
+
continue;
|
|
108
|
+
refTreeMatched += info.count;
|
|
109
|
+
refTreeBytesMatched += info.totalBytes;
|
|
66
110
|
}
|
|
111
|
+
const totalCount = cycleMatched + refTreeMatched;
|
|
112
|
+
const totalBytes = cycleBytesMatched + refTreeBytesMatched;
|
|
113
|
+
const instanceSizeBytes = cycleInstanceSize ??
|
|
114
|
+
(totalCount > 0 && totalBytes > 0
|
|
115
|
+
? Math.round(totalBytes / totalCount)
|
|
116
|
+
: undefined);
|
|
67
117
|
const entry = wantReferenceTree
|
|
68
118
|
? {
|
|
69
119
|
className: input.className,
|
|
70
|
-
instanceCount:
|
|
120
|
+
instanceCount: totalCount,
|
|
71
121
|
byCycle: cycleMatched,
|
|
72
122
|
byReferenceTree: refTreeMatched,
|
|
123
|
+
...(instanceSizeBytes != null ? { instanceSizeBytes } : {}),
|
|
124
|
+
...(totalBytes > 0 ? { totalBytes } : {}),
|
|
73
125
|
}
|
|
74
|
-
: {
|
|
126
|
+
: {
|
|
127
|
+
className: input.className,
|
|
128
|
+
instanceCount: cycleMatched,
|
|
129
|
+
...(instanceSizeBytes != null ? { instanceSizeBytes } : {}),
|
|
130
|
+
...(cycleBytesMatched > 0 ? { totalBytes: cycleBytesMatched } : {}),
|
|
131
|
+
};
|
|
75
132
|
return {
|
|
76
133
|
ok: true,
|
|
77
134
|
path: resolvedPath,
|
|
@@ -80,31 +137,69 @@ export async function countAlive(input) {
|
|
|
80
137
|
};
|
|
81
138
|
}
|
|
82
139
|
// topN path. Merge cycle + reference-tree counts when the flag is on,
|
|
83
|
-
// ordered by
|
|
140
|
+
// ordered by sortBy (default 'count', or 'totalBytes' for FLEX-style
|
|
141
|
+
// memory-budget rank).
|
|
84
142
|
const merged = new Map();
|
|
85
|
-
for (const [name,
|
|
86
|
-
merged.set(name, {
|
|
143
|
+
for (const [name, info] of cycleByClass.entries()) {
|
|
144
|
+
merged.set(name, {
|
|
145
|
+
byCycle: info.count,
|
|
146
|
+
byReferenceTree: 0,
|
|
147
|
+
cycleBytes: info.totalBytes,
|
|
148
|
+
refTreeBytes: 0,
|
|
149
|
+
...(info.instanceSizeBytes != null
|
|
150
|
+
? { instanceSizeBytes: info.instanceSizeBytes }
|
|
151
|
+
: {}),
|
|
152
|
+
});
|
|
87
153
|
}
|
|
88
154
|
if (wantReferenceTree) {
|
|
89
|
-
for (const [name,
|
|
155
|
+
for (const [name, info] of refTreeCounts.entries()) {
|
|
90
156
|
const existing = merged.get(name);
|
|
91
|
-
if (existing)
|
|
92
|
-
existing.byReferenceTree =
|
|
93
|
-
|
|
94
|
-
|
|
157
|
+
if (existing) {
|
|
158
|
+
existing.byReferenceTree = info.count;
|
|
159
|
+
existing.refTreeBytes = info.totalBytes;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
merged.set(name, {
|
|
163
|
+
byCycle: 0,
|
|
164
|
+
byReferenceTree: info.count,
|
|
165
|
+
cycleBytes: 0,
|
|
166
|
+
refTreeBytes: info.totalBytes,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
95
169
|
}
|
|
96
170
|
}
|
|
97
171
|
const topN = input.topN ?? 20;
|
|
98
|
-
const allEntries = Array.from(merged.entries())
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
172
|
+
const allEntries = Array.from(merged.entries()).map(([name, v]) => {
|
|
173
|
+
const totalCount = v.byCycle + v.byReferenceTree;
|
|
174
|
+
const totalBytes = v.cycleBytes + v.refTreeBytes;
|
|
175
|
+
const instanceSizeBytes = v.instanceSizeBytes ??
|
|
176
|
+
(totalCount > 0 && totalBytes > 0
|
|
177
|
+
? Math.round(totalBytes / totalCount)
|
|
178
|
+
: undefined);
|
|
179
|
+
return wantReferenceTree
|
|
180
|
+
? {
|
|
181
|
+
className: name,
|
|
182
|
+
instanceCount: totalCount,
|
|
183
|
+
byCycle: v.byCycle,
|
|
184
|
+
byReferenceTree: v.byReferenceTree,
|
|
185
|
+
...(instanceSizeBytes != null ? { instanceSizeBytes } : {}),
|
|
186
|
+
...(totalBytes > 0 ? { totalBytes } : {}),
|
|
187
|
+
}
|
|
188
|
+
: {
|
|
189
|
+
className: name,
|
|
190
|
+
instanceCount: v.byCycle,
|
|
191
|
+
...(instanceSizeBytes != null ? { instanceSizeBytes } : {}),
|
|
192
|
+
...(v.cycleBytes > 0 ? { totalBytes: v.cycleBytes } : {}),
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
allEntries.sort((a, b) => {
|
|
196
|
+
if (sortBy === "totalBytes") {
|
|
197
|
+
const ad = (b.totalBytes ?? 0) - (a.totalBytes ?? 0);
|
|
198
|
+
if (ad !== 0)
|
|
199
|
+
return ad;
|
|
105
200
|
}
|
|
106
|
-
|
|
107
|
-
|
|
201
|
+
return b.instanceCount - a.instanceCount;
|
|
202
|
+
});
|
|
108
203
|
const top = allEntries.slice(0, topN);
|
|
109
204
|
const result = {
|
|
110
205
|
ok: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"countAlive.js","sourceRoot":"","sources":["../../src/tools/countAlive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AAGrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IACxE,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mIAAmI,CACpI;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CACP,iFAAiF,CAClF;IACH,oBAAoB,EAAE,CAAC;SACpB,OAAO,EAAE;SACT,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACP,4aAA4a,CAC7a;CACJ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"countAlive.js","sourceRoot":"","sources":["../../src/tools/countAlive.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,6 +62,10 @@ const SCHEMA_TO_ANALYZER = {
|
|
|
62
62
|
tool: "analyzeAppLaunch",
|
|
63
63
|
description: "Returns cold/warm launch type plus per-phase breakdown (process-creation, dyld-init, ObjC-init, AppDelegate, first-frame).",
|
|
64
64
|
},
|
|
65
|
+
"network-connections": {
|
|
66
|
+
tool: "analyzeNetworkActivity",
|
|
67
|
+
description: "Per-request URL / host / method / status / response time / bytes. Top-N by duration and by bytes plus per-host aggregates.",
|
|
68
|
+
},
|
|
65
69
|
};
|
|
66
70
|
/** Pure: parse the trace-toc XML payload into an inspection result. */
|
|
67
71
|
export function parseTraceToc(xml, tracePath) {
|
|
@@ -72,16 +76,22 @@ export function parseTraceToc(xml, tracePath) {
|
|
|
72
76
|
// Surfacing only schema metadata + row counts is faster and avoids
|
|
73
77
|
// pulling row payloads into memory for traces that have hundreds of
|
|
74
78
|
// thousands of rows.
|
|
75
|
-
//
|
|
76
|
-
|
|
79
|
+
//
|
|
80
|
+
// Apple's `xctrace export --toc` emits self-closing `<table schema="X"/>`
|
|
81
|
+
// elements (the TOC carries column definitions only, no rows). Older
|
|
82
|
+
// synthetic fixtures and some xctrace versions use the open-close form
|
|
83
|
+
// `<table schema="X">...<row/>...</table>`. We match BOTH and fall back
|
|
84
|
+
// to row-counting from the body when present.
|
|
85
|
+
// Open-close form first: `<table schema="X">body</table>`.
|
|
86
|
+
const openCloseRegex = /<table\b[^>]*\bschema="([^"]+)"[^>]*>([\s\S]*?)<\/table>/g;
|
|
87
|
+
const seenRanges = [];
|
|
77
88
|
let match;
|
|
78
|
-
while ((match =
|
|
89
|
+
while ((match = openCloseRegex.exec(xml)) !== null) {
|
|
79
90
|
const name = match[1];
|
|
80
91
|
const body = match[2];
|
|
81
|
-
|
|
92
|
+
seenRanges.push([match.index, match.index + match[0].length]);
|
|
82
93
|
const rowMatches = body.match(/<row\b/g);
|
|
83
94
|
const rowCount = rowMatches ? rowMatches.length : 0;
|
|
84
|
-
// Description: schema may carry an `engineering-type` description.
|
|
85
95
|
const descMatch = /<engineering-description>([^<]+)<\/engineering-description>/.exec(body);
|
|
86
96
|
const description = descMatch?.[1]?.trim();
|
|
87
97
|
schemas.push({
|
|
@@ -90,15 +100,36 @@ export function parseTraceToc(xml, tracePath) {
|
|
|
90
100
|
...(description ? { description } : {}),
|
|
91
101
|
});
|
|
92
102
|
}
|
|
103
|
+
// Self-closing form: `<table schema="X" .../>`. Skip ranges already
|
|
104
|
+
// matched by openCloseRegex so we don't double-count when a body contains
|
|
105
|
+
// nested self-closing tables (unlikely but defensive).
|
|
106
|
+
const selfCloseRegex = /<table\b[^>]*\bschema="([^"]+)"[^>]*\/>/g;
|
|
107
|
+
while ((match = selfCloseRegex.exec(xml)) !== null) {
|
|
108
|
+
const start = match.index;
|
|
109
|
+
if (seenRanges.some(([s, e]) => start >= s && start < e))
|
|
110
|
+
continue;
|
|
111
|
+
const name = match[1];
|
|
112
|
+
schemas.push({
|
|
113
|
+
name,
|
|
114
|
+
rowCount: 0, // TOC self-closing tables carry no rows; rowCount must be filled by the async row-counting step in inspectTrace().
|
|
115
|
+
});
|
|
116
|
+
}
|
|
93
117
|
schemas.sort((a, b) => b.rowCount - a.rowCount);
|
|
94
118
|
const rowCounts = {};
|
|
95
119
|
for (const s of schemas)
|
|
96
120
|
rowCounts[s.name] = s.rowCount;
|
|
97
121
|
// Run-level metadata extracted from the TOC's <run> attributes / children.
|
|
98
|
-
|
|
99
|
-
|
|
122
|
+
// Apple's --toc output exposes device + OS as ATTRIBUTES on <device .../>
|
|
123
|
+
// and uses <start-date> instead of <recorded-when>. We try the Apple
|
|
124
|
+
// attribute form first, fall back to legacy text-element form for
|
|
125
|
+
// synthetic fixtures.
|
|
126
|
+
const deviceAttrMatch = /<device\b[^>]*\bmodel="([^"]+)"/.exec(xml);
|
|
127
|
+
const deviceMatch = deviceAttrMatch ?? /<device-model>([^<]+)<\/device-model>/.exec(xml);
|
|
128
|
+
const osAttrMatch = /<device\b[^>]*\bos-version="([^"]+)"/.exec(xml);
|
|
129
|
+
const osMatch = osAttrMatch ?? /<os-version>([^<]+)<\/os-version>/.exec(xml);
|
|
100
130
|
const templateMatch = /<template-name>([^<]+)<\/template-name>/.exec(xml);
|
|
101
|
-
const
|
|
131
|
+
const recordedAttrMatch = /<start-date>([^<]+)<\/start-date>/.exec(xml);
|
|
132
|
+
const recordedMatch = recordedAttrMatch ?? /<recorded-when>([^<]+)<\/recorded-when>/.exec(xml);
|
|
102
133
|
const suggestedNextCalls = [];
|
|
103
134
|
for (const s of schemas) {
|
|
104
135
|
if (s.rowCount === 0)
|
|
@@ -142,6 +173,36 @@ function buildDiagnosis(schemas, templateName) {
|
|
|
142
173
|
}
|
|
143
174
|
return parts.join(" ");
|
|
144
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Count `<row>` elements for a single schema by running a targeted xpath
|
|
178
|
+
* query. Used by `inspectTrace` to fill in row counts that the bare
|
|
179
|
+
* `--toc` output omits (Apple's TOC emits self-closing `<table/>` elements
|
|
180
|
+
* with column metadata only, no rows).
|
|
181
|
+
*
|
|
182
|
+
* Bounded by a 60s xctrace timeout each. On any failure we treat as zero
|
|
183
|
+
* rows rather than throwing: an empty result is the same semantic outcome
|
|
184
|
+
* as a missing schema, and downstream `summarizeTrace` already handles
|
|
185
|
+
* `rowCount === 0` as "schema-absent".
|
|
186
|
+
*/
|
|
187
|
+
async function countSchemaRows(tracePath, schemaName) {
|
|
188
|
+
try {
|
|
189
|
+
const result = await runCommand("xcrun", [
|
|
190
|
+
"xctrace",
|
|
191
|
+
"export",
|
|
192
|
+
"--input",
|
|
193
|
+
tracePath,
|
|
194
|
+
"--xpath",
|
|
195
|
+
`/trace-toc/run/data/table[@schema="${schemaName}"]`,
|
|
196
|
+
], { timeoutMs: 60_000 });
|
|
197
|
+
if (result.code !== 0)
|
|
198
|
+
return 0;
|
|
199
|
+
const rowMatches = result.stdout.match(/<row\b/g);
|
|
200
|
+
return rowMatches ? rowMatches.length : 0;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
145
206
|
export async function inspectTrace(input) {
|
|
146
207
|
const tracePath = resolvePath(input.tracePath);
|
|
147
208
|
if (!existsSync(tracePath)) {
|
|
@@ -155,22 +216,55 @@ export async function inspectTrace(input) {
|
|
|
155
216
|
// The bundle is a directory on macOS; stat reports the directory inode
|
|
156
217
|
// size, which is fine for orientation. Failures are non-fatal.
|
|
157
218
|
}
|
|
158
|
-
|
|
219
|
+
// Apple's `xctrace export --toc` is the canonical schema-discovery surface.
|
|
220
|
+
// The previously-used `--xpath '/trace-toc/run'` returns "no content to
|
|
221
|
+
// export" against real Apple-produced .trace bundles (validated 2026-05-15
|
|
222
|
+
// against wishlist-tti-device.trace). The --toc flag returns the full
|
|
223
|
+
// table-of-contents XML including all `<table schema="..."/>` elements.
|
|
224
|
+
const result = await runCommand("xcrun", ["xctrace", "export", "--input", tracePath, "--toc"], { timeoutMs: 60_000 });
|
|
159
225
|
if (result.code !== 0) {
|
|
160
|
-
|
|
161
|
-
// a trace with no /run node), try the broader /trace-toc xpath and
|
|
162
|
-
// parse whatever schemas surface.
|
|
163
|
-
const fallback = await runCommand("xcrun", ["xctrace", "export", "--input", tracePath, "--xpath", "/trace-toc"], { timeoutMs: 60_000 });
|
|
164
|
-
if (fallback.code !== 0) {
|
|
165
|
-
throw new Error(`xctrace export TOC failed (code ${result.code}): ${result.stderr || result.stdout || "<no output>"}`);
|
|
166
|
-
}
|
|
167
|
-
const parsed = parseTraceToc(fallback.stdout, tracePath);
|
|
168
|
-
return { ok: true, ...parsed, ...(fileSize != null ? { fileSize } : {}) };
|
|
226
|
+
throw new Error(`xctrace export --toc failed (code ${result.code}): ${result.stderr || result.stdout || "<no output>"}`);
|
|
169
227
|
}
|
|
170
228
|
const parsed = parseTraceToc(result.stdout, tracePath);
|
|
229
|
+
// The TOC carries schema NAMES + column metadata but no rows. Fill in
|
|
230
|
+
// row counts for the schemas an analyzer can consume (the ones in
|
|
231
|
+
// SCHEMA_TO_ANALYZER) so `summarizeTrace` can decide which analyzers to
|
|
232
|
+
// run. Other schemas (tick, kdebug, life-cycle-period, etc.) are left at
|
|
233
|
+
// rowCount=0; nothing downstream consumes them.
|
|
234
|
+
const knownSchemas = Object.keys(SCHEMA_TO_ANALYZER);
|
|
235
|
+
const schemasInTrace = new Set(parsed.schemas.map((s) => s.name));
|
|
236
|
+
const schemasToCount = knownSchemas.filter((name) => schemasInTrace.has(name));
|
|
237
|
+
const counts = await Promise.all(schemasToCount.map(async (name) => [name, await countSchemaRows(tracePath, name)]));
|
|
238
|
+
const rowCounts = { ...parsed.rowCounts };
|
|
239
|
+
for (const [name, count] of counts)
|
|
240
|
+
rowCounts[name] = count;
|
|
241
|
+
const updatedSchemas = parsed.schemas.map((s) => rowCounts[s.name] != null && rowCounts[s.name] !== s.rowCount
|
|
242
|
+
? { ...s, rowCount: rowCounts[s.name] }
|
|
243
|
+
: s);
|
|
244
|
+
updatedSchemas.sort((a, b) => b.rowCount - a.rowCount);
|
|
245
|
+
// Recompute suggestedNextCalls now that row counts are accurate.
|
|
246
|
+
const suggestedNextCalls = [];
|
|
247
|
+
for (const s of updatedSchemas) {
|
|
248
|
+
if (s.rowCount === 0)
|
|
249
|
+
continue;
|
|
250
|
+
const mapping = SCHEMA_TO_ANALYZER[s.name];
|
|
251
|
+
if (!mapping)
|
|
252
|
+
continue;
|
|
253
|
+
suggestedNextCalls.push({
|
|
254
|
+
tool: mapping.tool,
|
|
255
|
+
args: { tracePath },
|
|
256
|
+
why: `${s.rowCount.toLocaleString()} rows in the ${s.name} schema. ${mapping.description}`,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
// Recompute diagnosis with accurate row counts.
|
|
260
|
+
const diagnosis = buildDiagnosis(updatedSchemas, parsed.templateName);
|
|
171
261
|
return {
|
|
172
262
|
ok: true,
|
|
173
263
|
...parsed,
|
|
264
|
+
schemas: updatedSchemas,
|
|
265
|
+
rowCounts,
|
|
266
|
+
suggestedNextCalls,
|
|
267
|
+
diagnosis,
|
|
174
268
|
...(fileSize != null ? { fileSize } : {}),
|
|
175
269
|
};
|
|
176
270
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspectTrace.js","sourceRoot":"","sources":["../../src/tools/inspectTrace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,uFAAuF,CACxF;CACJ,CAAC,CAAC;AAoCH;;;GAGG;AACH,MAAM,kBAAkB,GAGpB;IACF,iBAAiB,EAAE;QACjB,IAAI,EAAE,cAAc;QACpB,WAAW,EACT,6JAA6J;KAChK;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EACT,0GAA0G;KAC7G;IACD,cAAc,EAAE;QACd,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,kIAAkI;KACrI;IACD,WAAW,EAAE;QACX,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,gJAAgJ;KACnJ;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,4HAA4H;KAC/H;CACF,CAAC;AAEF,uEAAuE;AACvE,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,SAAiB;IAEjB,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,mEAAmE;IACnE,gEAAgE;IAChE,mEAAmE;IACnE,mEAAmE;IACnE,oEAAoE;IACpE,qBAAqB;
|
|
1
|
+
{"version":3,"file":"inspectTrace.js","sourceRoot":"","sources":["../../src/tools/inspectTrace.ts"],"names":[],"mappings":"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"}
|
|
@@ -87,7 +87,90 @@ export interface RecordTimeProfileResult {
|
|
|
87
87
|
* and the practical mitigations.
|
|
88
88
|
*/
|
|
89
89
|
workaroundNotice?: RecordingTimeoutWorkaroundNotice;
|
|
90
|
+
/**
|
|
91
|
+
* v1.14+. `true` when, after a timed-out recording, the wrapper invoked
|
|
92
|
+
* `open -a Instruments <tracePath>` so the user can inspect the partial
|
|
93
|
+
* trace in the GUI (Instruments.app on macOS 26.x can still open and
|
|
94
|
+
* symbolicate traces the CLI export path rejects). Opt-in via
|
|
95
|
+
* `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS=1`. `false` when the env flag is
|
|
96
|
+
* unset (default) or the trace bundle is missing from disk. Absent when
|
|
97
|
+
* the recording did not time out.
|
|
98
|
+
*/
|
|
99
|
+
openedInInstrumentsApp?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* v1.14 item H. Pre-flight probe for the xctrace `--time-limit` ignore
|
|
103
|
+
* regression on macOS 26.x simulators. Runs a 2-second test recording
|
|
104
|
+
* against the same target the user requested. If the probe completes
|
|
105
|
+
* cleanly inside its wrapper window, the user's full recording is
|
|
106
|
+
* expected to behave; if the probe times out, we bail before spending
|
|
107
|
+
* the user's full `durationSec` + 30s grace window on a wedge.
|
|
108
|
+
*
|
|
109
|
+
* Returns `{ healthy: true }` when the probe exited cleanly. Returns
|
|
110
|
+
* `{ healthy: false, reason }` when the probe timed out OR when xctrace
|
|
111
|
+
* exited non-zero (the wedge does not always produce timedOut=true;
|
|
112
|
+
* sometimes xctrace exits early with a misleading error code when the
|
|
113
|
+
* sim is in a bad state). The recordTimeProfile flow treats either as
|
|
114
|
+
* "skip the full recording, return workaroundNotice now".
|
|
115
|
+
*
|
|
116
|
+
* Pre-flight is gated to ATTACH mode only. The `--launch` path would
|
|
117
|
+
* start the user's app a second time (probe launch + full-recording
|
|
118
|
+
* launch), losing first-launch state. For `--launch` callers we skip
|
|
119
|
+
* the probe and fall back to the existing 70s timeout wrapper.
|
|
120
|
+
*
|
|
121
|
+
* Exported so the gating logic can be unit-tested without spawning
|
|
122
|
+
* xctrace.
|
|
123
|
+
*/
|
|
124
|
+
export interface PreflightResult {
|
|
125
|
+
healthy: boolean;
|
|
126
|
+
reason?: string;
|
|
127
|
+
durationMs: number;
|
|
90
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns true when a pre-flight probe should run before the user's
|
|
131
|
+
* actual recording. v1.14 item H.
|
|
132
|
+
*
|
|
133
|
+
* - `MEMORYDETECTIVE_PREFLIGHT_XCTRACE=1` forces preflight on.
|
|
134
|
+
* - `MEMORYDETECTIVE_PREFLIGHT_XCTRACE=0` forces it off.
|
|
135
|
+
* - Default: auto-enabled when host is macOS 26.x AND target is a
|
|
136
|
+
* simulator AND attach mode (`--attach`, not `--launch`). The set of
|
|
137
|
+
* configurations where the regression is known to fire.
|
|
138
|
+
*
|
|
139
|
+
* The `osPlatform` and `osRelease` params are threaded through to
|
|
140
|
+
* `getPlatformAdvisory` so tests can simulate non-macOS-26 hosts even
|
|
141
|
+
* when running on a real macOS 26.x machine.
|
|
142
|
+
*/
|
|
143
|
+
export declare function shouldPreflightXctrace(input: RecordTimeProfileInput, env?: Readonly<Record<string, string | undefined>>, osPlatform?: () => NodeJS.Platform, osRelease?: () => string): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Runs the 2-second probe. Reuses runCommand's timeout wrapper with the
|
|
146
|
+
* same SIGINT-first / SIGKILL-fallback shape that the full recording
|
|
147
|
+
* uses, so the probe's salvage behavior matches the real path.
|
|
148
|
+
*
|
|
149
|
+
* The output bundle is placed at `<output>.preflight` to keep it
|
|
150
|
+
* recognizable in cleanup tools and not collide with the user's actual
|
|
151
|
+
* output path.
|
|
152
|
+
*/
|
|
153
|
+
export declare function preflightXctraceRecord(input: RecordTimeProfileInput, resolvedOutput: string): Promise<PreflightResult>;
|
|
154
|
+
/**
|
|
155
|
+
* v1.14 item J. When a `recordTimeProfile` call times out, optionally
|
|
156
|
+
* launch the partial `.trace` in Instruments.app so the user has a GUI
|
|
157
|
+
* escape hatch. Returns `true` when `open -a Instruments <tracePath>`
|
|
158
|
+
* was spawned, `false` otherwise.
|
|
159
|
+
*
|
|
160
|
+
* Gated on `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS=1` to avoid spamming
|
|
161
|
+
* the user's GUI on unattended runs and CI. Also requires the trace
|
|
162
|
+
* bundle to exist on disk (xctrace's SIGINT path may have failed to
|
|
163
|
+
* write anything).
|
|
164
|
+
*
|
|
165
|
+
* The `open` invocation is fire-and-forget: `detached: true` + `unref()`
|
|
166
|
+
* so the recording tool returns immediately. Failures to launch
|
|
167
|
+
* Instruments.app are swallowed; the user is no worse off than without
|
|
168
|
+
* the flag enabled.
|
|
169
|
+
*
|
|
170
|
+
* Exported so the env-gating logic can be tested without spawning
|
|
171
|
+
* Instruments in test runs.
|
|
172
|
+
*/
|
|
173
|
+
export declare function maybeOpenInInstruments(tracePath: string): boolean;
|
|
91
174
|
/** Pure: build the xctrace argv for the given input. Exposed for testing. */
|
|
92
175
|
export declare function buildXctraceArgs(input: RecordTimeProfileInput): string[];
|
|
93
176
|
export declare function recordTimeProfile(input: RecordTimeProfileInput): Promise<RecordTimeProfileResult>;
|