@memlab/core 1.0.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 +11 -0
- package/dist/__tests__/parser/HeapParser.test.d.ts +11 -0
- package/dist/__tests__/parser/HeapParser.test.d.ts.map +1 -0
- package/dist/__tests__/parser/HeapParser.test.js +54 -0
- package/dist/__tests__/parser/NodeHeap.test.d.ts +11 -0
- package/dist/__tests__/parser/NodeHeap.test.d.ts.map +1 -0
- package/dist/__tests__/parser/NodeHeap.test.js +96 -0
- package/dist/__tests__/parser/StringNode.test.d.ts +11 -0
- package/dist/__tests__/parser/StringNode.test.d.ts.map +1 -0
- package/dist/__tests__/parser/StringNode.test.js +61 -0
- package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.d.ts +16 -0
- package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.d.ts.map +1 -0
- package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.js +140 -0
- package/dist/__tests__/utils/utils.test.d.ts +11 -0
- package/dist/__tests__/utils/utils.test.d.ts.map +1 -0
- package/dist/__tests__/utils/utils.test.js +81 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/lib/BaseOption.d.ts +31 -0
- package/dist/lib/BaseOption.d.ts.map +1 -0
- package/dist/lib/BaseOption.js +109 -0
- package/dist/lib/BrowserInfo.d.ts +33 -0
- package/dist/lib/BrowserInfo.d.ts.map +1 -0
- package/dist/lib/BrowserInfo.js +117 -0
- package/dist/lib/Config.d.ts +203 -0
- package/dist/lib/Config.d.ts.map +1 -0
- package/dist/lib/Config.js +427 -0
- package/dist/lib/Console.d.ts +67 -0
- package/dist/lib/Console.d.ts.map +1 -0
- package/dist/lib/Console.js +344 -0
- package/dist/lib/Constant.d.ts +38 -0
- package/dist/lib/Constant.d.ts.map +1 -0
- package/dist/lib/Constant.js +58 -0
- package/dist/lib/FileManager.d.ts +69 -0
- package/dist/lib/FileManager.d.ts.map +1 -0
- package/dist/lib/FileManager.js +309 -0
- package/dist/lib/HeapAnalyzer.d.ts +51 -0
- package/dist/lib/HeapAnalyzer.d.ts.map +1 -0
- package/dist/lib/HeapAnalyzer.js +719 -0
- package/dist/lib/HeapParser.d.ts +19 -0
- package/dist/lib/HeapParser.d.ts.map +1 -0
- package/dist/lib/HeapParser.js +128 -0
- package/dist/lib/InternalValueSetter.d.ts +14 -0
- package/dist/lib/InternalValueSetter.d.ts.map +1 -0
- package/dist/lib/InternalValueSetter.js +43 -0
- package/dist/lib/NodeHeap.d.ts +16 -0
- package/dist/lib/NodeHeap.d.ts.map +1 -0
- package/dist/lib/NodeHeap.js +62 -0
- package/dist/lib/ProcessManager.d.ts +25 -0
- package/dist/lib/ProcessManager.d.ts.map +1 -0
- package/dist/lib/ProcessManager.js +67 -0
- package/dist/lib/Serializer.d.ts +49 -0
- package/dist/lib/Serializer.d.ts.map +1 -0
- package/dist/lib/Serializer.js +702 -0
- package/dist/lib/StringLoader.d.ts +26 -0
- package/dist/lib/StringLoader.d.ts.map +1 -0
- package/dist/lib/StringLoader.js +290 -0
- package/dist/lib/Types.d.ts +432 -0
- package/dist/lib/Types.d.ts.map +1 -0
- package/dist/lib/Types.js +11 -0
- package/dist/lib/Utils.d.ts +223 -0
- package/dist/lib/Utils.d.ts.map +1 -0
- package/dist/lib/Utils.js +1736 -0
- package/dist/lib/heap-data/HeapEdge.d.ts +27 -0
- package/dist/lib/heap-data/HeapEdge.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapEdge.js +75 -0
- package/dist/lib/heap-data/HeapLocation.d.ts +22 -0
- package/dist/lib/heap-data/HeapLocation.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapLocation.js +40 -0
- package/dist/lib/heap-data/HeapNode.d.ts +55 -0
- package/dist/lib/heap-data/HeapNode.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapNode.js +344 -0
- package/dist/lib/heap-data/HeapSnapshot.d.ts +85 -0
- package/dist/lib/heap-data/HeapSnapshot.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapSnapshot.js +462 -0
- package/dist/lib/heap-data/HeapStringNode.d.ts +18 -0
- package/dist/lib/heap-data/HeapStringNode.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapStringNode.js +43 -0
- package/dist/lib/heap-data/HeapUtils.d.ts +17 -0
- package/dist/lib/heap-data/HeapUtils.d.ts.map +1 -0
- package/dist/lib/heap-data/HeapUtils.js +25 -0
- package/dist/logger/LeakClusterLogger.d.ts +40 -0
- package/dist/logger/LeakClusterLogger.d.ts.map +1 -0
- package/dist/logger/LeakClusterLogger.js +228 -0
- package/dist/logger/LeakTraceDetailsLogger.d.ts +19 -0
- package/dist/logger/LeakTraceDetailsLogger.d.ts.map +1 -0
- package/dist/logger/LeakTraceDetailsLogger.js +50 -0
- package/dist/modes/BaseMode.d.ts +30 -0
- package/dist/modes/BaseMode.d.ts.map +1 -0
- package/dist/modes/BaseMode.js +95 -0
- package/dist/modes/InteractionTestMode.d.ts +23 -0
- package/dist/modes/InteractionTestMode.d.ts.map +1 -0
- package/dist/modes/InteractionTestMode.js +46 -0
- package/dist/modes/MeasureMode.d.ts +23 -0
- package/dist/modes/MeasureMode.d.ts.map +1 -0
- package/dist/modes/MeasureMode.js +58 -0
- package/dist/modes/RunningModes.d.ts +15 -0
- package/dist/modes/RunningModes.d.ts.map +1 -0
- package/dist/modes/RunningModes.js +40 -0
- package/dist/paths/TraceFinder.d.ts +31 -0
- package/dist/paths/TraceFinder.d.ts.map +1 -0
- package/dist/paths/TraceFinder.js +537 -0
- package/dist/trace-cluster/ClusterUtils.d.ts +14 -0
- package/dist/trace-cluster/ClusterUtils.d.ts.map +1 -0
- package/dist/trace-cluster/ClusterUtils.js +17 -0
- package/dist/trace-cluster/ClusterUtilsHelper.d.ts +38 -0
- package/dist/trace-cluster/ClusterUtilsHelper.d.ts.map +1 -0
- package/dist/trace-cluster/ClusterUtilsHelper.js +373 -0
- package/dist/trace-cluster/ClusteringHeuristics.d.ts +22 -0
- package/dist/trace-cluster/ClusteringHeuristics.d.ts.map +1 -0
- package/dist/trace-cluster/ClusteringHeuristics.js +23 -0
- package/dist/trace-cluster/EvalutationMetric.d.ts +22 -0
- package/dist/trace-cluster/EvalutationMetric.d.ts.map +1 -0
- package/dist/trace-cluster/EvalutationMetric.js +158 -0
- package/dist/trace-cluster/TraceBucket.d.ts +36 -0
- package/dist/trace-cluster/TraceBucket.d.ts.map +1 -0
- package/dist/trace-cluster/TraceBucket.js +238 -0
- package/dist/trace-cluster/TraceElement.d.ts +71 -0
- package/dist/trace-cluster/TraceElement.d.ts.map +1 -0
- package/dist/trace-cluster/TraceElement.js +182 -0
- package/dist/trace-cluster/strategies/TraceAsClusterStrategy.d.ts +15 -0
- package/dist/trace-cluster/strategies/TraceAsClusterStrategy.d.ts.map +1 -0
- package/dist/trace-cluster/strategies/TraceAsClusterStrategy.js +37 -0
- package/dist/trace-cluster/strategies/TraceSimilarityStrategy.d.ts +15 -0
- package/dist/trace-cluster/strategies/TraceSimilarityStrategy.d.ts.map +1 -0
- package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +60 -0
- package/package.json +60 -0
- package/static/run-meta.json +10 -0
- package/static/visit-order.json +27 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const Config_1 = __importDefault(require("../lib/Config"));
|
|
17
|
+
const Console_1 = __importDefault(require("../lib/Console"));
|
|
18
|
+
const Serializer_1 = __importDefault(require("../lib/Serializer"));
|
|
19
|
+
const Utils_1 = __importDefault(require("../lib/Utils"));
|
|
20
|
+
const TraceElement_1 = require("./TraceElement");
|
|
21
|
+
const TraceSimilarityStrategy_1 = __importDefault(require("./strategies/TraceSimilarityStrategy"));
|
|
22
|
+
const TraceAsClusterStrategy_1 = __importDefault(require("./strategies/TraceAsClusterStrategy"));
|
|
23
|
+
// sync up with html/intern/js/webspeed/memlab/lib/LeakCluster.js
|
|
24
|
+
class NormalizedTrace {
|
|
25
|
+
constructor(p = null, snapshot = null) {
|
|
26
|
+
if (!p) {
|
|
27
|
+
this.trace = [];
|
|
28
|
+
this.traceSummary = '';
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this.trace = NormalizedTrace.pathToTrace(p, {
|
|
32
|
+
untilFirstDetachedDOMElem: true,
|
|
33
|
+
});
|
|
34
|
+
this.traceSummary = snapshot
|
|
35
|
+
? Serializer_1.default.summarizePath(p, new Set(), snapshot)
|
|
36
|
+
: '';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// convert path to leak trace
|
|
40
|
+
static pathToTrace(p, options = {}) {
|
|
41
|
+
const skipRest = !!options.untilFirstDetachedDOMElem;
|
|
42
|
+
const shouldSkip = (node) => {
|
|
43
|
+
// only consider the trace from GC root to the first detached element
|
|
44
|
+
// NOTE: do not use utils.isDetachedDOMNode, which relies on
|
|
45
|
+
// the fact that p.node is a HeapNode
|
|
46
|
+
return (skipRest &&
|
|
47
|
+
node.name.startsWith('Detached ') &&
|
|
48
|
+
node.name !== 'Detached InternalNode');
|
|
49
|
+
};
|
|
50
|
+
const trace = [];
|
|
51
|
+
let curItem = p;
|
|
52
|
+
while (curItem) {
|
|
53
|
+
if (curItem.node) {
|
|
54
|
+
trace.push(new TraceElement_1.NodeRecord(curItem.node));
|
|
55
|
+
if (shouldSkip(curItem.node)) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (curItem.edge) {
|
|
60
|
+
trace.push(new TraceElement_1.EdgeRecord(curItem.edge));
|
|
61
|
+
}
|
|
62
|
+
curItem = curItem.next;
|
|
63
|
+
}
|
|
64
|
+
return trace;
|
|
65
|
+
}
|
|
66
|
+
// convert leak trace to path
|
|
67
|
+
static traceToPath(trace) {
|
|
68
|
+
if (!trace) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
let p = {};
|
|
72
|
+
for (let i = trace.length - 1; i >= 0; --i) {
|
|
73
|
+
const item = trace[i];
|
|
74
|
+
if (item.kind === 'edge') {
|
|
75
|
+
p.edge = item;
|
|
76
|
+
}
|
|
77
|
+
if (item.kind === 'node') {
|
|
78
|
+
p.node = item;
|
|
79
|
+
p = { next: p };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return p.next || {};
|
|
83
|
+
}
|
|
84
|
+
getTraceSummary() {
|
|
85
|
+
return this.traceSummary;
|
|
86
|
+
}
|
|
87
|
+
static addLeakedNodeToCluster(cluster, path) {
|
|
88
|
+
const leakedNode = Utils_1.default.getLeakedNode(path);
|
|
89
|
+
if (!cluster.leakedNodeIds) {
|
|
90
|
+
cluster.leakedNodeIds = new Set();
|
|
91
|
+
}
|
|
92
|
+
if (leakedNode) {
|
|
93
|
+
cluster.leakedNodeIds.add(leakedNode.id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
static calculateClusterRetainedSize(cluster, snapshot, aggregateDominatorMetrics) {
|
|
97
|
+
if (!cluster.leakedNodeIds) {
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
return (cluster.retainedSize = aggregateDominatorMetrics(cluster.leakedNodeIds, snapshot, () => true, (node) => node.retainedSize));
|
|
101
|
+
}
|
|
102
|
+
static samplePaths(paths) {
|
|
103
|
+
const maxCount = 5000;
|
|
104
|
+
const sampleRatio = Math.min(1, maxCount / paths.length);
|
|
105
|
+
if (sampleRatio < 1) {
|
|
106
|
+
Console_1.default.warning('Sampling trace due to a large number of traces:');
|
|
107
|
+
Console_1.default.lowLevel(` Number of Traces: ${paths.length}`);
|
|
108
|
+
Console_1.default.lowLevel(` Sampling Ratio: ${Utils_1.default.getReadablePercent(sampleRatio)}`);
|
|
109
|
+
}
|
|
110
|
+
const ret = [];
|
|
111
|
+
for (const p of paths) {
|
|
112
|
+
if (Math.random() < sampleRatio) {
|
|
113
|
+
ret.push(p);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return ret;
|
|
117
|
+
}
|
|
118
|
+
static diffTraces(newTraces, existingTraces, // existing representative traces
|
|
119
|
+
option = {}) {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
const strategy = (_b = (_a = option.strategy) !== null && _a !== void 0 ? _a : Config_1.default.clusterStrategy) !== null && _b !== void 0 ? _b : new TraceSimilarityStrategy_1.default();
|
|
122
|
+
return strategy.diffTraces(newTraces, existingTraces);
|
|
123
|
+
}
|
|
124
|
+
static diffClusters(newClusters, existingClusters) {
|
|
125
|
+
Console_1.default.overwrite('Diffing clusters');
|
|
126
|
+
// build trace to cluster map
|
|
127
|
+
const traceToClusterMap = new Map();
|
|
128
|
+
const newTraces = [];
|
|
129
|
+
const convertOption = { untilFirstDetachedDOMElem: true };
|
|
130
|
+
for (const cluster of newClusters) {
|
|
131
|
+
const trace = NormalizedTrace.pathToTrace(cluster.path, convertOption);
|
|
132
|
+
newTraces.push(trace);
|
|
133
|
+
traceToClusterMap.set(trace, cluster);
|
|
134
|
+
}
|
|
135
|
+
const existingTraces = [];
|
|
136
|
+
for (const cluster of existingClusters) {
|
|
137
|
+
const trace = NormalizedTrace.pathToTrace(cluster.path, convertOption);
|
|
138
|
+
existingTraces.push(trace);
|
|
139
|
+
traceToClusterMap.set(trace, cluster);
|
|
140
|
+
}
|
|
141
|
+
// differing representative traces in existing clusters vs new traces
|
|
142
|
+
// and calculate which representative traces are stale
|
|
143
|
+
// and which new traces should form new clusters
|
|
144
|
+
const traceDiff = NormalizedTrace.diffTraces(newTraces, existingTraces);
|
|
145
|
+
const { staleClusters, clustersToAdd, allClusters } = traceDiff;
|
|
146
|
+
// map trace to cluster
|
|
147
|
+
const traceToCluster = (trace) => {
|
|
148
|
+
if (!traceToClusterMap.has(trace)) {
|
|
149
|
+
throw Utils_1.default.haltOrThrow('trace to cluster mapping failed');
|
|
150
|
+
}
|
|
151
|
+
return traceToClusterMap.get(trace);
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
staleClusters: staleClusters.map(traceToCluster),
|
|
155
|
+
clustersToAdd: clustersToAdd.map(traceToCluster),
|
|
156
|
+
allClusters: allClusters.map(cluster => cluster.map(traceToCluster)),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
static clusterLeakTraces(leakTraces) {
|
|
160
|
+
const { allClusters } = NormalizedTrace.diffTraces(leakTraces, []);
|
|
161
|
+
const lastNodeFromTrace = (trace) => trace[trace.length - 1];
|
|
162
|
+
const labaledLeakTraces = allClusters.reduce((acc, bucket) => {
|
|
163
|
+
const lastNodeFromFirstTrace = lastNodeFromTrace(bucket[0]);
|
|
164
|
+
bucket.map(lastNodeFromTrace).forEach(lastNodeInTrace => {
|
|
165
|
+
if (lastNodeInTrace.id == null || lastNodeFromFirstTrace.id == null) {
|
|
166
|
+
throw new Error('node id not found in last node of the leak trace');
|
|
167
|
+
}
|
|
168
|
+
acc[lastNodeInTrace.id] = String(lastNodeFromFirstTrace.id);
|
|
169
|
+
});
|
|
170
|
+
return acc;
|
|
171
|
+
}, {});
|
|
172
|
+
return labaledLeakTraces;
|
|
173
|
+
}
|
|
174
|
+
static clusterPaths(paths, snapshot, aggregateDominatorMetrics, option = {}) {
|
|
175
|
+
Console_1.default.overwrite('Clustering leak traces');
|
|
176
|
+
if (paths.length === 0) {
|
|
177
|
+
Console_1.default.midLevel('No leaks found');
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
// sample paths if there are too many
|
|
181
|
+
paths = this.samplePaths(paths);
|
|
182
|
+
// build trace to path map
|
|
183
|
+
const traceToPathMap = new Map();
|
|
184
|
+
const traces = [];
|
|
185
|
+
for (const p of paths) {
|
|
186
|
+
const trace = NormalizedTrace.pathToTrace(p, {
|
|
187
|
+
untilFirstDetachedDOMElem: true,
|
|
188
|
+
});
|
|
189
|
+
traceToPathMap.set(trace, p);
|
|
190
|
+
traces.push(trace);
|
|
191
|
+
}
|
|
192
|
+
// cluster traces
|
|
193
|
+
const { allClusters } = NormalizedTrace.diffTraces(traces, [], option);
|
|
194
|
+
// construct TraceCluster from clustering result
|
|
195
|
+
const clusters = allClusters.map((traces) => {
|
|
196
|
+
const cluster = {
|
|
197
|
+
path: traceToPathMap.get(traces[0]),
|
|
198
|
+
count: traces.length,
|
|
199
|
+
snapshot,
|
|
200
|
+
retainedSize: 0,
|
|
201
|
+
};
|
|
202
|
+
traces.forEach((trace) => {
|
|
203
|
+
NormalizedTrace.addLeakedNodeToCluster(cluster, traceToPathMap.get(trace));
|
|
204
|
+
});
|
|
205
|
+
this.calculateClusterRetainedSize(cluster, snapshot, aggregateDominatorMetrics);
|
|
206
|
+
return cluster;
|
|
207
|
+
});
|
|
208
|
+
clusters.sort((c1, c2) => { var _a, _b; return ((_a = c2.retainedSize) !== null && _a !== void 0 ? _a : 0) - ((_b = c1.retainedSize) !== null && _b !== void 0 ? _b : 0); });
|
|
209
|
+
Console_1.default.midLevel(`MemLab found ${clusters.length} leak(s)`);
|
|
210
|
+
return clusters;
|
|
211
|
+
}
|
|
212
|
+
static generateUnClassifiedClusters(paths, snapshot, aggregateDominatorMetrics) {
|
|
213
|
+
return this.clusterPaths(paths, snapshot, aggregateDominatorMetrics, {
|
|
214
|
+
strategy: new TraceAsClusterStrategy_1.default(),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
static loadCluster() {
|
|
218
|
+
let ret = [];
|
|
219
|
+
const file = Config_1.default.traceClusterFile;
|
|
220
|
+
if (!fs_1.default.existsSync(file)) {
|
|
221
|
+
return ret;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const content = fs_1.default.readFileSync(file, 'UTF-8');
|
|
225
|
+
ret = JSON.parse(content);
|
|
226
|
+
}
|
|
227
|
+
catch (ex) {
|
|
228
|
+
throw Utils_1.default.haltOrThrow(Utils_1.default.getError(ex));
|
|
229
|
+
}
|
|
230
|
+
return ret;
|
|
231
|
+
}
|
|
232
|
+
static saveCluster(clusters) {
|
|
233
|
+
const file = Config_1.default.traceClusterFile;
|
|
234
|
+
const content = JSON.stringify(clusters, null, 2);
|
|
235
|
+
fs_1.default.writeFileSync(file, content, 'UTF-8');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.default = NormalizedTrace;
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { EdgeIterationCallback, IHeapEdge, IHeapLocation, IHeapNode, IHeapSnapshot, IHeapStringNode, Nullable } from '../lib/Types';
|
|
11
|
+
export declare class NodeRecord implements IHeapNode {
|
|
12
|
+
kind: string;
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
id: number;
|
|
16
|
+
is_detached: boolean;
|
|
17
|
+
detachState: number;
|
|
18
|
+
attributes: number;
|
|
19
|
+
self_size: number;
|
|
20
|
+
edge_count: number;
|
|
21
|
+
trace_node_id: number;
|
|
22
|
+
nodeIndex: number;
|
|
23
|
+
retainedSize: number;
|
|
24
|
+
highlight?: boolean;
|
|
25
|
+
markAsDetached(): void;
|
|
26
|
+
get isString(): boolean;
|
|
27
|
+
set isString(b: boolean);
|
|
28
|
+
set snapshot(s: IHeapSnapshot);
|
|
29
|
+
get snapshot(): IHeapSnapshot;
|
|
30
|
+
set references(r: IHeapEdge[]);
|
|
31
|
+
get references(): IHeapEdge[];
|
|
32
|
+
forEachReference(_callback: EdgeIterationCallback): void;
|
|
33
|
+
set referrers(r: IHeapEdge[]);
|
|
34
|
+
get referrers(): IHeapEdge[];
|
|
35
|
+
toStringNode(): IHeapStringNode;
|
|
36
|
+
forEachReferrer(_callback: EdgeIterationCallback): void;
|
|
37
|
+
findReference(): Nullable<IHeapEdge>;
|
|
38
|
+
findAnyReferrer(): Nullable<IHeapEdge>;
|
|
39
|
+
findReferrers(): IHeapEdge[];
|
|
40
|
+
set pathEdge(r: IHeapEdge);
|
|
41
|
+
get pathEdge(): IHeapEdge;
|
|
42
|
+
set dominatorNode(r: IHeapNode);
|
|
43
|
+
get dominatorNode(): IHeapNode;
|
|
44
|
+
set location(r: IHeapLocation);
|
|
45
|
+
get location(): IHeapLocation;
|
|
46
|
+
getReference(_edgeName: string | number, _edgeType?: string): Nullable<IHeapEdge>;
|
|
47
|
+
getReferenceNode(_edgeName: string | number, _edgeType?: string): Nullable<IHeapNode>;
|
|
48
|
+
getAnyReferrer(_edgeName: string | number, _edgeType?: string): Nullable<IHeapEdge>;
|
|
49
|
+
getAnyReferrerNode(_edgeName: string | number, _edgeType?: string): Nullable<IHeapNode>;
|
|
50
|
+
getReferrers(_edgeName: string | number, _edgeType?: string): IHeapEdge[];
|
|
51
|
+
getReferrerNodes(_edgeName: string | number, _edgeType?: string): IHeapNode[];
|
|
52
|
+
constructor(node: IHeapNode);
|
|
53
|
+
private extraceNodeName;
|
|
54
|
+
}
|
|
55
|
+
export declare class EdgeRecord implements IHeapEdge {
|
|
56
|
+
kind: string;
|
|
57
|
+
name_or_index: string | number;
|
|
58
|
+
type: string;
|
|
59
|
+
edgeIndex: number;
|
|
60
|
+
is_index: boolean;
|
|
61
|
+
to_node: number;
|
|
62
|
+
constructor(edge: IHeapEdge);
|
|
63
|
+
set snapshot(s: IHeapSnapshot);
|
|
64
|
+
get snapshot(): IHeapSnapshot;
|
|
65
|
+
set toNode(s: IHeapNode);
|
|
66
|
+
get toNode(): IHeapNode;
|
|
67
|
+
set fromNode(s: IHeapNode);
|
|
68
|
+
get fromNode(): IHeapNode;
|
|
69
|
+
}
|
|
70
|
+
export declare type NormalizedTraceElement = NodeRecord | EdgeRecord;
|
|
71
|
+
//# sourceMappingURL=TraceElement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceElement.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/TraceElement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.EdgeRecord = exports.NodeRecord = void 0;
|
|
16
|
+
const Utils_1 = __importDefault(require("../lib/Utils"));
|
|
17
|
+
class NodeRecord {
|
|
18
|
+
constructor(node) {
|
|
19
|
+
this.kind = 'node';
|
|
20
|
+
this.name = this.extraceNodeName(node);
|
|
21
|
+
this.type = node.type;
|
|
22
|
+
this.id = node.id;
|
|
23
|
+
this.is_detached = node.is_detached;
|
|
24
|
+
this.detachState = node.detachState;
|
|
25
|
+
this.attributes = node.attributes;
|
|
26
|
+
this.self_size = node.self_size;
|
|
27
|
+
this.edge_count = node.edge_count;
|
|
28
|
+
this.trace_node_id = node.trace_node_id;
|
|
29
|
+
this.nodeIndex = node.nodeIndex;
|
|
30
|
+
this.retainedSize = node.retainedSize;
|
|
31
|
+
this.highlight = node.highlight;
|
|
32
|
+
}
|
|
33
|
+
markAsDetached() {
|
|
34
|
+
throw new Error('NodeRecord.markAsDetached not callable.');
|
|
35
|
+
}
|
|
36
|
+
get isString() {
|
|
37
|
+
const type = this.type;
|
|
38
|
+
return (type === 'string' ||
|
|
39
|
+
type === 'sliced string' ||
|
|
40
|
+
type === 'concatenated string');
|
|
41
|
+
}
|
|
42
|
+
set isString(b) {
|
|
43
|
+
throw new Error('NodeRecord.string cannot be assigned');
|
|
44
|
+
}
|
|
45
|
+
set snapshot(s) {
|
|
46
|
+
throw new Error('NodeRecord.snapshot cannot be assigned.');
|
|
47
|
+
}
|
|
48
|
+
get snapshot() {
|
|
49
|
+
throw new Error('NodeRecord.snapshot cannot be read.');
|
|
50
|
+
}
|
|
51
|
+
set references(r) {
|
|
52
|
+
throw new Error('NodeRecord.references cannot be assigned');
|
|
53
|
+
}
|
|
54
|
+
get references() {
|
|
55
|
+
throw new Error('NodeRecord.references cannot be read');
|
|
56
|
+
}
|
|
57
|
+
forEachReference(
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
59
|
+
_callback) {
|
|
60
|
+
throw new Error('NodeRecord.forEachReference is not implemented');
|
|
61
|
+
}
|
|
62
|
+
set referrers(r) {
|
|
63
|
+
throw new Error('NodeRecord.referrers cannot be assigned');
|
|
64
|
+
}
|
|
65
|
+
get referrers() {
|
|
66
|
+
throw new Error('NodeRecord.referrers cannot be read');
|
|
67
|
+
}
|
|
68
|
+
toStringNode() {
|
|
69
|
+
throw new Error('NodeRecord.toStringNode is not implemented');
|
|
70
|
+
}
|
|
71
|
+
forEachReferrer(
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
73
|
+
_callback) {
|
|
74
|
+
throw new Error('NodeRecord.forEachReferrer is not implemented');
|
|
75
|
+
}
|
|
76
|
+
findReference() {
|
|
77
|
+
throw new Error('NodeRecord.findReference is not implemented');
|
|
78
|
+
}
|
|
79
|
+
findAnyReferrer() {
|
|
80
|
+
throw new Error('NodeRecord.findAnyReferrer is not implemented');
|
|
81
|
+
}
|
|
82
|
+
findReferrers() {
|
|
83
|
+
throw new Error('NodeRecord.findReferrers is not implemented');
|
|
84
|
+
}
|
|
85
|
+
set pathEdge(r) {
|
|
86
|
+
throw new Error('NodeRecord.pathEdge cannot be assigned');
|
|
87
|
+
}
|
|
88
|
+
get pathEdge() {
|
|
89
|
+
throw new Error('NodeRecord.pathEdge cannot be read');
|
|
90
|
+
}
|
|
91
|
+
set dominatorNode(r) {
|
|
92
|
+
throw new Error('NodeRecord.pathEdge cannot be assigned');
|
|
93
|
+
}
|
|
94
|
+
get dominatorNode() {
|
|
95
|
+
throw new Error('NodeRecord.pathEdge cannot be read');
|
|
96
|
+
}
|
|
97
|
+
set location(r) {
|
|
98
|
+
throw new Error('NodeRecord.location cannot be assigned');
|
|
99
|
+
}
|
|
100
|
+
get location() {
|
|
101
|
+
throw new Error('NodeRecord.location cannot be read');
|
|
102
|
+
}
|
|
103
|
+
getReference(
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
105
|
+
_edgeName,
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
107
|
+
_edgeType) {
|
|
108
|
+
throw new Error('NodeRecord.getReference is not implemented');
|
|
109
|
+
}
|
|
110
|
+
getReferenceNode(
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
112
|
+
_edgeName,
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
114
|
+
_edgeType) {
|
|
115
|
+
throw new Error('NodeRecord.getReferenceNode is not implemented');
|
|
116
|
+
}
|
|
117
|
+
getAnyReferrer(
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
119
|
+
_edgeName,
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
121
|
+
_edgeType) {
|
|
122
|
+
throw new Error('NodeRecord.getReferrer is not implemented');
|
|
123
|
+
}
|
|
124
|
+
getAnyReferrerNode(
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
126
|
+
_edgeName,
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
128
|
+
_edgeType) {
|
|
129
|
+
throw new Error('NodeRecord.getReferrerNode is not implemented');
|
|
130
|
+
}
|
|
131
|
+
getReferrers(
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
133
|
+
_edgeName,
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
135
|
+
_edgeType) {
|
|
136
|
+
throw new Error('NodeRecord.getReferrers is not implemented');
|
|
137
|
+
}
|
|
138
|
+
getReferrerNodes(
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
140
|
+
_edgeName,
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
142
|
+
_edgeType) {
|
|
143
|
+
throw new Error('NodeRecord.getReferrerNodes is not implemented');
|
|
144
|
+
}
|
|
145
|
+
extraceNodeName(node) {
|
|
146
|
+
// deserialized node may not have snapshot info
|
|
147
|
+
if (!node.snapshot || !Utils_1.default.isFiberNode(node)) {
|
|
148
|
+
return node.name;
|
|
149
|
+
}
|
|
150
|
+
return Utils_1.default.extractFiberNodeInfo(node);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.NodeRecord = NodeRecord;
|
|
154
|
+
class EdgeRecord {
|
|
155
|
+
constructor(edge) {
|
|
156
|
+
this.kind = 'edge';
|
|
157
|
+
this.name_or_index = edge.name_or_index;
|
|
158
|
+
this.type = edge.type;
|
|
159
|
+
this.edgeIndex = edge.edgeIndex;
|
|
160
|
+
this.is_index = edge.is_index;
|
|
161
|
+
this.to_node = edge.to_node;
|
|
162
|
+
}
|
|
163
|
+
set snapshot(s) {
|
|
164
|
+
throw new Error('EdgeRecord.snapshot cannot be assigned.');
|
|
165
|
+
}
|
|
166
|
+
get snapshot() {
|
|
167
|
+
throw new Error('EdgeRecord.snapshot cannot be read.');
|
|
168
|
+
}
|
|
169
|
+
set toNode(s) {
|
|
170
|
+
throw new Error('EdgeRecord.toNode cannot be assigned.');
|
|
171
|
+
}
|
|
172
|
+
get toNode() {
|
|
173
|
+
throw new Error('EdgeRecord.toNode cannot be read.');
|
|
174
|
+
}
|
|
175
|
+
set fromNode(s) {
|
|
176
|
+
throw new Error('EdgeRecord.fromNode cannot be assigned.');
|
|
177
|
+
}
|
|
178
|
+
get fromNode() {
|
|
179
|
+
throw new Error('EdgeRecord.fromNode cannot be read.');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
exports.EdgeRecord = EdgeRecord;
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { IClusterStrategy, LeakTrace, TraceDiff } from '../../lib/Types';
|
|
11
|
+
export default class TraceAsClusterStrategy implements IClusterStrategy {
|
|
12
|
+
diffTraces(newTraces: LeakTrace[], existingTraces: LeakTrace[]): TraceDiff;
|
|
13
|
+
static isSimilarTrace(t1: LeakTrace, t2: LeakTrace): boolean;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=TraceAsClusterStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceAsClusterStrategy.d.ts","sourceRoot":"","sources":["../../../src/trace-cluster/strategies/TraceAsClusterStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAI5E,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,gBAAgB;IAC9D,UAAU,CACf,SAAS,EAAE,SAAS,EAAE,EACtB,cAAc,EAAE,SAAS,EAAE,GAC1B,SAAS;IAkBZ,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO;CAG7D"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const ClusterUtils_1 = __importDefault(require("../ClusterUtils"));
|
|
16
|
+
// each trace is a cluster
|
|
17
|
+
class TraceAsClusterStrategy {
|
|
18
|
+
diffTraces(newTraces, existingTraces) {
|
|
19
|
+
// duplicated cluster to remove
|
|
20
|
+
const staleClusters = [];
|
|
21
|
+
// new cluster to save
|
|
22
|
+
const clustersToAdd = [];
|
|
23
|
+
// all clusters, with duplicated cluters in the same sub-array
|
|
24
|
+
const clusters = existingTraces.map(trace => [trace]);
|
|
25
|
+
// checking new clusters
|
|
26
|
+
for (let i = 0; i < newTraces.length; ++i) {
|
|
27
|
+
const traceToCheck = newTraces[i];
|
|
28
|
+
clustersToAdd.push(traceToCheck);
|
|
29
|
+
clusters.push([traceToCheck]);
|
|
30
|
+
}
|
|
31
|
+
return { staleClusters, clustersToAdd, allClusters: clusters };
|
|
32
|
+
}
|
|
33
|
+
static isSimilarTrace(t1, t2) {
|
|
34
|
+
return ClusterUtils_1.default.isSimilarTrace(t1, t2);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.default = TraceAsClusterStrategy;
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
import type { IClusterStrategy, LeakTrace, TraceDiff } from '../../lib/Types';
|
|
11
|
+
export default class TraceSimilarityStrategy implements IClusterStrategy {
|
|
12
|
+
diffTraces(newTraces: LeakTrace[], existingTraces: LeakTrace[]): TraceDiff;
|
|
13
|
+
static isSimilarTrace(t1: LeakTrace, t2: LeakTrace): boolean;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=TraceSimilarityStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceSimilarityStrategy.d.ts","sourceRoot":"","sources":["../../../src/trace-cluster/strategies/TraceSimilarityStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAI5E,MAAM,CAAC,OAAO,OAAO,uBAAwB,YAAW,gBAAgB;IAC/D,UAAU,CACf,SAAS,EAAE,SAAS,EAAE,EACtB,cAAc,EAAE,SAAS,EAAE,GAC1B,SAAS;IA0CZ,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO;CAG7D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const ClusterUtils_1 = __importDefault(require("../ClusterUtils"));
|
|
16
|
+
// cluster by putting similar traces together
|
|
17
|
+
class TraceSimilarityStrategy {
|
|
18
|
+
diffTraces(newTraces, existingTraces) {
|
|
19
|
+
// duplicated cluster to remove
|
|
20
|
+
const staleClusters = [];
|
|
21
|
+
// new cluster to save
|
|
22
|
+
const clustersToAdd = [];
|
|
23
|
+
// all clusters, with duplicated cluters in the same sub-array
|
|
24
|
+
const clusters = [];
|
|
25
|
+
// consolidating existing clusters
|
|
26
|
+
if (existingTraces.length > 0) {
|
|
27
|
+
clusters.push([existingTraces[0]]);
|
|
28
|
+
outer: for (let i = 1; i < existingTraces.length; ++i) {
|
|
29
|
+
const traceToCheck = existingTraces[i];
|
|
30
|
+
for (let j = 0; j < clusters.length; ++j) {
|
|
31
|
+
const repTrace = clusters[j][0];
|
|
32
|
+
if (TraceSimilarityStrategy.isSimilarTrace(repTrace, traceToCheck)) {
|
|
33
|
+
staleClusters.push(traceToCheck);
|
|
34
|
+
clusters[j].push(traceToCheck);
|
|
35
|
+
continue outer;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
clusters.push([traceToCheck]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// checking new clusters
|
|
42
|
+
outer: for (let i = 0; i < newTraces.length; ++i) {
|
|
43
|
+
const traceToCheck = newTraces[i];
|
|
44
|
+
for (let j = 0; j < clusters.length; ++j) {
|
|
45
|
+
const repTrace = clusters[j][0];
|
|
46
|
+
if (TraceSimilarityStrategy.isSimilarTrace(repTrace, traceToCheck)) {
|
|
47
|
+
clusters[j].push(traceToCheck);
|
|
48
|
+
continue outer;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
clustersToAdd.push(traceToCheck);
|
|
52
|
+
clusters.push([traceToCheck]);
|
|
53
|
+
}
|
|
54
|
+
return { staleClusters, clustersToAdd, allClusters: clusters };
|
|
55
|
+
}
|
|
56
|
+
static isSimilarTrace(t1, t2) {
|
|
57
|
+
return ClusterUtils_1.default.isSimilarTrace(t1, t2);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.default = TraceSimilarityStrategy;
|