@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,31 @@
|
|
|
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 { AnyOptions, HeapNodeIdSet, IHeapEdge, IHeapNode, IHeapSnapshot, LeakTracePathItem, Nullable, Optional, Predicator } from '../lib/Types';
|
|
11
|
+
declare class TraceFinder {
|
|
12
|
+
getRootNodeList(snapshot: IHeapSnapshot, opt?: {
|
|
13
|
+
prioritize?: boolean;
|
|
14
|
+
}): [IHeapNode[], IHeapNode[]];
|
|
15
|
+
visitReachableNodesbyDFS(snapshot: IHeapSnapshot, nodeVisitor?: Optional<Predicator<IHeapNode>>, edgeVisitor?: Optional<Predicator<IHeapEdge>>): void;
|
|
16
|
+
flagReachableNodesFromWindow(snapshot: IHeapSnapshot, flags: Uint32Array, flag: number): void;
|
|
17
|
+
private buildPostOrderIndex;
|
|
18
|
+
private calculateDominatorNodesFromPostOrder;
|
|
19
|
+
private calculateRetainedSizesFromDominatorNodes;
|
|
20
|
+
shouldIgnoreEdgeInTraceFinding(edge: IHeapEdge): boolean;
|
|
21
|
+
shouldTraverseEdge(edge: IHeapEdge, options?: AnyOptions): boolean;
|
|
22
|
+
isBlockListedEdge(edge: IHeapEdge): boolean;
|
|
23
|
+
isLessPreferableEdge(edge: IHeapEdge): boolean;
|
|
24
|
+
isLessPreferableNode(node: IHeapNode): boolean;
|
|
25
|
+
getEdgeKey(edge: IHeapEdge): string;
|
|
26
|
+
calculateAllNodesRetainedSizes(snapshot: IHeapSnapshot): void;
|
|
27
|
+
annotateShortestPaths(snapshot: IHeapSnapshot, excludeKeySet?: HeapNodeIdSet): void;
|
|
28
|
+
getPathToGCRoots(_snapshot: IHeapSnapshot, node: Nullable<IHeapNode>): Optional<LeakTracePathItem>;
|
|
29
|
+
}
|
|
30
|
+
export default TraceFinder;
|
|
31
|
+
//# sourceMappingURL=TraceFinder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceFinder.d.ts","sourceRoot":"","sources":["../../src/paths/TraceFinder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,SAAS,EAET,SAAS,EAET,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,cAAc,CAAC;AActB,cAAM,WAAW;IACf,eAAe,CACb,QAAQ,EAAE,aAAa,EACvB,GAAG,GAAE;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAM,GAC/B,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,CAAC;IA0B7B,wBAAwB,CACtB,QAAQ,EAAE,aAAa,EACvB,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAC7C,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,GAC5C,IAAI;IA6CP,4BAA4B,CAC1B,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GACX,IAAI;IA2CP,OAAO,CAAC,mBAAmB;IAoJ3B,OAAO,CAAC,oCAAoC;IAyJ5C,OAAO,CAAC,wCAAwC;IA4BhD,8BAA8B,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO;IAYxD,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO;IAQtE,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO;IAmB3C,oBAAoB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO;IAO9C,oBAAoB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO;IAQ9C,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM;IAMnC,8BAA8B,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IA2B7D,qBAAqB,CACnB,QAAQ,EAAE,aAAa,EACvB,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI;IA2EP,gBAAgB,CACd,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,GACxB,QAAQ,CAAC,iBAAiB,CAAC;CAY/B;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,537 @@
|
|
|
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 Config_1 = __importDefault(require("../lib/Config"));
|
|
16
|
+
const Console_1 = __importDefault(require("../lib/Console"));
|
|
17
|
+
const Utils_1 = __importDefault(require("../lib/Utils"));
|
|
18
|
+
const ROOT_NODE_INDEX = 0;
|
|
19
|
+
const PAGE_OBJECT_FLAG = 1;
|
|
20
|
+
class TraceFinder {
|
|
21
|
+
getRootNodeList(snapshot, opt = {}) {
|
|
22
|
+
const highPri = [];
|
|
23
|
+
const lowPri = [];
|
|
24
|
+
if (opt.prioritize) {
|
|
25
|
+
snapshot.nodes.forEach(node => {
|
|
26
|
+
if (Utils_1.default.isRootNode(node, {
|
|
27
|
+
excludeBlinkRoot: true,
|
|
28
|
+
excludePendingActivity: true,
|
|
29
|
+
})) {
|
|
30
|
+
highPri.push(node);
|
|
31
|
+
}
|
|
32
|
+
else if (Utils_1.default.isRootNode(node)) {
|
|
33
|
+
lowPri.push(node);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
snapshot.nodes.forEach(node => {
|
|
39
|
+
if (Utils_1.default.isRootNode(node)) {
|
|
40
|
+
highPri.push(node);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return [highPri, lowPri];
|
|
45
|
+
}
|
|
46
|
+
visitReachableNodesbyDFS(snapshot, nodeVisitor, edgeVisitor) {
|
|
47
|
+
const [queue] = this.getRootNodeList(snapshot);
|
|
48
|
+
const queuedIDs = new Set(queue.map(n => n.id));
|
|
49
|
+
const visitedIDs = new Set();
|
|
50
|
+
const traverseOption = {
|
|
51
|
+
visited: visitedIDs,
|
|
52
|
+
queued: queuedIDs,
|
|
53
|
+
excludeWeakMapEdge: false,
|
|
54
|
+
isForward: true,
|
|
55
|
+
};
|
|
56
|
+
while (queue.length > 0) {
|
|
57
|
+
const node = queue.pop();
|
|
58
|
+
if (!node || visitedIDs.has(node.id)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (nodeVisitor && nodeVisitor(node) === false) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
visitedIDs.add(node.id);
|
|
65
|
+
for (const edge of node.references) {
|
|
66
|
+
if (!this.shouldTraverseEdge(edge, traverseOption)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const nextNode = edge.toNode;
|
|
70
|
+
// deal with weak map specifically
|
|
71
|
+
if (Utils_1.default.isWeakMapEdgeToKey(edge)) {
|
|
72
|
+
const weakMapKeyObjectId = Utils_1.default.getWeakMapEdgeKeyId(edge);
|
|
73
|
+
// in weak map keys are weakly referenced
|
|
74
|
+
if (weakMapKeyObjectId === nextNode.id) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (edgeVisitor && edgeVisitor(edge) === false) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
queue.push(nextNode);
|
|
82
|
+
queuedIDs.add(nextNode.id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
flagReachableNodesFromWindow(snapshot, flags, flag) {
|
|
87
|
+
const nodesCount = snapshot.nodes.length;
|
|
88
|
+
const nodesToVisit = new Uint32Array(nodesCount);
|
|
89
|
+
let nodesToVisitLength = 0;
|
|
90
|
+
const node = snapshot.nodes.get(ROOT_NODE_INDEX);
|
|
91
|
+
for (const edge of node.references) {
|
|
92
|
+
if (edge.type === 'element') {
|
|
93
|
+
if (Utils_1.default.isDocumentDOMTreesRoot(edge.toNode)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (edge.type === 'shortcut') {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const childNodeIndex = edge.toNode.nodeIndex;
|
|
101
|
+
nodesToVisit[nodesToVisitLength++] = childNodeIndex;
|
|
102
|
+
flags[childNodeIndex] |= flag;
|
|
103
|
+
}
|
|
104
|
+
// flag all heap objects reachable from the root
|
|
105
|
+
while (nodesToVisitLength > 0) {
|
|
106
|
+
const nodeIndex = nodesToVisit[--nodesToVisitLength];
|
|
107
|
+
const node = snapshot.nodes.get(nodeIndex);
|
|
108
|
+
for (const edge of node.references) {
|
|
109
|
+
const childNode = edge.toNode;
|
|
110
|
+
const childNodeIndex = childNode.nodeIndex;
|
|
111
|
+
if (flags[childNodeIndex] & flag) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (edge.type === 'weak') {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
nodesToVisit[nodesToVisitLength++] = childNodeIndex;
|
|
118
|
+
flags[childNodeIndex] |= flag;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// build post order based on:
|
|
123
|
+
// Keith D. Cooper and Timothy J. Harvey and Ken Kennedy
|
|
124
|
+
// "A Simple, Fast Dominance Algorithm"
|
|
125
|
+
buildPostOrderIndex(snapshot, flags) {
|
|
126
|
+
const nodeCount = snapshot.nodes.length;
|
|
127
|
+
const rootNodeIndex = ROOT_NODE_INDEX;
|
|
128
|
+
const forwardEdges = snapshot.edges;
|
|
129
|
+
const firstEdgeIndexes = new Uint32Array(nodeCount + 1);
|
|
130
|
+
firstEdgeIndexes[nodeCount] = forwardEdges.length;
|
|
131
|
+
for (let nodeIndex = 0, edgeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
|
|
132
|
+
firstEdgeIndexes[nodeIndex] = edgeIndex;
|
|
133
|
+
edgeIndex += snapshot.nodes.get(nodeIndex).edge_count;
|
|
134
|
+
}
|
|
135
|
+
const flag = PAGE_OBJECT_FLAG;
|
|
136
|
+
const nodeStack = new Uint32Array(nodeCount);
|
|
137
|
+
const edgeStack = new Uint32Array(nodeCount);
|
|
138
|
+
const postOrderIndex2NodeIndex = new Uint32Array(nodeCount);
|
|
139
|
+
const nodeIndex2PostOrderIndex = new Uint32Array(nodeCount);
|
|
140
|
+
const visited = new Uint8Array(nodeCount);
|
|
141
|
+
let postOrderIndex = 0;
|
|
142
|
+
// build a DFS stack and put the root node
|
|
143
|
+
// at the bottom of the stack
|
|
144
|
+
let stackTopIndex = 0;
|
|
145
|
+
nodeStack[0] = rootNodeIndex;
|
|
146
|
+
edgeStack[0] = firstEdgeIndexes[rootNodeIndex];
|
|
147
|
+
visited[rootNodeIndex] = 1;
|
|
148
|
+
let iteratedOnce = false;
|
|
149
|
+
// eslint-disable-next-line no-constant-condition
|
|
150
|
+
while (true) {
|
|
151
|
+
// use DFS to traverse all nodes via a stack
|
|
152
|
+
while (stackTopIndex >= 0) {
|
|
153
|
+
const nodeIndex = nodeStack[stackTopIndex];
|
|
154
|
+
const edgeIndex = edgeStack[stackTopIndex];
|
|
155
|
+
const edgesEnd = firstEdgeIndexes[nodeIndex + 1];
|
|
156
|
+
if (edgeIndex < edgesEnd) {
|
|
157
|
+
edgeStack[stackTopIndex]++;
|
|
158
|
+
const edgeType = forwardEdges.get(edgeIndex).type;
|
|
159
|
+
if (!Utils_1.default.isEssentialEdge(nodeIndex, edgeType, rootNodeIndex)) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const childNodeIndex = forwardEdges.get(edgeIndex).toNode.nodeIndex;
|
|
163
|
+
if (visited[childNodeIndex]) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const nodeFlag = flags[nodeIndex] & flag;
|
|
167
|
+
const childNodeFlag = flags[childNodeIndex] & flag;
|
|
168
|
+
// According to Chrome devtools, need to skip the edges from
|
|
169
|
+
// non-page-owned nodes to page-owned nodes (since debugger may
|
|
170
|
+
// also have references to heap objects)
|
|
171
|
+
if (nodeIndex !== rootNodeIndex && childNodeFlag && !nodeFlag) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
++stackTopIndex;
|
|
175
|
+
nodeStack[stackTopIndex] = childNodeIndex;
|
|
176
|
+
edgeStack[stackTopIndex] = firstEdgeIndexes[childNodeIndex];
|
|
177
|
+
visited[childNodeIndex] = 1;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// DFS is done, now build the post order based on the stack
|
|
181
|
+
nodeIndex2PostOrderIndex[nodeIndex] = postOrderIndex;
|
|
182
|
+
postOrderIndex2NodeIndex[postOrderIndex++] = nodeIndex;
|
|
183
|
+
--stackTopIndex;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// If we have tried by build the stack once previously
|
|
187
|
+
// or we have already built the post order for all nodes
|
|
188
|
+
if (iteratedOnce || postOrderIndex === nodeCount) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
// Otherwise there are some nodes unreachable from
|
|
192
|
+
// the root node
|
|
193
|
+
if (Config_1.default.verbose) {
|
|
194
|
+
Console_1.default.overwrite(`${nodeCount - postOrderIndex} nodes are unreachable from the root`);
|
|
195
|
+
}
|
|
196
|
+
// Now the root node has the last post order index and
|
|
197
|
+
// the DFS stack is empty; we need to put the root node
|
|
198
|
+
// back to the bottom of the DFS stack, traverse all the
|
|
199
|
+
// orphan nodes with weak referrers (nodes unreachable
|
|
200
|
+
// from the root), and make sure the root node has the
|
|
201
|
+
// last post order index
|
|
202
|
+
--postOrderIndex;
|
|
203
|
+
stackTopIndex = 0;
|
|
204
|
+
nodeStack[0] = rootNodeIndex;
|
|
205
|
+
// skip iterating the edges of the root node
|
|
206
|
+
edgeStack[0] = firstEdgeIndexes[rootNodeIndex + 1];
|
|
207
|
+
for (let nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
|
|
208
|
+
if (visited[nodeIndex] ||
|
|
209
|
+
!Utils_1.default.hasOnlyWeakReferrers(snapshot.nodes.get(nodeIndex))) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
// Add all nodes that have only weak referrers
|
|
213
|
+
// to traverse their subgraphs
|
|
214
|
+
++stackTopIndex;
|
|
215
|
+
nodeStack[stackTopIndex] = nodeIndex;
|
|
216
|
+
edgeStack[stackTopIndex] = firstEdgeIndexes[nodeIndex];
|
|
217
|
+
visited[nodeIndex] = nodeIndex;
|
|
218
|
+
}
|
|
219
|
+
iteratedOnce = true;
|
|
220
|
+
}
|
|
221
|
+
// If we already processed all orphan nodes (nodes unreachable from root)
|
|
222
|
+
// that have only weak referrers and still have some orphans
|
|
223
|
+
if (postOrderIndex !== nodeCount) {
|
|
224
|
+
if (Config_1.default.verbose) {
|
|
225
|
+
Console_1.default.lowLevel(nodeCount - postOrderIndex + ' unreachable nodes in heap snapshot');
|
|
226
|
+
}
|
|
227
|
+
// Now the root node has the last post order index and
|
|
228
|
+
// the DFS stack is empty; we need to put the root node
|
|
229
|
+
// back to the bottom of the DFS stack, traverse all the
|
|
230
|
+
// remaining orphan nodes (nodes unreachable from the root),
|
|
231
|
+
// and make sure the root node has the last post order index
|
|
232
|
+
--postOrderIndex;
|
|
233
|
+
for (let nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
|
|
234
|
+
if (visited[nodeIndex]) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
// give the orphan node a postorder index anyway
|
|
238
|
+
nodeIndex2PostOrderIndex[nodeIndex] = postOrderIndex;
|
|
239
|
+
postOrderIndex2NodeIndex[postOrderIndex++] = nodeIndex;
|
|
240
|
+
}
|
|
241
|
+
nodeIndex2PostOrderIndex[rootNodeIndex] = postOrderIndex;
|
|
242
|
+
postOrderIndex2NodeIndex[postOrderIndex++] = rootNodeIndex;
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
postOrderIndex2NodeIndex,
|
|
246
|
+
nodeIndex2PostOrderIndex,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// The dominance algorithm is from:
|
|
250
|
+
// Keith D. Cooper and Timothy J. Harvey and Ken Kennedy
|
|
251
|
+
// "A Simple, Fast Dominance Algorithm"
|
|
252
|
+
calculateDominatorNodesFromPostOrder(nodes, edges, postOrderInfo, flags) {
|
|
253
|
+
const { postOrderIndex2NodeIndex, nodeIndex2PostOrderIndex } = postOrderInfo;
|
|
254
|
+
const nodeCount = nodes.length;
|
|
255
|
+
const forwardEdges = edges;
|
|
256
|
+
const firstEdgeIndexes = new Uint32Array(nodeCount + 1);
|
|
257
|
+
firstEdgeIndexes[nodeCount] = forwardEdges.length;
|
|
258
|
+
for (let nodeIndex = 0, edgeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
|
|
259
|
+
firstEdgeIndexes[nodeIndex] = edgeIndex;
|
|
260
|
+
edgeIndex += nodes.get(nodeIndex).edge_count;
|
|
261
|
+
}
|
|
262
|
+
const flag = PAGE_OBJECT_FLAG;
|
|
263
|
+
const rootPostOrderedIndex = nodeCount - 1;
|
|
264
|
+
const emptySlot = nodeCount;
|
|
265
|
+
const dominators = new Uint32Array(nodeCount);
|
|
266
|
+
for (let i = 0; i < rootPostOrderedIndex; ++i) {
|
|
267
|
+
dominators[i] = emptySlot;
|
|
268
|
+
}
|
|
269
|
+
dominators[rootPostOrderedIndex] = rootPostOrderedIndex;
|
|
270
|
+
// flag heap objects whose referrers changed and therefore
|
|
271
|
+
// the dominators of those heap objects needs to be recomputed
|
|
272
|
+
const nodesWithOutdatedDominatorInfo = new Uint8Array(nodeCount);
|
|
273
|
+
// start from the direct children of the root node
|
|
274
|
+
let nodeIndex = ROOT_NODE_INDEX;
|
|
275
|
+
const endEdgeIndex = firstEdgeIndexes[nodeIndex + 1];
|
|
276
|
+
for (let edgeIndex = firstEdgeIndexes[nodeIndex]; edgeIndex < endEdgeIndex; edgeIndex++) {
|
|
277
|
+
const edgeType = forwardEdges.get(edgeIndex).type;
|
|
278
|
+
if (!Utils_1.default.isEssentialEdge(ROOT_NODE_INDEX, edgeType, ROOT_NODE_INDEX)) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const childNodeIndex = forwardEdges.get(edgeIndex).toNode.nodeIndex;
|
|
282
|
+
nodesWithOutdatedDominatorInfo[nodeIndex2PostOrderIndex[childNodeIndex]] = 1;
|
|
283
|
+
}
|
|
284
|
+
// now iterate through all nodes in the heap
|
|
285
|
+
let dominatorInfoChanged = true;
|
|
286
|
+
// iterate until no dominator info changed
|
|
287
|
+
while (dominatorInfoChanged) {
|
|
288
|
+
dominatorInfoChanged = false;
|
|
289
|
+
for (let postOrderIndex = rootPostOrderedIndex - 1; postOrderIndex >= 0; --postOrderIndex) {
|
|
290
|
+
if (nodesWithOutdatedDominatorInfo[postOrderIndex] === 0) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
nodesWithOutdatedDominatorInfo[postOrderIndex] = 0;
|
|
294
|
+
// If dominator of the heap object has already been set to root node,
|
|
295
|
+
// then the heap object's dominator can't be changed anymore
|
|
296
|
+
if (dominators[postOrderIndex] === rootPostOrderedIndex) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
nodeIndex = postOrderIndex2NodeIndex[postOrderIndex];
|
|
300
|
+
const nodeFlag = flags[nodeIndex] & flag;
|
|
301
|
+
let newDominatorIndex = emptySlot;
|
|
302
|
+
let isOrphanNode = true;
|
|
303
|
+
const node = nodes.get(nodeIndex);
|
|
304
|
+
for (const edge of node.referrers) {
|
|
305
|
+
const referrerEdgeType = edge.type;
|
|
306
|
+
const referrerNodeIndex = edge.fromNode.nodeIndex;
|
|
307
|
+
if (!Utils_1.default.isEssentialEdge(referrerNodeIndex, referrerEdgeType, ROOT_NODE_INDEX)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
isOrphanNode = false;
|
|
311
|
+
const referrerNodeFlag = flags[referrerNodeIndex] & flag;
|
|
312
|
+
// According to Chrome devtools, need to skip the edges from
|
|
313
|
+
// non-page-owned nodes to page-owned nodes (since debugger may
|
|
314
|
+
// also have references to heap objects)
|
|
315
|
+
if (referrerNodeIndex !== ROOT_NODE_INDEX &&
|
|
316
|
+
nodeFlag &&
|
|
317
|
+
!referrerNodeFlag) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (!this.shouldTraverseEdge(edge)) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
let referrerPostOrderIndex = nodeIndex2PostOrderIndex[referrerNodeIndex];
|
|
324
|
+
if (dominators[referrerPostOrderIndex] !== emptySlot) {
|
|
325
|
+
if (newDominatorIndex === emptySlot) {
|
|
326
|
+
newDominatorIndex = referrerPostOrderIndex;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
while (referrerPostOrderIndex !== newDominatorIndex) {
|
|
330
|
+
while (referrerPostOrderIndex < newDominatorIndex) {
|
|
331
|
+
referrerPostOrderIndex = dominators[referrerPostOrderIndex];
|
|
332
|
+
}
|
|
333
|
+
while (newDominatorIndex < referrerPostOrderIndex) {
|
|
334
|
+
newDominatorIndex = dominators[newDominatorIndex];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// no need to check any further if reaching the root node
|
|
339
|
+
if (newDominatorIndex === rootPostOrderedIndex) {
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// set root node as the dominator of orphan nodes
|
|
345
|
+
if (isOrphanNode) {
|
|
346
|
+
newDominatorIndex = rootPostOrderedIndex;
|
|
347
|
+
}
|
|
348
|
+
if (newDominatorIndex !== emptySlot &&
|
|
349
|
+
dominators[postOrderIndex] !== newDominatorIndex) {
|
|
350
|
+
dominators[postOrderIndex] = newDominatorIndex;
|
|
351
|
+
dominatorInfoChanged = true;
|
|
352
|
+
nodeIndex = postOrderIndex2NodeIndex[postOrderIndex];
|
|
353
|
+
const node = nodes.get(nodeIndex);
|
|
354
|
+
for (const edge of node.references) {
|
|
355
|
+
nodesWithOutdatedDominatorInfo[nodeIndex2PostOrderIndex[edge.toNode.nodeIndex]] = 1;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const dominatorInfo = new Uint32Array(nodeCount);
|
|
361
|
+
for (let postOrderIndex = 0, l = dominators.length; postOrderIndex < l; ++postOrderIndex) {
|
|
362
|
+
nodeIndex = postOrderIndex2NodeIndex[postOrderIndex];
|
|
363
|
+
dominatorInfo[nodeIndex] =
|
|
364
|
+
postOrderIndex2NodeIndex[dominators[postOrderIndex]];
|
|
365
|
+
}
|
|
366
|
+
return dominatorInfo;
|
|
367
|
+
}
|
|
368
|
+
calculateRetainedSizesFromDominatorNodes(nodes, dominatorInfo, postOrderInfo) {
|
|
369
|
+
const { postOrderIndex2NodeIndex } = postOrderInfo;
|
|
370
|
+
const nodeCount = nodes.length;
|
|
371
|
+
const retainedSizes = new Float64Array(nodeCount);
|
|
372
|
+
for (let nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
|
|
373
|
+
retainedSizes[nodeIndex] = nodes.get(nodeIndex).self_size;
|
|
374
|
+
}
|
|
375
|
+
// add each heap object size to its dominator
|
|
376
|
+
// based on the post order
|
|
377
|
+
for (let postOrderIndex = 0; postOrderIndex < nodeCount - 1; ++postOrderIndex) {
|
|
378
|
+
const nodeIndex = postOrderIndex2NodeIndex[postOrderIndex];
|
|
379
|
+
const dominatorIndex = dominatorInfo[nodeIndex];
|
|
380
|
+
retainedSizes[dominatorIndex] += retainedSizes[nodeIndex];
|
|
381
|
+
}
|
|
382
|
+
return retainedSizes;
|
|
383
|
+
}
|
|
384
|
+
shouldIgnoreEdgeInTraceFinding(edge) {
|
|
385
|
+
if (!edge || !edge.toNode || !edge.fromNode) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
return (Config_1.default.hideBrowserLeak &&
|
|
389
|
+
(Utils_1.default.isBlinkRootNode(edge.fromNode) ||
|
|
390
|
+
Utils_1.default.isPendingActivityNode(edge.fromNode)) &&
|
|
391
|
+
Utils_1.default.isDetachedDOMNode(edge.toNode));
|
|
392
|
+
}
|
|
393
|
+
shouldTraverseEdge(edge, options = {}) {
|
|
394
|
+
if (this.isBlockListedEdge(edge)) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
return Utils_1.default.isMeaningfulEdge(edge, Object.assign({ includeString: true }, options));
|
|
398
|
+
}
|
|
399
|
+
// remove edges that are already part of reported leaked paths
|
|
400
|
+
isBlockListedEdge(edge) {
|
|
401
|
+
if (!edge) {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
const isStrName = typeof edge.name_or_index === 'string';
|
|
405
|
+
if (!Config_1.default.traverseDevToolsConsole &&
|
|
406
|
+
edge.type === 'internal' &&
|
|
407
|
+
isStrName &&
|
|
408
|
+
String(edge.name_or_index).indexOf('DevTools console') >= 0) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
if (Config_1.default.edgeNameBlockList.has(String(edge.name_or_index))) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
isLessPreferableEdge(edge) {
|
|
417
|
+
if (!edge) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
return Config_1.default.edgeNameGreyList.has(String(edge.name_or_index));
|
|
421
|
+
}
|
|
422
|
+
isLessPreferableNode(node) {
|
|
423
|
+
if (!node) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
return Config_1.default.nodeNameGreyList.has(node.name);
|
|
427
|
+
}
|
|
428
|
+
// each edge is indexed by fromNode's ID, toNode's ID, edge name, and edge type
|
|
429
|
+
getEdgeKey(edge) {
|
|
430
|
+
const fromNode = edge.fromNode;
|
|
431
|
+
const toNode = edge.toNode;
|
|
432
|
+
return `${fromNode.id}|${edge.name_or_index}|${edge.type}|${toNode.id}`;
|
|
433
|
+
}
|
|
434
|
+
calculateAllNodesRetainedSizes(snapshot) {
|
|
435
|
+
Console_1.default.overwrite('calculating dominators and retained sizes...');
|
|
436
|
+
// step 1: build post order index
|
|
437
|
+
const flags = new Uint32Array(snapshot.nodes.length);
|
|
438
|
+
this.flagReachableNodesFromWindow(snapshot, flags, PAGE_OBJECT_FLAG);
|
|
439
|
+
const postOrderInfo = this.buildPostOrderIndex(snapshot, flags);
|
|
440
|
+
// step 2: build dominator relations
|
|
441
|
+
const dominatorInfo = this.calculateDominatorNodesFromPostOrder(snapshot.nodes, snapshot.edges, postOrderInfo, flags);
|
|
442
|
+
// step 3: calculate retained sizes
|
|
443
|
+
const retainedSizes = this.calculateRetainedSizesFromDominatorNodes(snapshot.nodes, dominatorInfo, postOrderInfo);
|
|
444
|
+
// step 4: assign retained sizes and dominators to nodes
|
|
445
|
+
for (let i = 0; i < retainedSizes.length; i++) {
|
|
446
|
+
const node = snapshot.nodes.get(i);
|
|
447
|
+
node.retainedSize = retainedSizes[i];
|
|
448
|
+
node.dominatorNode = snapshot.nodes.get(dominatorInfo[i]);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
annotateShortestPaths(snapshot, excludeKeySet) {
|
|
452
|
+
snapshot.clearShortestPathInfo();
|
|
453
|
+
Console_1.default.overwrite('annotating shortest path for all nodes');
|
|
454
|
+
const [nodeRootLists, lowPriRootLists] = this.getRootNodeList(snapshot, {
|
|
455
|
+
prioritize: true,
|
|
456
|
+
});
|
|
457
|
+
const nodeCount = snapshot.nodes.length;
|
|
458
|
+
const visited = new Uint8Array(nodeCount);
|
|
459
|
+
const queued = new Uint8Array(nodeCount);
|
|
460
|
+
const traverseOption = {
|
|
461
|
+
visited,
|
|
462
|
+
queued,
|
|
463
|
+
excludeWeakMapEdge: true,
|
|
464
|
+
isForward: true,
|
|
465
|
+
};
|
|
466
|
+
let curQueue = nodeRootLists;
|
|
467
|
+
const postponeQueue = [];
|
|
468
|
+
while (curQueue.length > 0) {
|
|
469
|
+
const nextQueue = [];
|
|
470
|
+
while (curQueue.length > 0) {
|
|
471
|
+
const node = curQueue.pop();
|
|
472
|
+
visited[node.nodeIndex] = 1;
|
|
473
|
+
for (const edge of node.references) {
|
|
474
|
+
// skip nodes that already have a parent
|
|
475
|
+
if (edge.toNode.pathEdge) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
if (!this.shouldTraverseEdge(edge, traverseOption)) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (this.shouldIgnoreEdgeInTraceFinding(edge)) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (Utils_1.default.isWeakMapEdge(edge) && excludeKeySet) {
|
|
485
|
+
const weakMapKeyObjectId = Utils_1.default.getWeakMapEdgeKeyId(edge);
|
|
486
|
+
if (excludeKeySet.has(weakMapKeyObjectId)) {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
// postpone traversing edges and nodes that are less preferable
|
|
491
|
+
if (this.isLessPreferableEdge(edge) ||
|
|
492
|
+
this.isLessPreferableNode(edge.toNode)) {
|
|
493
|
+
postponeQueue.push(edge);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
edge.toNode.pathEdge = edge;
|
|
497
|
+
nextQueue.push(edge.toNode);
|
|
498
|
+
}
|
|
499
|
+
queued[edge.toNode.nodeIndex] = 1;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// if no other preferable traces available
|
|
503
|
+
// traverse the postpone queue
|
|
504
|
+
while (nextQueue.length === 0 && postponeQueue.length > 0) {
|
|
505
|
+
const edge = postponeQueue.pop();
|
|
506
|
+
if (edge.toNode.pathEdge) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
edge.toNode.pathEdge = edge;
|
|
510
|
+
nextQueue.push(edge.toNode);
|
|
511
|
+
}
|
|
512
|
+
// if no other preferable traces available
|
|
513
|
+
// consider the low priority root nodes
|
|
514
|
+
while (nextQueue.length === 0 && lowPriRootLists.length > 0) {
|
|
515
|
+
const root = lowPriRootLists.pop();
|
|
516
|
+
if (root.pathEdge) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
nextQueue.push(root);
|
|
520
|
+
}
|
|
521
|
+
curQueue = nextQueue;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
getPathToGCRoots(_snapshot, node) {
|
|
525
|
+
if (!node || !node.pathEdge) {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
let path = { node };
|
|
529
|
+
while (node && node.pathEdge) {
|
|
530
|
+
const edge = node.pathEdge;
|
|
531
|
+
path = { node: edge.fromNode, edge, next: path };
|
|
532
|
+
node = edge.fromNode;
|
|
533
|
+
}
|
|
534
|
+
return path;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
exports.default = TraceFinder;
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
declare const _default: {
|
|
11
|
+
isSimilarTrace: (t1: import("..").LeakTrace, t2: import("..").LeakTrace) => boolean;
|
|
12
|
+
};
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=ClusterUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterUtils.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/ClusterUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;;;AAKH,wBAA6D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
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 ClusterUtilsHelper_1 = __importDefault(require("./ClusterUtilsHelper"));
|
|
16
|
+
const ClusteringHeuristics_1 = __importDefault(require("./ClusteringHeuristics"));
|
|
17
|
+
exports.default = ClusterUtilsHelper_1.default.initialize(ClusteringHeuristics_1.default);
|
|
@@ -0,0 +1,38 @@
|
|
|
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 { AnyValue, LeakTraceElement, LeakTrace } from '../lib/Types';
|
|
11
|
+
declare type NameWeightMapType = Map<string | RegExp | number, number>;
|
|
12
|
+
interface ClusteringHeuristic {
|
|
13
|
+
edgeNameStopWords: NameWeightMapType;
|
|
14
|
+
nodeNameStopWords: NameWeightMapType;
|
|
15
|
+
similarWordRegExps: Map<RegExp, number>;
|
|
16
|
+
decendentDecayFactors: {
|
|
17
|
+
kind: string;
|
|
18
|
+
name: string;
|
|
19
|
+
decay: number;
|
|
20
|
+
}[];
|
|
21
|
+
startingModuleForTraceMatching: (string | RegExp)[];
|
|
22
|
+
}
|
|
23
|
+
export declare function debugLog(...args: AnyValue[]): void;
|
|
24
|
+
interface DebugElementSimilarityStatsParams {
|
|
25
|
+
elementA: LeakTraceElement;
|
|
26
|
+
elementB: LeakTraceElement;
|
|
27
|
+
matchedSum: number;
|
|
28
|
+
totalSum: number;
|
|
29
|
+
}
|
|
30
|
+
export declare const debugTraceElementSimilarityStats: ({ elementA, elementB, matchedSum, totalSum, }: DebugElementSimilarityStatsParams) => void;
|
|
31
|
+
declare type ClusteringUtilReturnType = {
|
|
32
|
+
isSimilarTrace: (t1: LeakTrace, t2: LeakTrace) => boolean;
|
|
33
|
+
};
|
|
34
|
+
declare const _default: {
|
|
35
|
+
initialize: (heuristics: ClusteringHeuristic) => ClusteringUtilReturnType;
|
|
36
|
+
};
|
|
37
|
+
export default _default;
|
|
38
|
+
//# sourceMappingURL=ClusterUtilsHelper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterUtilsHelper.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/ClusterUtilsHelper.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,OAAO,KAAK,EAAC,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,cAAc,CAAC;AASxE,aAAK,iBAAiB,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC;AAK/D,UAAU,mBAAmB;IAC3B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,qBAAqB,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IACrE,8BAA8B,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACrD;AAED,wBAAgB,QAAQ,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,CAQlD;AAED,UAAU,iCAAiC;IACzC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gCAAgC,kDAK1C,iCAAiC,KAAG,IAatC,CAAC;AAMF,aAAK,wBAAwB,GAAG;IAC9B,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC;CAC3D,CAAC;;;;AAqcF,wBAEE"}
|