@memlab/core 1.1.21 → 1.1.23
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/dist/__tests__/lib/TestUtils.d.ts +13 -0
- package/dist/__tests__/lib/TestUtils.js +39 -0
- package/dist/lib/Config.d.ts +10 -1
- package/dist/lib/Config.js +21 -2
- package/dist/lib/Constant.js +1 -0
- package/dist/lib/FileManager.js +1 -1
- package/dist/lib/HeapAnalyzer.js +49 -27
- package/dist/lib/RunInfoUtils.d.ts +1 -0
- package/dist/lib/RunInfoUtils.js +8 -4
- package/dist/lib/SerializationHelper.d.ts +18 -0
- package/dist/lib/SerializationHelper.js +36 -0
- package/dist/lib/Serializer.d.ts +2 -6
- package/dist/lib/Serializer.js +12 -3
- package/dist/lib/TraceSampler.d.ts +36 -0
- package/dist/lib/TraceSampler.js +78 -0
- package/dist/lib/Types.d.ts +26 -3
- package/dist/lib/Utils.d.ts +8 -0
- package/dist/lib/Utils.js +74 -6
- package/dist/lib/charts/MemoryBarChart.js +2 -2
- package/dist/lib/heap-data/HeapStringNode.js +25 -16
- package/dist/lib/leak-filters/LeakFilterRuleList.js +2 -0
- package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.d.ts +0 -1
- package/dist/lib/leak-filters/rules/FilterDetachedDOMElement.rule.js +22 -9
- package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.js +50 -0
- package/dist/lib/leak-filters/rules/FilterUnmountedFiberNode.rule.js +4 -3
- package/dist/lib/leak-filters/rules/FilterXMLHTTPRequest.rule.d.ts +20 -0
- package/dist/lib/leak-filters/rules/FilterXMLHTTPRequest.rule.js +30 -0
- package/dist/lib/trace-filters/TraceFilterRuleList.js +2 -0
- package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.js +44 -0
- package/dist/paths/TraceFinder.js +1 -1
- package/dist/trace-cluster/TraceBucket.d.ts +1 -1
- package/dist/trace-cluster/TraceBucket.js +54 -22
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@ const TraceSimilarityStrategy_1 = __importDefault(require("./strategies/TraceSim
|
|
|
22
22
|
const TraceAsClusterStrategy_1 = __importDefault(require("./strategies/TraceAsClusterStrategy"));
|
|
23
23
|
const MLTraceSimilarityStrategy_1 = __importDefault(require("./strategies/MLTraceSimilarityStrategy"));
|
|
24
24
|
const ClusterUtils_1 = require("./ClusterUtils");
|
|
25
|
+
const TraceSampler_1 = __importDefault(require("../lib/TraceSampler"));
|
|
25
26
|
// sync up with html/intern/js/webspeed/memlab/lib/LeakCluster.js
|
|
26
27
|
class NormalizedTrace {
|
|
27
28
|
constructor(p = null, snapshot = null) {
|
|
@@ -127,26 +128,19 @@ class NormalizedTrace {
|
|
|
127
128
|
return Math.max(30, Utils_1.default.getNumberAtPercentile(lengthArr, 80));
|
|
128
129
|
}
|
|
129
130
|
static samplePaths(paths) {
|
|
130
|
-
const maxCount =
|
|
131
|
+
const maxCount = Config_1.default.maxSamplesForClustering;
|
|
131
132
|
if (paths.length <= maxCount) {
|
|
132
133
|
return [...paths];
|
|
133
134
|
}
|
|
134
|
-
const
|
|
135
|
-
if (sampleRatio < 1) {
|
|
136
|
-
Console_1.default.warning('Sampling trace due to a large number of traces:');
|
|
137
|
-
Console_1.default.lowLevel(` Number of Traces: ${paths.length}`);
|
|
138
|
-
Console_1.default.lowLevel(` Sampling Ratio: ${Utils_1.default.getReadablePercent(sampleRatio)}`);
|
|
139
|
-
}
|
|
135
|
+
const sampler = new TraceSampler_1.default(paths.length);
|
|
140
136
|
const ret = [];
|
|
141
137
|
const samplePathMaxLength = NormalizedTrace.getSamplePathMaxLength(paths);
|
|
142
138
|
if (Config_1.default.verbose) {
|
|
143
139
|
Console_1.default.lowLevel(` Sample Trace's Max Length: ${samplePathMaxLength}`);
|
|
144
140
|
}
|
|
141
|
+
paths = paths.filter(p => Utils_1.default.getLeakTracePathLength(p) <= samplePathMaxLength);
|
|
145
142
|
for (const p of paths) {
|
|
146
|
-
if (
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
if (Math.random() < sampleRatio) {
|
|
143
|
+
if (sampler.sample()) {
|
|
150
144
|
ret.push(p);
|
|
151
145
|
}
|
|
152
146
|
else {
|
|
@@ -157,6 +151,9 @@ class NormalizedTrace {
|
|
|
157
151
|
}
|
|
158
152
|
}
|
|
159
153
|
}
|
|
154
|
+
if (Config_1.default.verbose) {
|
|
155
|
+
Console_1.default.lowLevel(`Number of samples after sampling: ${ret.length}.`);
|
|
156
|
+
}
|
|
160
157
|
return ret;
|
|
161
158
|
}
|
|
162
159
|
static diffTraces(newTraces, existingTraces, // existing representative traces
|
|
@@ -194,6 +191,11 @@ class NormalizedTrace {
|
|
|
194
191
|
}
|
|
195
192
|
return traceToClusterMap.get(trace);
|
|
196
193
|
};
|
|
194
|
+
if (Config_1.default.isContinuousTest) {
|
|
195
|
+
Console_1.default.lowLevel(`${staleClusters.length} stale clusters`);
|
|
196
|
+
Console_1.default.lowLevel(`${clustersToAdd.length} new clusters`);
|
|
197
|
+
Console_1.default.lowLevel(`${allClusters.length} clusters in total`);
|
|
198
|
+
}
|
|
197
199
|
return {
|
|
198
200
|
staleClusters: staleClusters.map(traceToCluster),
|
|
199
201
|
clustersToAdd: clustersToAdd.map(traceToCluster),
|
|
@@ -308,43 +310,64 @@ class NormalizedTrace {
|
|
|
308
310
|
leakedNodeIds: new Set(),
|
|
309
311
|
};
|
|
310
312
|
}
|
|
311
|
-
static clusterControlTreatmentPaths(leakPathsFromControlRuns, controlSnapshots,
|
|
313
|
+
static clusterControlTreatmentPaths(leakPathsFromControlRuns, controlSnapshots, leakPathsFromTreatmentRuns, treatmentSnapshots, aggregateDominatorMetrics, option = {}) {
|
|
312
314
|
const result = {
|
|
313
|
-
|
|
315
|
+
controlLikelyOrOnlyClusters: [],
|
|
314
316
|
treatmentOnlyClusters: [],
|
|
317
|
+
treatmentLikelyClusters: [],
|
|
315
318
|
hybridClusters: [],
|
|
316
319
|
};
|
|
317
320
|
Console_1.default.overwrite('Clustering leak traces');
|
|
318
321
|
const totalControlPaths = leakPathsFromControlRuns.reduce((count, leakPaths) => count + leakPaths.length, 0);
|
|
319
|
-
|
|
322
|
+
const totalTreatmentPaths = leakPathsFromTreatmentRuns.reduce((count, leakPaths) => count + leakPaths.length, 0);
|
|
323
|
+
if (totalControlPaths === 0 && totalTreatmentPaths === 0) {
|
|
320
324
|
Console_1.default.midLevel('No leaks found');
|
|
321
325
|
return result;
|
|
322
326
|
}
|
|
323
327
|
// sample paths if there are too many
|
|
324
328
|
const flattenedLeakPathsFromControlRuns = leakPathsFromControlRuns.reduce((arr, leakPaths) => [...arr, ...leakPaths], []);
|
|
325
329
|
const controlPaths = this.samplePaths(flattenedLeakPathsFromControlRuns);
|
|
326
|
-
|
|
330
|
+
const pathsForEachTreatmentGroup = leakPathsFromTreatmentRuns.map((treatmentPaths) => this.samplePaths(treatmentPaths));
|
|
327
331
|
// build control trace to control path map
|
|
328
332
|
const controlTraceToPathMap = NormalizedTrace.buildTraceToPathMap(controlPaths);
|
|
329
333
|
const controlTraces = Array.from(controlTraceToPathMap.keys());
|
|
330
|
-
// build treatment trace to treatment path
|
|
331
|
-
|
|
332
|
-
|
|
334
|
+
// build treatment trace to treatment path maps
|
|
335
|
+
// we need to know the mapping to each treatment group
|
|
336
|
+
// to figure out if a trace cluster contains traces from all treatment groups
|
|
337
|
+
const treatmentTraceToPathMaps = pathsForEachTreatmentGroup.map(treatmentPaths => NormalizedTrace.buildTraceToPathMap(treatmentPaths));
|
|
338
|
+
const treatmentTraceToPathMap = new Map();
|
|
339
|
+
const treatmentTraces = [];
|
|
340
|
+
for (const map of treatmentTraceToPathMaps) {
|
|
341
|
+
for (const [key, value] of map.entries()) {
|
|
342
|
+
treatmentTraceToPathMap.set(key, value);
|
|
343
|
+
treatmentTraces.push(key);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
333
346
|
// cluster traces from both the control group and the treatment group
|
|
334
347
|
const { allClusters } = NormalizedTrace.diffTraces([...controlTraces, ...treatmentTraces], [], option);
|
|
335
|
-
// pick one of the control heap snapshots
|
|
348
|
+
// pick one of the control and treatment heap snapshots
|
|
336
349
|
const controlSnapshot = controlSnapshots[0];
|
|
350
|
+
const treatmentSnapshot = treatmentSnapshots[0];
|
|
337
351
|
// construct TraceCluster from clustering result
|
|
338
352
|
allClusters.forEach((traces) => {
|
|
339
353
|
var _a, _b;
|
|
340
354
|
const controlCluster = NormalizedTrace.initEmptyCluster(controlSnapshot);
|
|
341
355
|
const treatmentCluster = NormalizedTrace.initEmptyCluster(treatmentSnapshot);
|
|
356
|
+
// a set containing each the treatment group that
|
|
357
|
+
// has at least one trace in this cluster
|
|
358
|
+
const treatmentSetWithClusterTrace = new Set();
|
|
342
359
|
for (const trace of traces) {
|
|
343
360
|
const normalizedTrace = trace;
|
|
344
361
|
if (controlTraceToPathMap.has(normalizedTrace)) {
|
|
345
362
|
NormalizedTrace.pushLeakPathToCluster(controlTraceToPathMap, normalizedTrace, controlCluster);
|
|
346
363
|
}
|
|
347
364
|
else {
|
|
365
|
+
for (let i = 0; i < treatmentTraceToPathMaps.length; ++i) {
|
|
366
|
+
if (treatmentTraceToPathMaps[i].has(normalizedTrace)) {
|
|
367
|
+
treatmentSetWithClusterTrace.add(i);
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
348
371
|
NormalizedTrace.pushLeakPathToCluster(treatmentTraceToPathMap, normalizedTrace, treatmentCluster);
|
|
349
372
|
}
|
|
350
373
|
}
|
|
@@ -358,11 +381,19 @@ class NormalizedTrace {
|
|
|
358
381
|
if (treatmentClusterSize > 0) {
|
|
359
382
|
this.calculateClusterRetainedSize(treatmentCluster, treatmentSnapshot, aggregateDominatorMetrics);
|
|
360
383
|
}
|
|
361
|
-
if (controlClusterSize === 0
|
|
384
|
+
if (controlClusterSize === 0 &&
|
|
385
|
+
treatmentSetWithClusterTrace.size === leakPathsFromTreatmentRuns.length) {
|
|
386
|
+
// only when the leak cluster consists of traces from all treatment groups
|
|
362
387
|
result.treatmentOnlyClusters.push(treatmentCluster);
|
|
363
388
|
}
|
|
389
|
+
else if (controlClusterSize === 0) {
|
|
390
|
+
// when the leak cluster consists of traces from
|
|
391
|
+
// some but not all of treatment groups
|
|
392
|
+
result.treatmentLikelyClusters.push(treatmentCluster);
|
|
393
|
+
}
|
|
364
394
|
else if (treatmentClusterSize === 0) {
|
|
365
|
-
|
|
395
|
+
// when the leak cluster consists of traces from any of the control groups
|
|
396
|
+
result.controlLikelyOrOnlyClusters.push(controlCluster);
|
|
366
397
|
}
|
|
367
398
|
else {
|
|
368
399
|
result.hybridClusters.push({
|
|
@@ -372,7 +403,8 @@ class NormalizedTrace {
|
|
|
372
403
|
}
|
|
373
404
|
});
|
|
374
405
|
result.treatmentOnlyClusters.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); });
|
|
375
|
-
result.
|
|
406
|
+
result.treatmentLikelyClusters.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); });
|
|
407
|
+
result.controlLikelyOrOnlyClusters.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); });
|
|
376
408
|
result.hybridClusters.sort((g1, g2) => {
|
|
377
409
|
var _a, _b, _c, _d;
|
|
378
410
|
return ((_a = g2.control.retainedSize) !== null && _a !== void 0 ? _a : 0) +
|