@memlab/core 1.1.20 → 1.1.21
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/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/lib/Config.d.ts +2 -0
- package/dist/lib/Config.js +9 -0
- package/dist/lib/FileManager.d.ts +3 -0
- package/dist/lib/FileManager.js +10 -1
- package/dist/lib/HeapAnalyzer.d.ts +5 -1
- package/dist/lib/HeapAnalyzer.js +33 -21
- package/dist/lib/RunInfoUtils.d.ts +39 -0
- package/dist/lib/RunInfoUtils.js +86 -0
- package/dist/lib/Types.d.ts +7 -2
- package/dist/lib/Utils.d.ts +25 -19
- package/dist/lib/Utils.js +90 -148
- package/dist/lib/charts/MemoryBarChart.d.ts +1 -0
- package/dist/lib/charts/MemoryBarChart.js +18 -3
- package/dist/lib/trace-filters/BaseTraceFilter.rule.d.ts +29 -0
- package/dist/lib/trace-filters/BaseTraceFilter.rule.js +22 -0
- package/dist/lib/trace-filters/LeakTraceFilter.d.ts +20 -0
- package/dist/lib/trace-filters/LeakTraceFilter.js +37 -0
- package/dist/lib/trace-filters/TraceFilterRuleList.d.ts +13 -0
- package/dist/lib/trace-filters/TraceFilterRuleList.js +33 -0
- package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.js +55 -0
- package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.js +41 -0
- package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.js +29 -0
- package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.js +57 -0
- package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.js +62 -0
- package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.js +44 -0
- package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.js +49 -0
- package/dist/logger/LeakClusterLogger.js +1 -0
- package/dist/paths/TraceFinder.js +16 -2
- package/dist/trace-cluster/TraceBucket.d.ts +1 -1
- package/dist/trace-cluster/TraceBucket.js +7 -3
- package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export { default as utils } from './lib/Utils';
|
|
|
26
26
|
/** @internal */
|
|
27
27
|
export { default as fileManager } from './lib/FileManager';
|
|
28
28
|
/** @internal */
|
|
29
|
+
export { default as runInfoUtils } from './lib/RunInfoUtils';
|
|
30
|
+
/** @internal */
|
|
29
31
|
export * from './lib/FileManager';
|
|
30
32
|
/** @internal */
|
|
31
33
|
export { default as serializer } from './lib/Serializer';
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.TraceFinder = exports.MultiIterationSeqClustering = exports.SequentialClustering = exports.EvaluationMetric = exports.NormalizedTrace = exports.leakClusterLogger = exports.ProcessManager = exports.modes = exports.memoryBarChart = exports.constant = exports.analysis = exports.browserInfo = exports.serializer = exports.fileManager = exports.utils = exports.BaseOption = exports.info = exports.config = exports.registerPackage = void 0;
|
|
38
|
+
exports.TraceFinder = exports.MultiIterationSeqClustering = exports.SequentialClustering = exports.EvaluationMetric = exports.NormalizedTrace = exports.leakClusterLogger = exports.ProcessManager = exports.modes = exports.memoryBarChart = exports.constant = exports.analysis = exports.browserInfo = exports.serializer = exports.runInfoUtils = exports.fileManager = exports.utils = exports.BaseOption = exports.info = exports.config = exports.registerPackage = void 0;
|
|
39
39
|
const path_1 = __importDefault(require("path"));
|
|
40
40
|
const PackageInfoLoader_1 = require("./lib/PackageInfoLoader");
|
|
41
41
|
__exportStar(require("./lib/Types"), exports);
|
|
@@ -67,6 +67,9 @@ Object.defineProperty(exports, "utils", { enumerable: true, get: function () { r
|
|
|
67
67
|
var FileManager_1 = require("./lib/FileManager");
|
|
68
68
|
Object.defineProperty(exports, "fileManager", { enumerable: true, get: function () { return __importDefault(FileManager_1).default; } });
|
|
69
69
|
/** @internal */
|
|
70
|
+
var RunInfoUtils_1 = require("./lib/RunInfoUtils");
|
|
71
|
+
Object.defineProperty(exports, "runInfoUtils", { enumerable: true, get: function () { return __importDefault(RunInfoUtils_1).default; } });
|
|
72
|
+
/** @internal */
|
|
70
73
|
__exportStar(require("./lib/FileManager"), exports);
|
|
71
74
|
/** @internal */
|
|
72
75
|
var Serializer_1 = require("./lib/Serializer");
|
package/dist/lib/Config.d.ts
CHANGED
|
@@ -99,6 +99,7 @@ export declare class MemLabConfig {
|
|
|
99
99
|
dataBuilderDataDir: string;
|
|
100
100
|
unclassifiedClusterDir: string;
|
|
101
101
|
externalCookiesFile: Optional<string>;
|
|
102
|
+
extraRunInfoMap: Map<string, string>;
|
|
102
103
|
heapConfig: Optional<IHeapConfig>;
|
|
103
104
|
puppeteerConfig: LaunchOptions & BrowserLaunchArgumentOptions & BrowserConnectOptions;
|
|
104
105
|
openDevtoolsConsole: boolean;
|
|
@@ -225,6 +226,7 @@ export declare class MemLabConfig {
|
|
|
225
226
|
setDevice(deviceName: string, options?: {
|
|
226
227
|
manualOverride?: boolean;
|
|
227
228
|
}): void;
|
|
229
|
+
setRunInfo(key: string, value: string): void;
|
|
228
230
|
private removeFromSet;
|
|
229
231
|
private addToSet;
|
|
230
232
|
enableXvfb(display: string): void;
|
package/dist/lib/Config.js
CHANGED
|
@@ -176,6 +176,12 @@ class MemLabConfig {
|
|
|
176
176
|
// if true, split dataset into trunks
|
|
177
177
|
// with random order for sequential clustering
|
|
178
178
|
this.seqClusteringIsRandomChunks = false;
|
|
179
|
+
// extra E2E run info (other than the fields defined in
|
|
180
|
+
// RunMetaInfo like app, interaction, browserInfo).
|
|
181
|
+
// Information saved in this map will be
|
|
182
|
+
// auto-serialized to run-meta.json when the file is saved
|
|
183
|
+
// and auto-deserialized from run-meta.json when the file is loaded
|
|
184
|
+
this.extraRunInfoMap = new Map();
|
|
179
185
|
}
|
|
180
186
|
// initialize configurable parameters
|
|
181
187
|
init(options = {}) {
|
|
@@ -507,6 +513,9 @@ class MemLabConfig {
|
|
|
507
513
|
this.puppeteerConfig.defaultViewport = null;
|
|
508
514
|
this.defaultUserAgent = null;
|
|
509
515
|
}
|
|
516
|
+
setRunInfo(key, value) {
|
|
517
|
+
this.extraRunInfoMap.set(key, value);
|
|
518
|
+
}
|
|
510
519
|
removeFromSet(set, list) {
|
|
511
520
|
for (const v of list) {
|
|
512
521
|
set.delete(v);
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
import type { MemLabConfig } from './Config';
|
|
11
11
|
import type { AnyValue, FileOption } from './Types';
|
|
12
12
|
/** @internal */
|
|
13
|
+
export declare function joinAndProcessDir(options: FileOption, ...args: AnyValue[]): string;
|
|
14
|
+
/** @internal */
|
|
13
15
|
export declare class FileManager {
|
|
14
16
|
private memlabConfigCache;
|
|
15
17
|
getDefaultWorkDir(): string;
|
|
@@ -75,6 +77,7 @@ export declare class FileManager {
|
|
|
75
77
|
rmWorkDir(options?: FileOption): void;
|
|
76
78
|
isWithinInternalDirectory(filePath: string): boolean;
|
|
77
79
|
createDefaultVisitOrderMetaFile(options?: FileOption): void;
|
|
80
|
+
createDefaultVisitOrderMetaFileWithSingleSnapshot(options: FileOption | undefined, snapshotFile: string): void;
|
|
78
81
|
initDirs(config: MemLabConfig, options?: FileOption): void;
|
|
79
82
|
}
|
|
80
83
|
declare const _default: FileManager;
|
package/dist/lib/FileManager.js
CHANGED
|
@@ -12,13 +12,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.FileManager = void 0;
|
|
15
|
+
exports.FileManager = exports.joinAndProcessDir = void 0;
|
|
16
16
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
17
17
|
const os_1 = __importDefault(require("os"));
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
19
19
|
const Console_1 = __importDefault(require("./Console"));
|
|
20
20
|
const Constant_1 = __importDefault(require("./Constant"));
|
|
21
21
|
const Utils_1 = __importDefault(require("./Utils"));
|
|
22
|
+
/** @internal */
|
|
22
23
|
function joinAndProcessDir(options, ...args) {
|
|
23
24
|
const filepath = path_1.default.join(...args);
|
|
24
25
|
if (!fs_extra_1.default.existsSync(filepath)) {
|
|
@@ -34,6 +35,7 @@ function joinAndProcessDir(options, ...args) {
|
|
|
34
35
|
}
|
|
35
36
|
return filepath;
|
|
36
37
|
}
|
|
38
|
+
exports.joinAndProcessDir = joinAndProcessDir;
|
|
37
39
|
/** @internal */
|
|
38
40
|
class FileManager {
|
|
39
41
|
constructor() {
|
|
@@ -310,6 +312,9 @@ class FileManager {
|
|
|
310
312
|
}
|
|
311
313
|
}
|
|
312
314
|
isDirectory(file) {
|
|
315
|
+
if (!fs_extra_1.default.existsSync(file)) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
313
318
|
const stats = fs_extra_1.default.statSync(file);
|
|
314
319
|
return stats.isDirectory();
|
|
315
320
|
}
|
|
@@ -356,6 +361,10 @@ class FileManager {
|
|
|
356
361
|
}
|
|
357
362
|
// If there is at least one snapshot, create a snap-seq.json file.
|
|
358
363
|
// First, get the meta file for leak detection in a single heap snapshot
|
|
364
|
+
this.createDefaultVisitOrderMetaFileWithSingleSnapshot(options, snapshotFile);
|
|
365
|
+
}
|
|
366
|
+
createDefaultVisitOrderMetaFileWithSingleSnapshot(options = FileManager.defaultFileOption, snapshotFile) {
|
|
367
|
+
const snapshotSeqMetaFile = this.getSnapshotSequenceMetaFile(options);
|
|
359
368
|
const codeDataDir = this.getCodeDataDir();
|
|
360
369
|
const singleSnapshotMetaFile = path_1.default.join(codeDataDir, 'visit-order-single-snapshot.json');
|
|
361
370
|
const visitOrder = JSON.parse(fs_extra_1.default.readFileSync(singleSnapshotMetaFile, 'UTF-8'));
|
|
@@ -16,6 +16,10 @@ declare type DiffSnapshotsOptions = {
|
|
|
16
16
|
declare type WorkDirOptions = {
|
|
17
17
|
workDir?: string;
|
|
18
18
|
};
|
|
19
|
+
declare type GetTraceOptions = {
|
|
20
|
+
workDir?: string;
|
|
21
|
+
printConsoleOnly?: boolean;
|
|
22
|
+
};
|
|
19
23
|
declare class MemoryAnalyst {
|
|
20
24
|
checkLeak(): Promise<ISerializedInfo[]>;
|
|
21
25
|
diffLeakByWorkDir(options: DiffLeakOptions): Promise<ISerializedInfo[]>;
|
|
@@ -50,7 +54,7 @@ declare class MemoryAnalyst {
|
|
|
50
54
|
serializeClusterUpdate(clusters: TraceCluster[], options?: {
|
|
51
55
|
reclusterOnly?: boolean;
|
|
52
56
|
}): Promise<void>;
|
|
53
|
-
dumpPathByNodeId(leakedIdSet: HeapNodeIdSet, snapshot: IHeapSnapshot, nodeIdsInSnapshots: Array<HeapNodeIdSet>, id: number, pathLoaderFile: string, summaryFile: string, options?:
|
|
57
|
+
dumpPathByNodeId(leakedIdSet: HeapNodeIdSet, snapshot: IHeapSnapshot, nodeIdsInSnapshots: Array<HeapNodeIdSet>, id: number, pathLoaderFile: string, summaryFile: string, options?: GetTraceOptions): void;
|
|
54
58
|
}
|
|
55
59
|
declare const _default: MemoryAnalyst;
|
|
56
60
|
export default _default;
|
package/dist/lib/HeapAnalyzer.js
CHANGED
|
@@ -34,6 +34,7 @@ const TraceFinder_1 = __importDefault(require("../paths/TraceFinder"));
|
|
|
34
34
|
const TraceBucket_1 = __importDefault(require("../trace-cluster/TraceBucket"));
|
|
35
35
|
const LeakObjectFilter_1 = require("./leak-filters/LeakObjectFilter");
|
|
36
36
|
const MLTraceSimilarityStrategy_1 = __importDefault(require("../trace-cluster/strategies/MLTraceSimilarityStrategy"));
|
|
37
|
+
const LeakTraceFilter_1 = require("./trace-filters/LeakTraceFilter");
|
|
37
38
|
class MemoryAnalyst {
|
|
38
39
|
checkLeak() {
|
|
39
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -44,14 +45,14 @@ class MemoryAnalyst {
|
|
|
44
45
|
}
|
|
45
46
|
diffLeakByWorkDir(options) {
|
|
46
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
-
const
|
|
48
|
-
workDir:
|
|
49
|
-
});
|
|
48
|
+
const controlSnapshotDirs = options.controlWorkDirs.map(controlWorkDir => FileManager_1.default.getCurDataDir({
|
|
49
|
+
workDir: controlWorkDir,
|
|
50
|
+
}));
|
|
50
51
|
const treatmentSnapshotDir = FileManager_1.default.getCurDataDir({
|
|
51
52
|
workDir: options.treatmentWorkDir,
|
|
52
53
|
});
|
|
53
54
|
// check control working dir
|
|
54
|
-
Utils_1.default.checkSnapshots({ snapshotDir: controlSnapshotDir });
|
|
55
|
+
controlSnapshotDirs.forEach(controlSnapshotDir => Utils_1.default.checkSnapshots({ snapshotDir: controlSnapshotDir }));
|
|
55
56
|
// check treatment working dir
|
|
56
57
|
Utils_1.default.checkSnapshots({ snapshotDir: treatmentSnapshotDir });
|
|
57
58
|
// display control and treatment memory
|
|
@@ -63,31 +64,37 @@ class MemoryAnalyst {
|
|
|
63
64
|
diffMemoryLeakTraces(options) {
|
|
64
65
|
return __awaiter(this, void 0, void 0, function* () {
|
|
65
66
|
Config_1.default.dumpNodeInfo = false;
|
|
66
|
-
// diff snapshots and get control raw paths
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// diff snapshots from control dirs and get control raw paths array
|
|
68
|
+
const controlSnapshots = [];
|
|
69
|
+
const leakPathsFromControlRuns = [];
|
|
70
|
+
for (const controlWorkDir of options.controlWorkDirs) {
|
|
71
|
+
const snapshotDiff = yield this.diffSnapshots({
|
|
72
|
+
loadAllSnapshots: true,
|
|
73
|
+
workDir: controlWorkDir,
|
|
74
|
+
});
|
|
75
|
+
leakPathsFromControlRuns.push(this.filterLeakPaths(snapshotDiff.leakedHeapNodeIdSet, snapshotDiff.snapshot, { workDir: controlWorkDir }));
|
|
76
|
+
controlSnapshots.push(snapshotDiff.snapshot);
|
|
77
|
+
}
|
|
73
78
|
// diff snapshots and get treatment raw paths
|
|
74
|
-
snapshotDiff = yield this.diffSnapshots({
|
|
79
|
+
const snapshotDiff = yield this.diffSnapshots({
|
|
75
80
|
loadAllSnapshots: true,
|
|
76
81
|
workDir: options.treatmentWorkDir,
|
|
77
82
|
});
|
|
78
|
-
const treatmentLeakPaths = this.filterLeakPaths(snapshotDiff.leakedHeapNodeIdSet, snapshotDiff.snapshot, { workDir: options.
|
|
83
|
+
const treatmentLeakPaths = this.filterLeakPaths(snapshotDiff.leakedHeapNodeIdSet, snapshotDiff.snapshot, { workDir: options.treatmentWorkDir });
|
|
79
84
|
const treatmentSnapshot = snapshotDiff.snapshot;
|
|
80
|
-
|
|
85
|
+
const controlPathCounts = JSON.stringify(leakPathsFromControlRuns.map(leakPaths => leakPaths.length));
|
|
86
|
+
Console_1.default.topLevel(`${controlPathCounts} traces from control group`);
|
|
81
87
|
Console_1.default.topLevel(`${treatmentLeakPaths.length} traces from treatment group`);
|
|
82
|
-
const result = TraceBucket_1.default.clusterControlTreatmentPaths(
|
|
88
|
+
const result = TraceBucket_1.default.clusterControlTreatmentPaths(leakPathsFromControlRuns, controlSnapshots, treatmentLeakPaths, treatmentSnapshot, Utils_1.default.aggregateDominatorMetrics, {
|
|
83
89
|
strategy: Config_1.default.isMLClustering
|
|
84
90
|
? new MLTraceSimilarityStrategy_1.default()
|
|
85
91
|
: undefined,
|
|
86
92
|
});
|
|
87
93
|
Console_1.default.midLevel(`MemLab found ${result.treatmentOnlyClusters.length} new leak(s) in the treatment group`);
|
|
88
94
|
yield this.serializeClusterUpdate(result.treatmentOnlyClusters);
|
|
89
|
-
//
|
|
90
|
-
|
|
95
|
+
// serialize JSON file with detailed leak trace information
|
|
96
|
+
const treatmentOnlyPaths = result.treatmentOnlyClusters.map(c => c.path);
|
|
97
|
+
return LeakTraceDetailsLogger_1.default.logTraces(snapshotDiff.leakedHeapNodeIdSet, snapshotDiff.snapshot, snapshotDiff.listOfLeakedHeapNodeIdSet, treatmentOnlyPaths, Config_1.default.traceJsonOutDir);
|
|
91
98
|
});
|
|
92
99
|
}
|
|
93
100
|
// find all unique pattern of leaks
|
|
@@ -124,7 +131,7 @@ class MemoryAnalyst {
|
|
|
124
131
|
snapshotLeakedHeapNodeIdSet = snapshotDiff.leakedHeapNodeIdSet;
|
|
125
132
|
snapshot = snapshotDiff.snapshot;
|
|
126
133
|
}
|
|
127
|
-
this.dumpPathByNodeId(snapshotLeakedHeapNodeIdSet, snapshot, nodeIdsInSnapshots, Config_1.default.focusFiberNodeId, Config_1.default.viewJsonFile, Config_1.default.singleReportSummary);
|
|
134
|
+
this.dumpPathByNodeId(snapshotLeakedHeapNodeIdSet, snapshot, nodeIdsInSnapshots, Config_1.default.focusFiberNodeId, Config_1.default.viewJsonFile, Config_1.default.singleReportSummary, { printConsoleOnly: true });
|
|
128
135
|
});
|
|
129
136
|
}
|
|
130
137
|
shouldLoadCompleteSnapshot(tabsOrder, tab) {
|
|
@@ -348,6 +355,7 @@ class MemoryAnalyst {
|
|
|
348
355
|
this.printHeapAndLeakInfo(leakedNodeIds, snapshot, options);
|
|
349
356
|
// get all leaked objects
|
|
350
357
|
this.filterLeakedObjects(leakedNodeIds, snapshot);
|
|
358
|
+
const leakTraceFilter = new LeakTraceFilter_1.LeakTraceFilter();
|
|
351
359
|
const nodeIdInPaths = new Set();
|
|
352
360
|
const paths = [];
|
|
353
361
|
let numOfLeakedObjects = 0;
|
|
@@ -359,7 +367,8 @@ class MemoryAnalyst {
|
|
|
359
367
|
}
|
|
360
368
|
// BFS search for path from the leaked node to GC roots
|
|
361
369
|
const p = finder.getPathToGCRoots(snapshot, node);
|
|
362
|
-
if (
|
|
370
|
+
if (p == null ||
|
|
371
|
+
!leakTraceFilter.filter(p, { config: Config_1.default, leakedNodeIds, snapshot })) {
|
|
363
372
|
return;
|
|
364
373
|
}
|
|
365
374
|
++numOfLeakedObjects;
|
|
@@ -451,10 +460,13 @@ class MemoryAnalyst {
|
|
|
451
460
|
return;
|
|
452
461
|
}
|
|
453
462
|
LeakTraceDetailsLogger_1.default.logTrace(leakedIdSet, snapshot, nodeIdsInSnapshots, path, pathLoaderFile);
|
|
454
|
-
const tabsOrder = Utils_1.default.loadTabsOrder(FileManager_1.default.getSnapshotSequenceMetaFile(options));
|
|
455
|
-
const interactionSummary = Serializer_1.default.summarizeTabsOrder(tabsOrder);
|
|
456
463
|
let pathSummary = Serializer_1.default.summarizePath(path, nodeIdInPaths, snapshot, { color: true });
|
|
457
464
|
Console_1.default.topLevel(pathSummary);
|
|
465
|
+
if (options.printConsoleOnly) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const tabsOrder = Utils_1.default.loadTabsOrder(FileManager_1.default.getSnapshotSequenceMetaFile(options));
|
|
469
|
+
const interactionSummary = Serializer_1.default.summarizeTabsOrder(tabsOrder);
|
|
458
470
|
pathSummary = Serializer_1.default.summarizePath(path, nodeIdInPaths, snapshot);
|
|
459
471
|
const summary = `Page Interaction: \n${interactionSummary}\n\n` +
|
|
460
472
|
`Path from GC Root to Leaked Object:\n${pathSummary}`;
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
import type { Nullable, Optional, RunMetaInfo } from './Types';
|
|
11
|
+
export declare class RunMetaInfoManager {
|
|
12
|
+
getRunMetaFilePath(options?: {
|
|
13
|
+
workDir?: Optional<string>;
|
|
14
|
+
}): string;
|
|
15
|
+
saveRunMetaInfo(runMetaInfo: RunMetaInfo, options?: {
|
|
16
|
+
workDir?: Optional<string>;
|
|
17
|
+
extraRunInfo?: Map<string, string>;
|
|
18
|
+
}): string;
|
|
19
|
+
private loadRunMetaInfoFromFile;
|
|
20
|
+
loadRunMetaInfo(options?: {
|
|
21
|
+
metaFile?: Optional<string>;
|
|
22
|
+
workDir?: Optional<string>;
|
|
23
|
+
}): RunMetaInfo;
|
|
24
|
+
loadRunMetaInfoSilentFail(options?: {
|
|
25
|
+
metaFile?: Optional<string>;
|
|
26
|
+
workDir?: Optional<string>;
|
|
27
|
+
}): Nullable<RunMetaInfo>;
|
|
28
|
+
loadRunMetaExternalTemplate(): RunMetaInfo;
|
|
29
|
+
setConfigFromRunMeta(options?: {
|
|
30
|
+
workDir?: Optional<string>;
|
|
31
|
+
silentFail?: boolean;
|
|
32
|
+
}): void;
|
|
33
|
+
}
|
|
34
|
+
declare const runInfoUtils: {
|
|
35
|
+
runMetaInfoManager: RunMetaInfoManager;
|
|
36
|
+
};
|
|
37
|
+
/** @internal */
|
|
38
|
+
export default runInfoUtils;
|
|
39
|
+
//# sourceMappingURL=RunInfoUtils.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RunMetaInfoManager = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const BrowserInfo_1 = __importDefault(require("./BrowserInfo"));
|
|
9
|
+
const Config_1 = __importDefault(require("./Config"));
|
|
10
|
+
const Constant_1 = __importDefault(require("./Constant"));
|
|
11
|
+
const FileManager_1 = __importDefault(require("./FileManager"));
|
|
12
|
+
const Utils_1 = __importDefault(require("./Utils"));
|
|
13
|
+
const InternalValueSetter_1 = require("./InternalValueSetter");
|
|
14
|
+
class RunMetaInfoManager {
|
|
15
|
+
getRunMetaFilePath(options) {
|
|
16
|
+
if ((options === null || options === void 0 ? void 0 : options.workDir) != null) {
|
|
17
|
+
return FileManager_1.default.getRunMetaFile({ workDir: options.workDir });
|
|
18
|
+
}
|
|
19
|
+
if (Config_1.default.useExternalSnapshot) {
|
|
20
|
+
return Config_1.default.externalRunMetaFile;
|
|
21
|
+
}
|
|
22
|
+
if (Config_1.default.runMetaFile != null) {
|
|
23
|
+
return Config_1.default.runMetaFile;
|
|
24
|
+
}
|
|
25
|
+
return FileManager_1.default.getRunMetaFile();
|
|
26
|
+
}
|
|
27
|
+
saveRunMetaInfo(runMetaInfo, options) {
|
|
28
|
+
var _a;
|
|
29
|
+
const runMetaFile = this.getRunMetaFilePath(options);
|
|
30
|
+
const serializable = Object.assign(Object.assign({}, runMetaInfo), { extraInfo: Object.assign(Object.assign({}, Utils_1.default.mapToObject(Config_1.default.extraRunInfoMap)), Utils_1.default.mapToObject((_a = options === null || options === void 0 ? void 0 : options.extraRunInfo) !== null && _a !== void 0 ? _a : new Map())) });
|
|
31
|
+
fs_1.default.writeFileSync(runMetaFile, JSON.stringify(serializable, null, 2), 'UTF-8');
|
|
32
|
+
return runMetaFile;
|
|
33
|
+
}
|
|
34
|
+
loadRunMetaInfoFromFile(file) {
|
|
35
|
+
const content = fs_1.default.readFileSync(file, 'UTF-8');
|
|
36
|
+
const runMetaInfo = JSON.parse(content);
|
|
37
|
+
if (runMetaInfo && runMetaInfo.extraInfo) {
|
|
38
|
+
Config_1.default.extraRunInfoMap = Utils_1.default.objectToMap(runMetaInfo.extraInfo);
|
|
39
|
+
}
|
|
40
|
+
return runMetaInfo;
|
|
41
|
+
}
|
|
42
|
+
loadRunMetaInfo(options) {
|
|
43
|
+
const file = (options === null || options === void 0 ? void 0 : options.metaFile) || this.getRunMetaFilePath(options);
|
|
44
|
+
try {
|
|
45
|
+
return this.loadRunMetaInfoFromFile(file);
|
|
46
|
+
}
|
|
47
|
+
catch (_) {
|
|
48
|
+
throw Utils_1.default.haltOrThrow('Run info missing. Please make sure `memlab run` is complete.');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
loadRunMetaInfoSilentFail(options) {
|
|
52
|
+
const file = (options === null || options === void 0 ? void 0 : options.metaFile) || this.getRunMetaFilePath(options);
|
|
53
|
+
try {
|
|
54
|
+
return this.loadRunMetaInfoFromFile(file);
|
|
55
|
+
}
|
|
56
|
+
catch (_) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
loadRunMetaExternalTemplate() {
|
|
61
|
+
const runMetaTemplateFile = FileManager_1.default.getRunMetaExternalTemplateFile();
|
|
62
|
+
return JSON.parse(fs_1.default.readFileSync(runMetaTemplateFile, 'UTF-8'));
|
|
63
|
+
}
|
|
64
|
+
setConfigFromRunMeta(options = {}) {
|
|
65
|
+
const meta = (options === null || options === void 0 ? void 0 : options.silentFail)
|
|
66
|
+
? this.loadRunMetaInfoSilentFail(options)
|
|
67
|
+
: this.loadRunMetaInfo(options);
|
|
68
|
+
if (meta == null) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.app) == null || (meta === null || meta === void 0 ? void 0 : meta.interaction) == null) {
|
|
72
|
+
if (options === null || options === void 0 ? void 0 : options.silentFail) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
throw Utils_1.default.haltOrThrow('No app or interaction infomation');
|
|
76
|
+
}
|
|
77
|
+
Config_1.default.targetApp = meta.app;
|
|
78
|
+
Config_1.default.targetTab = meta.interaction;
|
|
79
|
+
BrowserInfo_1.default.load(meta.browserInfo);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.RunMetaInfoManager = RunMetaInfoManager;
|
|
83
|
+
const runInfoUtils = { runMetaInfoManager: new RunMetaInfoManager() };
|
|
84
|
+
(0, InternalValueSetter_1.setInternalValue)(runInfoUtils, __filename, Constant_1.default.internalDir);
|
|
85
|
+
/** @internal */
|
|
86
|
+
exports.default = runInfoUtils;
|
package/dist/lib/Types.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare type Optional<T> = Nullable<T> | undefined;
|
|
|
23
23
|
/** @internal */
|
|
24
24
|
export declare type AnyRecord = Record<string, RecordValue>;
|
|
25
25
|
/** @internal */
|
|
26
|
+
export declare type StringRecord = Record<string, string>;
|
|
27
|
+
/** @internal */
|
|
26
28
|
export declare type AnyAyncFunction = (...args: AnyValue[]) => Promise<AnyValue>;
|
|
27
29
|
/** @internal */
|
|
28
30
|
export declare type AnyFunction = (...args: AnyValue[]) => AnyValue;
|
|
@@ -66,6 +68,7 @@ export declare type XvfbType = {
|
|
|
66
68
|
export declare type ShellOptions = {
|
|
67
69
|
dir?: Optional<string>;
|
|
68
70
|
ignoreError?: Optional<boolean>;
|
|
71
|
+
throwError?: Optional<boolean>;
|
|
69
72
|
disconnectStdio?: Optional<boolean>;
|
|
70
73
|
};
|
|
71
74
|
/** @internal */
|
|
@@ -942,6 +945,8 @@ export declare type RunMetaInfo = {
|
|
|
942
945
|
* output data from the browser
|
|
943
946
|
*/
|
|
944
947
|
browserInfo: IBrowserInfo;
|
|
948
|
+
/** @internal */
|
|
949
|
+
extraInfo?: StringRecord;
|
|
945
950
|
};
|
|
946
951
|
/**
|
|
947
952
|
* A heap snapshot is generally a graph where graph nodes are JS heap objects
|
|
@@ -1924,12 +1929,12 @@ export interface IOveralLeakInfo extends Partial<IOveralHeapInfo> {
|
|
|
1924
1929
|
}
|
|
1925
1930
|
/** @internal */
|
|
1926
1931
|
export declare type DiffLeakOptions = {
|
|
1927
|
-
|
|
1932
|
+
controlWorkDirs: string[];
|
|
1928
1933
|
treatmentWorkDir: string;
|
|
1929
1934
|
};
|
|
1930
1935
|
/** @internal */
|
|
1931
1936
|
export declare type PlotMemoryOptions = {
|
|
1932
|
-
|
|
1937
|
+
controlWorkDirs?: string[];
|
|
1933
1938
|
treatmentWorkDir?: string;
|
|
1934
1939
|
workDir?: string;
|
|
1935
1940
|
} & IMemoryAnalystOptions;
|
package/dist/lib/Utils.d.ts
CHANGED
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
* @format
|
|
8
8
|
* @oncall web_perf_infra
|
|
9
9
|
*/
|
|
10
|
-
import type { HaltOrThrowOptions, HeapNodeIdSet, ShellOptions } from './Types';
|
|
10
|
+
import type { HaltOrThrowOptions, HeapNodeIdSet, ShellOptions, StringRecord } from './Types';
|
|
11
11
|
import type { Browser, Page } from 'puppeteer';
|
|
12
|
-
import type { AnyAyncFunction, AnyOptions, E2EStepInfo, IHeapSnapshot, IHeapNode, IHeapEdge, IScenario, ILeakFilter, LeakTracePathItem,
|
|
12
|
+
import type { AnyAyncFunction, AnyOptions, E2EStepInfo, IHeapSnapshot, IHeapNode, IHeapEdge, IScenario, ILeakFilter, LeakTracePathItem, RawHeapSnapshot, Nullable, Optional } from './Types';
|
|
13
13
|
declare function isHermesInternalObject(node: IHeapNode): boolean;
|
|
14
14
|
declare function isStackTraceFrame(node: IHeapNode): boolean;
|
|
15
15
|
declare function isFiberNode(node: Optional<IHeapNode>): boolean;
|
|
16
16
|
declare function isDetachedFiberNode(node: IHeapNode): boolean;
|
|
17
|
+
declare function isDOMInternalNode(node: Optional<IHeapNode>): boolean;
|
|
18
|
+
declare function isGlobalHandlesNode(node: Optional<IHeapNode>): boolean;
|
|
17
19
|
declare function isDetachedDOMNode(node: Optional<IHeapNode>, args?: AnyOptions): boolean;
|
|
18
20
|
declare function isWeakMapEdge(edge: IHeapEdge): boolean;
|
|
19
21
|
declare function isWeakMapEdgeToKey(edge: IHeapEdge): boolean;
|
|
@@ -23,6 +25,9 @@ declare function isFiberNodeDeletionsEdge(edge: IHeapEdge): boolean;
|
|
|
23
25
|
declare function isBlinkRootNode(node: IHeapNode): boolean;
|
|
24
26
|
declare function isPendingActivityNode(node: IHeapNode): boolean;
|
|
25
27
|
declare function isDOMNodeIncomplete(node: IHeapNode): boolean;
|
|
28
|
+
declare function isXMLDocumentNode(node: IHeapNode): boolean;
|
|
29
|
+
declare function isHTMLDocumentNode(node: IHeapNode): boolean;
|
|
30
|
+
declare function isDOMTextNode(node: IHeapNode): boolean;
|
|
26
31
|
declare function isRootNode(node: IHeapNode, opt?: AnyOptions): boolean;
|
|
27
32
|
declare function isDirectPropEdge(edge: IHeapEdge): boolean;
|
|
28
33
|
declare function isReturnEdge(edge: IHeapEdge): boolean;
|
|
@@ -64,12 +69,8 @@ declare function getBooleanNodeValue(node: IHeapNode): Nullable<boolean>;
|
|
|
64
69
|
declare function getToNodeByEdge(node: Nullable<IHeapNode>, propName: string, propType?: string): Nullable<IHeapNode>;
|
|
65
70
|
declare function extractHTMLElementNodeInfo(node: IHeapNode): string;
|
|
66
71
|
declare function hasOnlyWeakReferrers(node: IHeapNode): boolean;
|
|
67
|
-
declare function getRunMetaFilePath(): string;
|
|
68
|
-
declare function loadRunMetaInfo(metaFile?: Optional<string>): RunMetaInfo;
|
|
69
|
-
declare function loadTargetInfoFromRunMeta(): void;
|
|
70
72
|
declare function getSnapshotSequenceFilePath(): string;
|
|
71
73
|
declare function loadTabsOrder(metaFile?: Optional<string>): E2EStepInfo[];
|
|
72
|
-
declare function isInterestingPath(p: LeakTracePathItem): boolean;
|
|
73
74
|
declare function isObjectNode(node: IHeapNode): boolean;
|
|
74
75
|
declare function isPlainJSObjectNode(node: IHeapNode): boolean;
|
|
75
76
|
declare function pathHasDetachedHTMLNode(path: LeakTracePathItem): boolean;
|
|
@@ -129,14 +130,16 @@ declare function getRetainedSize(node: IHeapNode): number;
|
|
|
129
130
|
declare function aggregateDominatorMetrics(ids: HeapNodeIdSet, snapshot: IHeapSnapshot, checkNodeCb: (node: IHeapNode) => boolean, nodeMetricsCb: (node: IHeapNode) => number): number;
|
|
130
131
|
declare function getLeakTracePathLength(path: LeakTracePathItem): number;
|
|
131
132
|
declare function getNumberAtPercentile(arr: number[], percentile: number): number;
|
|
133
|
+
declare function mapToObject(map: Map<string, string>): StringRecord;
|
|
134
|
+
declare function objectToMap(object: StringRecord): Map<string, string>;
|
|
132
135
|
declare const _default: {
|
|
133
136
|
aggregateDominatorMetrics: typeof aggregateDominatorMetrics;
|
|
134
137
|
applyToNodes: typeof applyToNodes;
|
|
135
138
|
callAsync: typeof callAsync;
|
|
136
139
|
camelCaseToReadableString: typeof camelCaseToReadableString;
|
|
140
|
+
checkIsChildOfParent: typeof checkIsChildOfParent;
|
|
137
141
|
checkSnapshots: typeof checkSnapshots;
|
|
138
142
|
checkUninstalledLibrary: typeof checkUninstalledLibrary;
|
|
139
|
-
checkIsChildOfParent: typeof checkIsChildOfParent;
|
|
140
143
|
closePuppeteer: typeof closePuppeteer;
|
|
141
144
|
dumpSnapshot: typeof dumpSnapshot;
|
|
142
145
|
equalOrMatch: typeof equalOrMatch;
|
|
@@ -145,13 +148,14 @@ declare const _default: {
|
|
|
145
148
|
extractHTMLElementNodeInfo: typeof extractHTMLElementNodeInfo;
|
|
146
149
|
filterNodesInPlace: typeof filterNodesInPlace;
|
|
147
150
|
getAllDominators: typeof getAllDominators;
|
|
151
|
+
getBooleanNodeValue: typeof getBooleanNodeValue;
|
|
148
152
|
getClosureSourceUrl: typeof getClosureSourceUrl;
|
|
149
153
|
getConditionalDominatorIds: typeof getConditionalDominatorIds;
|
|
150
|
-
getError: typeof getError;
|
|
151
154
|
getEdgeByNameAndType: typeof getEdgeByNameAndType;
|
|
155
|
+
getError: typeof getError;
|
|
152
156
|
getLastNodeId: typeof getLastNodeId;
|
|
153
|
-
getLeakedNode: typeof getLeakedNode;
|
|
154
157
|
getLeakTracePathLength: typeof getLeakTracePathLength;
|
|
158
|
+
getLeakedNode: typeof getLeakedNode;
|
|
155
159
|
getNodesIdSet: typeof getNodesIdSet;
|
|
156
160
|
getNumberAtPercentile: typeof getNumberAtPercentile;
|
|
157
161
|
getNumberNodeValue: typeof getNumberNodeValue;
|
|
@@ -159,17 +163,16 @@ declare const _default: {
|
|
|
159
163
|
getReadablePercent: typeof getReadablePercent;
|
|
160
164
|
getReadableTime: typeof getReadableTime;
|
|
161
165
|
getRetainedSize: typeof getRetainedSize;
|
|
162
|
-
getRunMetaFilePath: typeof getRunMetaFilePath;
|
|
163
166
|
getScenarioName: typeof getScenarioName;
|
|
164
167
|
getSingleSnapshotFileForAnalysis: typeof getSingleSnapshotFileForAnalysis;
|
|
165
168
|
getSnapshotDirForAnalysis: typeof getSnapshotDirForAnalysis;
|
|
166
|
-
|
|
169
|
+
getSnapshotFilePath: typeof getSnapshotFilePath;
|
|
170
|
+
getSnapshotFilePathWithTabType: typeof getSnapshotFilePathWithTabType;
|
|
167
171
|
getSnapshotFilesFromTabsOrder: typeof getSnapshotFilesFromTabsOrder;
|
|
172
|
+
getSnapshotFilesInDir: typeof getSnapshotFilesInDir;
|
|
168
173
|
getSnapshotFromFile: typeof getSnapshotFromFile;
|
|
169
174
|
getSnapshotNodeIdsFromFile: typeof getSnapshotNodeIdsFromFile;
|
|
170
175
|
getSnapshotSequenceFilePath: typeof getSnapshotSequenceFilePath;
|
|
171
|
-
getSnapshotFilePath: typeof getSnapshotFilePath;
|
|
172
|
-
getSnapshotFilePathWithTabType: typeof getSnapshotFilePathWithTabType;
|
|
173
176
|
getStringNodeValue: typeof getStringNodeValue;
|
|
174
177
|
getToNodeByEdge: typeof getToNodeByEdge;
|
|
175
178
|
getUniqueID: typeof getUniqueID;
|
|
@@ -180,18 +183,21 @@ declare const _default: {
|
|
|
180
183
|
hasReactEdges: typeof hasReactEdges;
|
|
181
184
|
isAlternateNode: typeof isAlternateNode;
|
|
182
185
|
isBlinkRootNode: typeof isBlinkRootNode;
|
|
186
|
+
isDOMInternalNode: typeof isDOMInternalNode;
|
|
187
|
+
isDOMNodeIncomplete: typeof isDOMNodeIncomplete;
|
|
188
|
+
isDOMTextNode: typeof isDOMTextNode;
|
|
183
189
|
isDebuggableNode: typeof isDebuggableNode;
|
|
184
|
-
isDetachedFiberNode: typeof isDetachedFiberNode;
|
|
185
190
|
isDetachedDOMNode: typeof isDetachedDOMNode;
|
|
191
|
+
isDetachedFiberNode: typeof isDetachedFiberNode;
|
|
186
192
|
isDirectPropEdge: typeof isDirectPropEdge;
|
|
187
193
|
isDocumentDOMTreesRoot: typeof isDocumentDOMTreesRoot;
|
|
188
|
-
isDOMNodeIncomplete: typeof isDOMNodeIncomplete;
|
|
189
194
|
isEssentialEdge: typeof isEssentialEdge;
|
|
190
195
|
isFiberNode: typeof isFiberNode;
|
|
191
196
|
isFiberNodeDeletionsEdge: typeof isFiberNodeDeletionsEdge;
|
|
197
|
+
isGlobalHandlesNode: typeof isGlobalHandlesNode;
|
|
198
|
+
isHTMLDocumentNode: typeof isHTMLDocumentNode;
|
|
192
199
|
isHermesInternalObject: typeof isHermesInternalObject;
|
|
193
200
|
isHostRoot: typeof isHostRoot;
|
|
194
|
-
isInterestingPath: typeof isInterestingPath;
|
|
195
201
|
isMeaningfulEdge: typeof isMeaningfulEdge;
|
|
196
202
|
isMeaningfulNode: typeof isMeaningfulNode;
|
|
197
203
|
isNodeDominatedByDeletionsArray: typeof isNodeDominatedByDeletionsArray;
|
|
@@ -210,17 +216,18 @@ declare const _default: {
|
|
|
210
216
|
isWeakMapEdge: typeof isWeakMapEdge;
|
|
211
217
|
isWeakMapEdgeToKey: typeof isWeakMapEdgeToKey;
|
|
212
218
|
isWeakMapEdgeToValue: typeof isWeakMapEdgeToValue;
|
|
219
|
+
isXMLDocumentNode: typeof isXMLDocumentNode;
|
|
213
220
|
iterateChildFiberNodes: typeof iterateChildFiberNodes;
|
|
214
221
|
iterateDescendantFiberNodes: typeof iterateDescendantFiberNodes;
|
|
215
|
-
loadRunMetaInfo: typeof loadRunMetaInfo;
|
|
216
222
|
loadLeakFilter: typeof loadLeakFilter;
|
|
217
223
|
loadScenario: typeof loadScenario;
|
|
218
224
|
loadTabsOrder: typeof loadTabsOrder;
|
|
219
|
-
|
|
225
|
+
mapToObject: typeof mapToObject;
|
|
220
226
|
markAllDetachedFiberNode: typeof markAllDetachedFiberNode;
|
|
221
227
|
markAlternateFiberNode: typeof markAlternateFiberNode;
|
|
222
228
|
memCache: Record<string, any>;
|
|
223
229
|
normalizeBaseUrl: typeof normalizeBaseUrl;
|
|
230
|
+
objectToMap: typeof objectToMap;
|
|
224
231
|
pathHasDetachedHTMLNode: typeof pathHasDetachedHTMLNode;
|
|
225
232
|
pathHasEdgeWithIndex: typeof pathHasEdgeWithIndex;
|
|
226
233
|
repeat: typeof repeat;
|
|
@@ -233,7 +240,6 @@ declare const _default: {
|
|
|
233
240
|
shuffleArray: typeof shuffleArray;
|
|
234
241
|
throwError: typeof throwError;
|
|
235
242
|
upperCaseFirstCharacter: typeof upperCaseFirstCharacter;
|
|
236
|
-
getBooleanNodeValue: typeof getBooleanNodeValue;
|
|
237
243
|
};
|
|
238
244
|
export default _default;
|
|
239
245
|
//# sourceMappingURL=Utils.d.ts.map
|