@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.
Files changed (130) hide show
  1. package/README.md +11 -0
  2. package/dist/__tests__/parser/HeapParser.test.d.ts +11 -0
  3. package/dist/__tests__/parser/HeapParser.test.d.ts.map +1 -0
  4. package/dist/__tests__/parser/HeapParser.test.js +54 -0
  5. package/dist/__tests__/parser/NodeHeap.test.d.ts +11 -0
  6. package/dist/__tests__/parser/NodeHeap.test.d.ts.map +1 -0
  7. package/dist/__tests__/parser/NodeHeap.test.js +96 -0
  8. package/dist/__tests__/parser/StringNode.test.d.ts +11 -0
  9. package/dist/__tests__/parser/StringNode.test.d.ts.map +1 -0
  10. package/dist/__tests__/parser/StringNode.test.js +61 -0
  11. package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.d.ts +16 -0
  12. package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.d.ts.map +1 -0
  13. package/dist/__tests__/parser/traverse/HeapNodeTraverse.test.js +140 -0
  14. package/dist/__tests__/utils/utils.test.d.ts +11 -0
  15. package/dist/__tests__/utils/utils.test.d.ts.map +1 -0
  16. package/dist/__tests__/utils/utils.test.js +81 -0
  17. package/dist/index.d.ts +29 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +62 -0
  20. package/dist/lib/BaseOption.d.ts +31 -0
  21. package/dist/lib/BaseOption.d.ts.map +1 -0
  22. package/dist/lib/BaseOption.js +109 -0
  23. package/dist/lib/BrowserInfo.d.ts +33 -0
  24. package/dist/lib/BrowserInfo.d.ts.map +1 -0
  25. package/dist/lib/BrowserInfo.js +117 -0
  26. package/dist/lib/Config.d.ts +203 -0
  27. package/dist/lib/Config.d.ts.map +1 -0
  28. package/dist/lib/Config.js +427 -0
  29. package/dist/lib/Console.d.ts +67 -0
  30. package/dist/lib/Console.d.ts.map +1 -0
  31. package/dist/lib/Console.js +344 -0
  32. package/dist/lib/Constant.d.ts +38 -0
  33. package/dist/lib/Constant.d.ts.map +1 -0
  34. package/dist/lib/Constant.js +58 -0
  35. package/dist/lib/FileManager.d.ts +69 -0
  36. package/dist/lib/FileManager.d.ts.map +1 -0
  37. package/dist/lib/FileManager.js +309 -0
  38. package/dist/lib/HeapAnalyzer.d.ts +51 -0
  39. package/dist/lib/HeapAnalyzer.d.ts.map +1 -0
  40. package/dist/lib/HeapAnalyzer.js +719 -0
  41. package/dist/lib/HeapParser.d.ts +19 -0
  42. package/dist/lib/HeapParser.d.ts.map +1 -0
  43. package/dist/lib/HeapParser.js +128 -0
  44. package/dist/lib/InternalValueSetter.d.ts +14 -0
  45. package/dist/lib/InternalValueSetter.d.ts.map +1 -0
  46. package/dist/lib/InternalValueSetter.js +43 -0
  47. package/dist/lib/NodeHeap.d.ts +16 -0
  48. package/dist/lib/NodeHeap.d.ts.map +1 -0
  49. package/dist/lib/NodeHeap.js +62 -0
  50. package/dist/lib/ProcessManager.d.ts +25 -0
  51. package/dist/lib/ProcessManager.d.ts.map +1 -0
  52. package/dist/lib/ProcessManager.js +67 -0
  53. package/dist/lib/Serializer.d.ts +49 -0
  54. package/dist/lib/Serializer.d.ts.map +1 -0
  55. package/dist/lib/Serializer.js +702 -0
  56. package/dist/lib/StringLoader.d.ts +26 -0
  57. package/dist/lib/StringLoader.d.ts.map +1 -0
  58. package/dist/lib/StringLoader.js +290 -0
  59. package/dist/lib/Types.d.ts +432 -0
  60. package/dist/lib/Types.d.ts.map +1 -0
  61. package/dist/lib/Types.js +11 -0
  62. package/dist/lib/Utils.d.ts +223 -0
  63. package/dist/lib/Utils.d.ts.map +1 -0
  64. package/dist/lib/Utils.js +1736 -0
  65. package/dist/lib/heap-data/HeapEdge.d.ts +27 -0
  66. package/dist/lib/heap-data/HeapEdge.d.ts.map +1 -0
  67. package/dist/lib/heap-data/HeapEdge.js +75 -0
  68. package/dist/lib/heap-data/HeapLocation.d.ts +22 -0
  69. package/dist/lib/heap-data/HeapLocation.d.ts.map +1 -0
  70. package/dist/lib/heap-data/HeapLocation.js +40 -0
  71. package/dist/lib/heap-data/HeapNode.d.ts +55 -0
  72. package/dist/lib/heap-data/HeapNode.d.ts.map +1 -0
  73. package/dist/lib/heap-data/HeapNode.js +344 -0
  74. package/dist/lib/heap-data/HeapSnapshot.d.ts +85 -0
  75. package/dist/lib/heap-data/HeapSnapshot.d.ts.map +1 -0
  76. package/dist/lib/heap-data/HeapSnapshot.js +462 -0
  77. package/dist/lib/heap-data/HeapStringNode.d.ts +18 -0
  78. package/dist/lib/heap-data/HeapStringNode.d.ts.map +1 -0
  79. package/dist/lib/heap-data/HeapStringNode.js +43 -0
  80. package/dist/lib/heap-data/HeapUtils.d.ts +17 -0
  81. package/dist/lib/heap-data/HeapUtils.d.ts.map +1 -0
  82. package/dist/lib/heap-data/HeapUtils.js +25 -0
  83. package/dist/logger/LeakClusterLogger.d.ts +40 -0
  84. package/dist/logger/LeakClusterLogger.d.ts.map +1 -0
  85. package/dist/logger/LeakClusterLogger.js +228 -0
  86. package/dist/logger/LeakTraceDetailsLogger.d.ts +19 -0
  87. package/dist/logger/LeakTraceDetailsLogger.d.ts.map +1 -0
  88. package/dist/logger/LeakTraceDetailsLogger.js +50 -0
  89. package/dist/modes/BaseMode.d.ts +30 -0
  90. package/dist/modes/BaseMode.d.ts.map +1 -0
  91. package/dist/modes/BaseMode.js +95 -0
  92. package/dist/modes/InteractionTestMode.d.ts +23 -0
  93. package/dist/modes/InteractionTestMode.d.ts.map +1 -0
  94. package/dist/modes/InteractionTestMode.js +46 -0
  95. package/dist/modes/MeasureMode.d.ts +23 -0
  96. package/dist/modes/MeasureMode.d.ts.map +1 -0
  97. package/dist/modes/MeasureMode.js +58 -0
  98. package/dist/modes/RunningModes.d.ts +15 -0
  99. package/dist/modes/RunningModes.d.ts.map +1 -0
  100. package/dist/modes/RunningModes.js +40 -0
  101. package/dist/paths/TraceFinder.d.ts +31 -0
  102. package/dist/paths/TraceFinder.d.ts.map +1 -0
  103. package/dist/paths/TraceFinder.js +537 -0
  104. package/dist/trace-cluster/ClusterUtils.d.ts +14 -0
  105. package/dist/trace-cluster/ClusterUtils.d.ts.map +1 -0
  106. package/dist/trace-cluster/ClusterUtils.js +17 -0
  107. package/dist/trace-cluster/ClusterUtilsHelper.d.ts +38 -0
  108. package/dist/trace-cluster/ClusterUtilsHelper.d.ts.map +1 -0
  109. package/dist/trace-cluster/ClusterUtilsHelper.js +373 -0
  110. package/dist/trace-cluster/ClusteringHeuristics.d.ts +22 -0
  111. package/dist/trace-cluster/ClusteringHeuristics.d.ts.map +1 -0
  112. package/dist/trace-cluster/ClusteringHeuristics.js +23 -0
  113. package/dist/trace-cluster/EvalutationMetric.d.ts +22 -0
  114. package/dist/trace-cluster/EvalutationMetric.d.ts.map +1 -0
  115. package/dist/trace-cluster/EvalutationMetric.js +158 -0
  116. package/dist/trace-cluster/TraceBucket.d.ts +36 -0
  117. package/dist/trace-cluster/TraceBucket.d.ts.map +1 -0
  118. package/dist/trace-cluster/TraceBucket.js +238 -0
  119. package/dist/trace-cluster/TraceElement.d.ts +71 -0
  120. package/dist/trace-cluster/TraceElement.d.ts.map +1 -0
  121. package/dist/trace-cluster/TraceElement.js +182 -0
  122. package/dist/trace-cluster/strategies/TraceAsClusterStrategy.d.ts +15 -0
  123. package/dist/trace-cluster/strategies/TraceAsClusterStrategy.d.ts.map +1 -0
  124. package/dist/trace-cluster/strategies/TraceAsClusterStrategy.js +37 -0
  125. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.d.ts +15 -0
  126. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.d.ts.map +1 -0
  127. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +60 -0
  128. package/package.json +60 -0
  129. package/static/run-meta.json +10 -0
  130. package/static/visit-order.json +27 -0
@@ -0,0 +1,373 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.debugTraceElementSimilarityStats = exports.debugLog = void 0;
13
+ function NON_NULLABLE(v) {
14
+ if (v == null) {
15
+ throw new Error('value must not be null or undefined');
16
+ }
17
+ return v;
18
+ }
19
+ // Set this flag to true when debugging the leak trace clustering algorithm
20
+ // to get more runtime information in terminal.
21
+ const DEBUG = false;
22
+ function debugLog(...args) {
23
+ if (!DEBUG) {
24
+ return;
25
+ }
26
+ if (typeof console === 'undefined' || typeof console.log !== 'function') {
27
+ return;
28
+ }
29
+ console.log(args.join(' |\t'));
30
+ }
31
+ exports.debugLog = debugLog;
32
+ const debugTraceElementSimilarityStats = ({ elementA, elementB, matchedSum, totalSum, }) => {
33
+ const similarityScoreString = `${matchedSum} / ${totalSum}`;
34
+ if (elementA.kind === 'edge') {
35
+ debugLog(elementA.kind, elementA.name_or_index, elementB.name_or_index, similarityScoreString);
36
+ return;
37
+ }
38
+ debugLog(elementA.kind, elementA.name, elementB.name, similarityScoreString);
39
+ };
40
+ exports.debugTraceElementSimilarityStats = debugTraceElementSimilarityStats;
41
+ const SIMILAR_TRACE_THRESHOLD = 0.8;
42
+ const REACT_FIBER_EDGE_PREFIX = '__reactFiber$';
43
+ const WINDOW_NODE_PREFIX = 'Window / ';
44
+ const initialize = (heuristics) => {
45
+ const { edgeNameStopWords, nodeNameStopWords, similarWordRegExps, decendentDecayFactors, startingModuleForTraceMatching, } = heuristics;
46
+ function _searchForEdge(t, name) {
47
+ for (let i = 0; i < t.length; ++i) {
48
+ const traceElement = t[i];
49
+ if (traceElement.kind === 'edge' && 'name_or_index' in traceElement) {
50
+ if (name instanceof RegExp) {
51
+ if (name.test(`${traceElement.name_or_index}`)) {
52
+ return i;
53
+ }
54
+ }
55
+ else if (traceElement.name_or_index === name) {
56
+ return i;
57
+ }
58
+ }
59
+ }
60
+ return -1;
61
+ }
62
+ function _searchForNode(t, name) {
63
+ for (let i = 0; i < t.length; ++i) {
64
+ const traceElement = t[i];
65
+ if (traceElement.kind === 'node' && 'name' in traceElement) {
66
+ if (name instanceof RegExp) {
67
+ if (name.test(NON_NULLABLE(traceElement.name))) {
68
+ return i;
69
+ }
70
+ }
71
+ else if (traceElement.name === name) {
72
+ return i;
73
+ }
74
+ }
75
+ }
76
+ return -1;
77
+ }
78
+ function _searchForMatch(t1, t2, name) {
79
+ let i1 = _searchForEdge(t1, name);
80
+ let i2 = _searchForEdge(t2, name);
81
+ if (i1 >= 0 && i2 >= 0) {
82
+ return [i1, i2];
83
+ }
84
+ i1 = _searchForNode(t1, name);
85
+ i2 = _searchForNode(t2, name);
86
+ if (i1 >= 0 && i2 >= 0) {
87
+ return [i1, i2];
88
+ }
89
+ return null;
90
+ }
91
+ // the trace similarity calculation starts from modulesMap if
92
+ // both traces have the modulesMap heap object
93
+ function matchTraceStartItem(t1, t2) {
94
+ for (const name of startingModuleForTraceMatching) {
95
+ const ret = _searchForMatch(t1, t2, name);
96
+ if (ret) {
97
+ return ret;
98
+ }
99
+ }
100
+ return [0, 0];
101
+ }
102
+ function getNodeStopWordWeight(name) {
103
+ return _getStopWordWeight(nodeNameStopWords, name);
104
+ }
105
+ function getEdgeStopWordWeight(name) {
106
+ return _getStopWordWeight(edgeNameStopWords, name);
107
+ }
108
+ function _getStopWordWeight(stopWordsMap, name) {
109
+ if (stopWordsMap.has(name)) {
110
+ return NON_NULLABLE(stopWordsMap.get(name));
111
+ }
112
+ for (const stopWord of stopWordsMap.keys()) {
113
+ if (!(stopWord instanceof RegExp)) {
114
+ continue;
115
+ }
116
+ if (stopWord.test(`${name}`)) {
117
+ return NON_NULLABLE(stopWordsMap.get(stopWord));
118
+ }
119
+ }
120
+ return 1;
121
+ }
122
+ function getSimilarWordsWeight(name1, name2) {
123
+ const n1 = `${name1}`;
124
+ const n2 = `${name2}`;
125
+ for (const regexp of similarWordRegExps.keys()) {
126
+ if (regexp.test(n1) && regexp.test(n2)) {
127
+ return NON_NULLABLE(similarWordRegExps.get(regexp));
128
+ }
129
+ }
130
+ return 1;
131
+ }
132
+ function getDecendentDecayFactor(elem,
133
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
134
+ _elem2) {
135
+ for (const factors of decendentDecayFactors) {
136
+ if (factors.kind === elem.kind) {
137
+ if ('name' in elem && factors.name === elem.name) {
138
+ return factors.decay;
139
+ }
140
+ if ('name_or_index' in elem && factors.name === elem.name_or_index) {
141
+ return factors.decay;
142
+ }
143
+ }
144
+ }
145
+ return 1;
146
+ }
147
+ function isNodeNameSame(name1, name2) {
148
+ const isWindowNode1 = typeof name1 === 'string' && name1.startsWith(WINDOW_NODE_PREFIX);
149
+ const isWindowNode2 = typeof name2 === 'string' && name2.startsWith(WINDOW_NODE_PREFIX);
150
+ if (isWindowNode1 && isWindowNode2) {
151
+ return true;
152
+ }
153
+ return name1 === name2;
154
+ }
155
+ function isNameSimilar(name1, name2) {
156
+ const n1 = `${name1}`;
157
+ const n2 = `${name2}`;
158
+ for (const regexp of similarWordRegExps.keys()) {
159
+ if (regexp.test(n1) && regexp.test(n2)) {
160
+ return true;
161
+ }
162
+ }
163
+ return false;
164
+ }
165
+ function isEdgeNameSame(name1, name2) {
166
+ const isFiberEdge1 = typeof name1 === 'string' && name1.startsWith(REACT_FIBER_EDGE_PREFIX);
167
+ const isFiberEdge2 = typeof name2 === 'string' && name2.startsWith(REACT_FIBER_EDGE_PREFIX);
168
+ if (isFiberEdge1 && isFiberEdge2) {
169
+ return true;
170
+ }
171
+ return name1 === name2;
172
+ }
173
+ function representsNumber(value) {
174
+ if (typeof value === 'number') {
175
+ return true;
176
+ }
177
+ if (parseInt(value, 10) + '' === value + '') {
178
+ return true;
179
+ }
180
+ if (parseFloat(value) + '' === value + '') {
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+ function areBothNodes(elem1, elem2) {
186
+ if (elem1 == null || elem2 == null) {
187
+ return false;
188
+ }
189
+ if (elem1.kind !== 'node' || elem2.kind !== 'node') {
190
+ return false;
191
+ }
192
+ if (elem1.type !== elem2.type) {
193
+ return false;
194
+ }
195
+ return true;
196
+ }
197
+ function isSameNode(elem1, elem2) {
198
+ if (!areBothNodes(elem1, elem2)) {
199
+ return false;
200
+ }
201
+ return isNodeNameSame(NON_NULLABLE(elem1.name), NON_NULLABLE(elem2.name));
202
+ }
203
+ function isSimilarNode(elem1, elem2) {
204
+ if (!areBothNodes(elem1, elem2)) {
205
+ return false;
206
+ }
207
+ return isNameSimilar(NON_NULLABLE(elem1.name), NON_NULLABLE(elem2.name));
208
+ }
209
+ function isSameEdge(trace1, i1, trace2, i2) {
210
+ const elem1 = trace1[i1];
211
+ const elem2 = trace2[i2];
212
+ if (elem1 == null || elem2 == null) {
213
+ return false;
214
+ }
215
+ if (elem1.kind !== 'edge' || elem2.kind !== 'edge') {
216
+ return false;
217
+ }
218
+ if (elem1.type !== elem2.type) {
219
+ return false;
220
+ }
221
+ // index properties are considered the same if
222
+ // their referrer node are the same
223
+ if (representsNumber(elem1.name_or_index) &&
224
+ representsNumber(elem2.name_or_index)) {
225
+ const referrer1 = trace1[i1 - 1];
226
+ const referrer2 = trace2[i2 - 1];
227
+ return isSameNode(referrer1, referrer2);
228
+ }
229
+ return isEdgeNameSame(NON_NULLABLE(elem1.name_or_index), NON_NULLABLE(elem2.name_or_index));
230
+ }
231
+ function areBothEdges(elem1, elem2) {
232
+ if (elem1 == null || elem2 == null) {
233
+ return false;
234
+ }
235
+ if (elem1.kind !== 'edge' || elem2.kind !== 'edge') {
236
+ return false;
237
+ }
238
+ if (elem1.type !== elem2.type) {
239
+ return false;
240
+ }
241
+ return true;
242
+ }
243
+ function isSimilarEdge(trace1, i1, trace2, i2) {
244
+ const elem1 = trace1[i1];
245
+ const elem2 = trace2[i2];
246
+ if (!areBothEdges(elem1, elem2)) {
247
+ return false;
248
+ }
249
+ // index properties are considered the same if
250
+ // their referrer node are the same
251
+ if (representsNumber(elem1.name_or_index) &&
252
+ representsNumber(elem2.name_or_index)) {
253
+ const referrer1 = trace1[i1 - 1];
254
+ const referrer2 = trace2[i2 - 1];
255
+ return (isSameNode(referrer1, referrer2) || isSimilarNode(referrer1, referrer2));
256
+ }
257
+ return isNameSimilar(NON_NULLABLE(elem1.name_or_index), NON_NULLABLE(elem2.name_or_index));
258
+ }
259
+ function isSameOrSimilarElement(trace1, i1, trace2, i2) {
260
+ const elem1 = trace1[i1];
261
+ const elem2 = trace2[i2];
262
+ if (!elem1 || !elem2) {
263
+ return false;
264
+ }
265
+ if (elem1.kind !== elem2.kind) {
266
+ return false;
267
+ }
268
+ if (elem1.kind === 'edge') {
269
+ if (isSameEdge(trace1, i1, trace2, i2)) {
270
+ return true;
271
+ }
272
+ return isSimilarEdge(trace1, i1, trace2, i2);
273
+ }
274
+ if (isSameNode(elem1, elem2)) {
275
+ return true;
276
+ }
277
+ return isSimilarNode(elem1, elem2);
278
+ }
279
+ function getDecayFactor(trace1, i1, trace2, i2) {
280
+ const elem1 = trace1[i1];
281
+ const elem2 = trace2[i2];
282
+ if (!elem1 || !elem2) {
283
+ return 1;
284
+ }
285
+ if (elem1.kind !== elem2.kind) {
286
+ return 1;
287
+ }
288
+ return getDecendentDecayFactor(elem1, elem2);
289
+ }
290
+ function getElementPairWeight(trace1, i1, trace2, i2) {
291
+ const elem1 = trace1[i1];
292
+ const elem2 = trace2[i2];
293
+ if (!elem1 || !elem2) {
294
+ return 1;
295
+ }
296
+ if (elem1.kind !== elem2.kind) {
297
+ return 1;
298
+ }
299
+ if (elem1.kind === 'edge') {
300
+ if (!isSameEdge(trace1, i1, trace2, i2)) {
301
+ return getSimilarWordsWeight(NON_NULLABLE(elem1.name_or_index), NON_NULLABLE(elem2.name_or_index));
302
+ }
303
+ const edgeName = NON_NULLABLE(elem1.name_or_index);
304
+ return getEdgeStopWordWeight(edgeName);
305
+ }
306
+ if (!isSameNode(elem1, elem2)) {
307
+ return getSimilarWordsWeight(NON_NULLABLE(elem1.name), NON_NULLABLE(elem2.name));
308
+ }
309
+ const nodeName = NON_NULLABLE(elem1.name);
310
+ return getNodeStopWordWeight(nodeName);
311
+ }
312
+ function getSimilarityByTraceElementList(t1, t2) {
313
+ // find first starting item that matches
314
+ let [i1, i2] = matchTraceStartItem(t1, t2);
315
+ const l1 = t1.length;
316
+ const l2 = t2.length;
317
+ const d1 = l1 - i1;
318
+ const d2 = l2 - i2;
319
+ let delta1 = 0.9 / d1;
320
+ let delta2 = 0.9 / d2;
321
+ let w1 = 1;
322
+ let w2 = 1;
323
+ const l = Math.max(l1, l2);
324
+ let matchedSum = 0;
325
+ let totalSum = 0;
326
+ while (i1 < l || i2 < l) {
327
+ const trace1 = t1;
328
+ const trace2 = t2;
329
+ const pw = getElementPairWeight(trace1, i1, trace2, i2);
330
+ if (isSameOrSimilarElement(trace1, i1, trace2, i2)) {
331
+ (0, exports.debugTraceElementSimilarityStats)({
332
+ elementA: trace1[i1],
333
+ elementB: trace2[i2],
334
+ matchedSum,
335
+ totalSum,
336
+ });
337
+ matchedSum += (w1 + w2) * pw;
338
+ }
339
+ totalSum += (w1 + w2) * pw;
340
+ const decayFactor = 0.99 * getDecayFactor(trace1, i1, trace2, i2);
341
+ w1 *= decayFactor;
342
+ w2 *= decayFactor;
343
+ delta1 *= decayFactor;
344
+ delta2 *= decayFactor;
345
+ if (w1 - delta1 >= 0) {
346
+ w1 -= delta1;
347
+ }
348
+ if (w2 - delta2 >= 0) {
349
+ w2 -= delta2;
350
+ }
351
+ ++i1;
352
+ ++i2;
353
+ if (i1 >= l1 || i2 >= l2) {
354
+ const sim = matchedSum / (totalSum + 0.0001);
355
+ if (sim > 0.9) {
356
+ return sim;
357
+ }
358
+ }
359
+ }
360
+ return matchedSum / (totalSum + 0.0001);
361
+ }
362
+ function isSimilarTrace(t1, t2) {
363
+ const similarity = getSimilarityByTraceElementList(t1, t2);
364
+ debugLog(similarity);
365
+ return similarity >= SIMILAR_TRACE_THRESHOLD;
366
+ }
367
+ return {
368
+ isSimilarTrace,
369
+ };
370
+ };
371
+ exports.default = {
372
+ initialize,
373
+ };
@@ -0,0 +1,22 @@
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
+ edgeNameStopWords: Map<any, any>;
12
+ nodeNameStopWords: Map<any, any>;
13
+ similarWordRegExps: Map<any, any>;
14
+ decendentDecayFactors: {
15
+ kind: string;
16
+ name: string;
17
+ decay: number;
18
+ }[];
19
+ startingModuleForTraceMatching: (string | RegExp)[];
20
+ };
21
+ export default _default;
22
+ //# sourceMappingURL=ClusteringHeuristics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClusteringHeuristics.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/ClusteringHeuristics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;;;;;cAUqC,MAAM;cAAQ,MAAM;eAAS,MAAM;;;;AAL3E,wBAUE"}
@@ -0,0 +1,23 @@
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 InternalValueSetter_1 = require("../lib/InternalValueSetter");
16
+ const Constant_1 = __importDefault(require("../lib/Constant"));
17
+ exports.default = (0, InternalValueSetter_1.setInternalValue)({
18
+ edgeNameStopWords: new Map(),
19
+ nodeNameStopWords: new Map(),
20
+ similarWordRegExps: new Map(),
21
+ decendentDecayFactors: [],
22
+ startingModuleForTraceMatching: [],
23
+ }, __filename, Constant_1.default.internalDir);
@@ -0,0 +1,22 @@
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 type ClusteredLeakTraces = Record<string, string>;
11
+ declare const _default: {
12
+ evaluateAdjustRandScore: (trueTraceIdLabelMap: ClusteredLeakTraces, predictedTraceIdLabelMap: ClusteredLeakTraces) => number;
13
+ vMeasure: (trueLabels: number[], predictedLabels: number[], beta?: number) => number;
14
+ completeness: (trueLabels: number[], predictedLabels: number[]) => number;
15
+ homogeneity: (trueLabels?: number[], predictedLabels?: number[]) => number;
16
+ getRepresentativeTraceMetrics: (trueTraceIdLabelMap: ClusteredLeakTraces, predictedTraceIdLabelMap: ClusteredLeakTraces) => {
17
+ omitted: number;
18
+ duplicated: number;
19
+ };
20
+ };
21
+ export default _default;
22
+ //# sourceMappingURL=EvalutationMetric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EvalutationMetric.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/EvalutationMetric.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqHH,aAAK,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;;;;;;;;;;AA+ElD,wBAME"}
@@ -0,0 +1,158 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ ////////////////////////
13
+ const zip = (arr1, arr2) => arr1.reduce((ret, el, idx) => {
14
+ ret.push([el, arr2[idx]]);
15
+ return ret;
16
+ }, []);
17
+ /*
18
+ countUnique returns array of count of unique items for given array of numbers.
19
+ For example, countUnique([1, 2, 3, 3, 2]) returns [['1', '2', '3'], [1, 2, 2]].
20
+ countUnique([[1, 2], [2, 3], [2, 3]]) returns [['1,2', '2,3'], [1, 2]].
21
+ */
22
+ const countUnique = (arr = []) => {
23
+ const key = (el) => {
24
+ if (Array.isArray(el)) {
25
+ return el.join(',');
26
+ }
27
+ return `${el}`;
28
+ };
29
+ const map = new Map();
30
+ arr.forEach(el => {
31
+ const k = key(el);
32
+ if (map.has(key(el))) {
33
+ map.set(k, map.get(k) + 1);
34
+ }
35
+ else {
36
+ map.set(k, 1);
37
+ }
38
+ });
39
+ return [Array.from(map.keys()), Array.from(map.values())];
40
+ };
41
+ const entropy = (labels = []) => {
42
+ const nLabels = labels.length;
43
+ if (nLabels <= 1)
44
+ return 0;
45
+ const [, counts] = countUnique(labels);
46
+ const probabilities = counts.map(c => c / nLabels);
47
+ const nClassess = probabilities.filter(el => el !== 0).length;
48
+ if (nClassess <= 1)
49
+ return 0;
50
+ let ent = 0.0;
51
+ for (const prob of probabilities) {
52
+ ent -= prob * Math.log(prob);
53
+ }
54
+ return ent;
55
+ };
56
+ const homogeneity = (trueLabels = [], predictedLabels = []) => {
57
+ const trueLabelEntropy = entropy(trueLabels);
58
+ if (trueLabelEntropy == 0)
59
+ return 1;
60
+ // Combine two lists into a list of tuples which will be used for conditional Entropy.
61
+ const joined = zip(trueLabels, predictedLabels);
62
+ const joinedEntropy = entropy(joined);
63
+ const predictedLabelEntropy = entropy(predictedLabels);
64
+ // Conditional Entropy (Chain rule) - https://en.wikipedia.org/wiki/Conditional_entropy
65
+ // H(X|Y) = H(X,Y) - H(X)
66
+ const conditionalEntropy = joinedEntropy - predictedLabelEntropy;
67
+ const h = 1 - conditionalEntropy / trueLabelEntropy;
68
+ return h;
69
+ };
70
+ const completeness = (trueLabels, predictedLabels) => {
71
+ const predictedLabelEntropy = entropy(predictedLabels);
72
+ if (predictedLabelEntropy == 0)
73
+ return 1;
74
+ // # Combine two lists into a list of tuples.
75
+ // # For example, classes [1, 3] and clusters [20, 30] become [(1, 20), (3, 30)].
76
+ const joined = zip(trueLabels, predictedLabels);
77
+ const joinedEntropy = entropy(joined);
78
+ const trueLabelEntropy = entropy(trueLabels);
79
+ const conditionalEntropy = joinedEntropy - trueLabelEntropy;
80
+ const c = 1 - conditionalEntropy / predictedLabelEntropy;
81
+ return c;
82
+ };
83
+ /*
84
+ Ratio of weight attributed to homogeneity vs completeness.
85
+ If beta is greater than 1, completeness is weighted more strongly in the calculation.
86
+ If beta is less than 1, homogeneity is weighted more strongly.
87
+ */
88
+ const vMeasure = (trueLabels, predictedLabels, beta = 1) => {
89
+ const h = homogeneity(trueLabels, predictedLabels);
90
+ const c = completeness(trueLabels, predictedLabels);
91
+ const v = ((1 + beta) * h * c) / (beta * h + c);
92
+ return v;
93
+ };
94
+ /**
95
+ * The dataset the function takes as argument is map of key:value pairs.
96
+ * Key is trace_id and value is the cluster_id, which is another trace_id
97
+ * that represents the cluster it, belongs to
98
+ * @param trueTraceIdLabelMap Baseline
99
+ * @param predictedTraceIdLabelMap Predicted outcome from some clustering
100
+ * @returns numeric evaluation ([-1:1] 1 being identical) of how close the traces are clustered using Adjust Rand Index formula.
101
+ */
102
+ const evaluateAdjustRandScore = (trueTraceIdLabelMap, predictedTraceIdLabelMap) => {
103
+ let truePositive = 0;
104
+ let falsePositive = 0;
105
+ let falseNegative = 0;
106
+ let trueNegative = 0;
107
+ const predictedTraceIDs = Object.keys(predictedTraceIdLabelMap);
108
+ for (let i = 0; i < predictedTraceIDs.length - 1; i++) {
109
+ for (let j = i + 1; j < predictedTraceIDs.length - 1; j++) {
110
+ const [traceIdA, traceIdB] = [predictedTraceIDs[i], predictedTraceIDs[j]];
111
+ const isSameInPredicted = predictedTraceIdLabelMap[traceIdA] ===
112
+ predictedTraceIdLabelMap[traceIdB];
113
+ const isSameInTrue = trueTraceIdLabelMap[traceIdA] === trueTraceIdLabelMap[traceIdB];
114
+ if (isSameInPredicted && isSameInTrue) {
115
+ truePositive++;
116
+ }
117
+ else if (!isSameInPredicted && isSameInTrue) {
118
+ falseNegative++;
119
+ }
120
+ else if (isSameInPredicted && !isSameInTrue) {
121
+ falsePositive++;
122
+ }
123
+ else {
124
+ trueNegative++;
125
+ }
126
+ }
127
+ }
128
+ const n = predictedTraceIDs.length;
129
+ // Total number of pairs
130
+ const totalNumberOfPairs = (n * (n - 1)) / 2;
131
+ // The formula is from https://arxiv.org/pdf/2002.03677.pdf
132
+ const ARI = (totalNumberOfPairs * (truePositive + trueNegative) -
133
+ ((truePositive + falsePositive) * (truePositive + falseNegative) +
134
+ (falseNegative + trueNegative) * (falsePositive + trueNegative))) /
135
+ (Math.pow(totalNumberOfPairs, 2) -
136
+ ((truePositive + falsePositive) * (truePositive + falseNegative) +
137
+ (falseNegative + trueNegative) * (falsePositive + trueNegative)));
138
+ return ARI;
139
+ };
140
+ const getRepresentativeTraceMetrics = (trueTraceIdLabelMap, predictedTraceIdLabelMap) => {
141
+ const [uniqTrueLabels] = countUnique(Object.values(trueTraceIdLabelMap));
142
+ const nTrueLabels = uniqTrueLabels.length;
143
+ const [uniqPredLabels] = countUnique(Object.values(predictedTraceIdLabelMap));
144
+ const predLabelToTrueLabel = uniqPredLabels.map(representativeTraceId => trueTraceIdLabelMap[representativeTraceId]);
145
+ const [, countsOfTrueLabelsForPredicted] = countUnique(predLabelToTrueLabel);
146
+ const nClustersThatShouldMerge = countsOfTrueLabelsForPredicted.filter(count => count > 1).length;
147
+ return {
148
+ omitted: (nTrueLabels - countsOfTrueLabelsForPredicted.length) / nTrueLabels,
149
+ duplicated: nClustersThatShouldMerge / nTrueLabels,
150
+ };
151
+ };
152
+ exports.default = {
153
+ evaluateAdjustRandScore,
154
+ vMeasure,
155
+ completeness,
156
+ homogeneity,
157
+ getRepresentativeTraceMetrics,
158
+ };
@@ -0,0 +1,36 @@
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 { IHeapNode, IHeapSnapshot, LeakTrace, LeakTracePathItem, Optional, TraceCluster, TraceClusterDiff, IClusterStrategy } from '../lib/Types';
11
+ import type { NormalizedTraceElement } from './TraceElement';
12
+ declare type AggregateNodeCb = (ids: Set<number>, snapshot: IHeapSnapshot, checkCb: (node: IHeapNode) => boolean, calculateCb: (node: IHeapNode) => number) => number;
13
+ export default class NormalizedTrace {
14
+ private trace;
15
+ private traceSummary;
16
+ constructor(p?: LeakTracePathItem | null, snapshot?: IHeapSnapshot | null);
17
+ static pathToTrace(p: LeakTracePathItem, options?: {
18
+ untilFirstDetachedDOMElem?: boolean;
19
+ }): NormalizedTraceElement[];
20
+ static traceToPath(trace: Optional<LeakTrace>): LeakTracePathItem;
21
+ getTraceSummary(): string;
22
+ static addLeakedNodeToCluster(cluster: TraceCluster, path: LeakTracePathItem): void;
23
+ static calculateClusterRetainedSize(cluster: TraceCluster, snapshot: IHeapSnapshot, aggregateDominatorMetrics: AggregateNodeCb): number;
24
+ static samplePaths(paths: LeakTracePathItem[]): LeakTracePathItem[];
25
+ private static diffTraces;
26
+ static diffClusters(newClusters: TraceCluster[], existingClusters: TraceCluster[]): TraceClusterDiff;
27
+ static clusterLeakTraces(leakTraces: LeakTrace[]): Record<string, string>;
28
+ static clusterPaths(paths: LeakTracePathItem[], snapshot: IHeapSnapshot, aggregateDominatorMetrics: AggregateNodeCb, option?: {
29
+ strategy?: IClusterStrategy;
30
+ }): TraceCluster[];
31
+ static generateUnClassifiedClusters(paths: LeakTracePathItem[], snapshot: IHeapSnapshot, aggregateDominatorMetrics: AggregateNodeCb): TraceCluster[];
32
+ static loadCluster(): NormalizedTrace[];
33
+ static saveCluster(clusters: NormalizedTrace[]): void;
34
+ }
35
+ export {};
36
+ //# sourceMappingURL=TraceBucket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TraceBucket.d.ts","sourceRoot":"","sources":["../../src/trace-cluster/TraceBucket.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,SAAS,EACT,iBAAiB,EAEjB,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,gBAAgB,CAAC;AAW3D,aAAK,eAAe,GAAG,CACrB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAChB,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,EACrC,WAAW,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,MAAM,KACrC,MAAM,CAAC;AAIZ,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAS;gBAE3B,CAAC,GAAE,iBAAiB,GAAG,IAAW,EAClC,QAAQ,GAAE,aAAa,GAAG,IAAW;IAgBvC,MAAM,CAAC,WAAW,CAChB,CAAC,EAAE,iBAAiB,EACpB,OAAO,GAAE;QACP,yBAAyB,CAAC,EAAE,OAAO,CAAC;KAChC,GACL,sBAAsB,EAAE;IA8B3B,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,iBAAiB;IAkBjE,eAAe,IAAI,MAAM;IAIzB,MAAM,CAAC,sBAAsB,CAC3B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,iBAAiB,GACtB,IAAI;IAUP,MAAM,CAAC,4BAA4B,CACjC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,aAAa,EACvB,yBAAyB,EAAE,eAAe,GACzC,MAAM;IAYT,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE;IAmBnE,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,MAAM,CAAC,YAAY,CACjB,WAAW,EAAE,YAAY,EAAE,EAC3B,gBAAgB,EAAE,YAAY,EAAE,GAC/B,gBAAgB;IAwCnB,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAoBzE,MAAM,CAAC,YAAY,CACjB,KAAK,EAAE,iBAAiB,EAAE,EAC1B,QAAQ,EAAE,aAAa,EACvB,yBAAyB,EAAE,eAAe,EAC1C,MAAM,GAAE;QAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAA;KAAM,GACzC,YAAY,EAAE;IAgDjB,MAAM,CAAC,4BAA4B,CACjC,KAAK,EAAE,iBAAiB,EAAE,EAC1B,QAAQ,EAAE,aAAa,EACvB,yBAAyB,EAAE,eAAe,GACzC,YAAY,EAAE;IAMjB,MAAM,CAAC,WAAW,IAAI,eAAe,EAAE;IAevC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,IAAI;CAKtD"}