@memlab/heap-analysis 1.0.31 → 1.0.33
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/PluginUtils.d.ts +2 -0
- package/dist/PluginUtils.d.ts.map +1 -1
- package/dist/PluginUtils.js +51 -0
- package/dist/options/HeapAnalysisOutputOption.d.ts +20 -0
- package/dist/options/HeapAnalysisOutputOption.d.ts.map +1 -0
- package/dist/options/HeapAnalysisOutputOption.js +56 -0
- package/dist/plugins/CollectionsHoldingStaleAnalysis.d.ts +1 -0
- package/dist/plugins/CollectionsHoldingStaleAnalysis.d.ts.map +1 -1
- package/dist/plugins/CollectionsHoldingStaleAnalysis.js +24 -3
- package/dist/plugins/ObjectContentAnalysis.d.ts +1 -0
- package/dist/plugins/ObjectContentAnalysis.d.ts.map +1 -1
- package/dist/plugins/ObjectContentAnalysis.js +34 -26
- package/package.json +3 -3
package/dist/PluginUtils.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ type PrintNodeOption = {
|
|
|
51
51
|
printReferences?: boolean;
|
|
52
52
|
};
|
|
53
53
|
declare function printNodeListInTerminal(nodeList: IHeapNode[], options?: AnyOptions & PrintNodeOption): void;
|
|
54
|
+
declare function printNodeInTerminal(node: IHeapNode): void;
|
|
54
55
|
declare function printReferencesInTerminal(edgeList: IHeapEdge[], options?: AnyOptions & PrintNodeOption): void;
|
|
55
56
|
declare function printReferrersInTerminal(edgeList: IHeapEdge[], options?: AnyOptions & PrintNodeOption): void;
|
|
56
57
|
declare function getObjectOutgoingEdgeCount(node: IHeapNode): number;
|
|
@@ -360,6 +361,7 @@ declare const _default: {
|
|
|
360
361
|
printNodeListInTerminal: typeof printNodeListInTerminal;
|
|
361
362
|
printReferencesInTerminal: typeof printReferencesInTerminal;
|
|
362
363
|
printReferrersInTerminal: typeof printReferrersInTerminal;
|
|
364
|
+
printNodeInTerminal: typeof printNodeInTerminal;
|
|
363
365
|
snapshotMapReduce: typeof snapshotMapReduce;
|
|
364
366
|
takeNodeFullHeap: typeof takeNodeFullHeap;
|
|
365
367
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginUtils.d.ts","sourceRoot":"","sources":["../src/PluginUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,aAAa,EACb,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EAER,YAAY,
|
|
1
|
+
{"version":3,"file":"PluginUtils.d.ts","sourceRoot":"","sources":["../src/PluginUtils.ts"],"names":[],"mappings":"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"}
|
package/dist/PluginUtils.js
CHANGED
|
@@ -95,6 +95,40 @@ function filterOutDominators(nodeList) {
|
|
|
95
95
|
}
|
|
96
96
|
return nodeList.filter(node => candidateIdSet.has(node.id));
|
|
97
97
|
}
|
|
98
|
+
// Note: be cautious when using printRef = true, it may cause infinite loop
|
|
99
|
+
function getNodeRecord(node, printRef = false) {
|
|
100
|
+
const refs = node.references.slice(0, MAX_NUM_OF_EDGES_TO_PRINT);
|
|
101
|
+
return {
|
|
102
|
+
id: node.id,
|
|
103
|
+
name: node.name,
|
|
104
|
+
type: node.type,
|
|
105
|
+
selfsize: node.self_size,
|
|
106
|
+
retainedSize: node.retainedSize,
|
|
107
|
+
traceNodeId: node.trace_node_id,
|
|
108
|
+
nodeIndex: node.nodeIndex,
|
|
109
|
+
references: printRef
|
|
110
|
+
? refs.map(edge => getEdgeRecord(edge))
|
|
111
|
+
: refs.map(edge => ({
|
|
112
|
+
name: edge.name_or_index.toString(),
|
|
113
|
+
toNode: edge.toNode.id,
|
|
114
|
+
})),
|
|
115
|
+
referrers: node.referrers.slice(0, MAX_NUM_OF_EDGES_TO_PRINT).map(edge => ({
|
|
116
|
+
name: edge.name_or_index.toString(),
|
|
117
|
+
fromNode: edge.fromNode.id,
|
|
118
|
+
})),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function getEdgeRecord(edge) {
|
|
122
|
+
return {
|
|
123
|
+
nameOrIndex: edge.name_or_index,
|
|
124
|
+
type: edge.type,
|
|
125
|
+
edgeIndex: edge.edgeIndex,
|
|
126
|
+
toNode: getNodeRecord(edge.toNode),
|
|
127
|
+
fromNode: getNodeRecord(edge.fromNode),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Note: be cautious when setting printReferences to true,
|
|
131
|
+
// it may cause infinite loop
|
|
98
132
|
function printNodeListInTerminal(nodeList, options = {}) {
|
|
99
133
|
const dot = chalk_1.default.grey('· ');
|
|
100
134
|
const indent = options.indent || '';
|
|
@@ -102,6 +136,12 @@ function printNodeListInTerminal(nodeList, options = {}) {
|
|
|
102
136
|
if (!options.printAll) {
|
|
103
137
|
nodeList = filterOutDominators(nodeList);
|
|
104
138
|
}
|
|
139
|
+
if (core_1.config.outputFormat === core_1.OutputFormat.Json) {
|
|
140
|
+
const jsonNodes = nodeList.map(node => getNodeRecord(node, printRef));
|
|
141
|
+
core_2.info.writeOutput(JSON.stringify(jsonNodes));
|
|
142
|
+
core_2.info.writeOutput('\n');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
105
145
|
for (const node of nodeList) {
|
|
106
146
|
const nodeInfo = getHeapObjectString(node);
|
|
107
147
|
core_2.info.topLevel(`${indent}${dot}${nodeInfo}`);
|
|
@@ -110,6 +150,11 @@ function printNodeListInTerminal(nodeList, options = {}) {
|
|
|
110
150
|
}
|
|
111
151
|
}
|
|
112
152
|
}
|
|
153
|
+
function printNodeInTerminal(node) {
|
|
154
|
+
const nodeRecord = getNodeRecord(node);
|
|
155
|
+
core_2.info.writeOutput(JSON.stringify(nodeRecord));
|
|
156
|
+
core_2.info.writeOutput('\n');
|
|
157
|
+
}
|
|
113
158
|
function isNumeric(v) {
|
|
114
159
|
if (typeof v === 'number') {
|
|
115
160
|
return true;
|
|
@@ -171,6 +216,11 @@ function getReferenceString(edge) {
|
|
|
171
216
|
return ` --${edgeName}--> ${objectInfo}`;
|
|
172
217
|
}
|
|
173
218
|
function printReferencesInTerminal(edgeList, options = {}) {
|
|
219
|
+
if (core_1.config.outputFormat === core_1.OutputFormat.Json) {
|
|
220
|
+
const jsonEdges = edgeList.map(edge => getEdgeRecord(edge));
|
|
221
|
+
core_2.info.writeOutput(JSON.stringify(jsonEdges));
|
|
222
|
+
core_2.info.writeOutput('\n');
|
|
223
|
+
}
|
|
174
224
|
const dot = chalk_1.default.grey('· ');
|
|
175
225
|
const indent = options.indent || '';
|
|
176
226
|
let n = 0;
|
|
@@ -654,6 +704,7 @@ exports.default = {
|
|
|
654
704
|
printNodeListInTerminal,
|
|
655
705
|
printReferencesInTerminal,
|
|
656
706
|
printReferrersInTerminal,
|
|
707
|
+
printNodeInTerminal,
|
|
657
708
|
snapshotMapReduce,
|
|
658
709
|
takeNodeFullHeap,
|
|
659
710
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { ParsedArgs } from 'minimist';
|
|
11
|
+
import { MemLabConfig } from '@memlab/core';
|
|
12
|
+
import { BaseOption } from '@memlab/core';
|
|
13
|
+
export default class HeapAnalysisOutputOption extends BaseOption {
|
|
14
|
+
getOptionName(): string;
|
|
15
|
+
getDescription(): string;
|
|
16
|
+
getExampleValues(): string[];
|
|
17
|
+
parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
|
|
18
|
+
private static parseOutputFormat;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=HeapAnalysisOutputOption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeapAnalysisOutputOption.d.ts","sourceRoot":"","sources":["../../src/options/HeapAnalysisOutputOption.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,EAAC,YAAY,EAAsB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAC;AAExC,MAAM,CAAC,OAAO,OAAO,wBAAyB,SAAQ,UAAU;IAC9D,aAAa,IAAI,MAAM;IAIvB,cAAc,IAAI,MAAM;IAIxB,gBAAgB,IAAI,MAAM,EAAE;IAItB,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAWjC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
* @format
|
|
9
|
+
* @oncall web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const core_2 = require("@memlab/core");
|
|
23
|
+
class HeapAnalysisOutputOption extends core_2.BaseOption {
|
|
24
|
+
getOptionName() {
|
|
25
|
+
return 'output';
|
|
26
|
+
}
|
|
27
|
+
getDescription() {
|
|
28
|
+
return 'specify output format of the analysis (defaults to text)';
|
|
29
|
+
}
|
|
30
|
+
getExampleValues() {
|
|
31
|
+
return ['text', 'json'];
|
|
32
|
+
}
|
|
33
|
+
parse(config, args) {
|
|
34
|
+
var _a;
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const name = this.getOptionName();
|
|
37
|
+
const format = (_a = `${args[name]}`) !== null && _a !== void 0 ? _a : 'text';
|
|
38
|
+
config.outputFormat = HeapAnalysisOutputOption.parseOutputFormat(format);
|
|
39
|
+
if (config.outputFormat === core_1.OutputFormat.Json) {
|
|
40
|
+
config.isContinuousTest = true;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
static parseOutputFormat(s) {
|
|
45
|
+
switch (s.toLowerCase()) {
|
|
46
|
+
case 'text':
|
|
47
|
+
return core_1.OutputFormat.Text;
|
|
48
|
+
case 'json':
|
|
49
|
+
return core_1.OutputFormat.Json;
|
|
50
|
+
default:
|
|
51
|
+
core_1.utils.haltOrThrow('Invalid output format, valid output: text, json');
|
|
52
|
+
return core_1.OutputFormat.Text;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.default = HeapAnalysisOutputOption;
|
|
@@ -23,5 +23,6 @@ export default class CollectionsHoldingStaleAnalysis extends BaseAnalysis {
|
|
|
23
23
|
process(options: HeapAnalysisOptions): Promise<void>;
|
|
24
24
|
private getCollectionsWithStaleValues;
|
|
25
25
|
private print;
|
|
26
|
+
private printJson;
|
|
26
27
|
}
|
|
27
28
|
//# sourceMappingURL=CollectionsHoldingStaleAnalysis.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionsHoldingStaleAnalysis.d.ts","sourceRoot":"","sources":["../../src/plugins/CollectionsHoldingStaleAnalysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAG/E,OAAO,EAAc,UAAU,
|
|
1
|
+
{"version":3,"file":"CollectionsHoldingStaleAnalysis.d.ts","sourceRoot":"","sources":["../../src/plugins/CollectionsHoldingStaleAnalysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAG/E,OAAO,EAAc,UAAU,EAAuB,MAAM,cAAc,CAAC;AAC3E,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAmD3C,MAAM,CAAC,OAAO,OAAO,+BAAgC,SAAQ,YAAY;IAChE,cAAc,IAAI,MAAM;IAI/B,gBAAgB;IACT,cAAc,IAAI,MAAM;IAI/B,gBAAgB;IAChB,UAAU,IAAI,UAAU,EAAE;IAI1B,gBAAgB;IACH,2BAA2B,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC;IAQjC,OAAO,CAAC,qBAAqB,CAO1B;IAEH,gBAAgB;IACV,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1D,OAAO,CAAC,6BAA6B;IAoBrC,OAAO,CAAC,KAAK;IAiCb,OAAO,CAAC,SAAS;CAelB"}
|
|
@@ -26,6 +26,8 @@ const BaseAnalysis_1 = __importDefault(require("../BaseAnalysis"));
|
|
|
26
26
|
const PluginUtils_1 = __importDefault(require("../PluginUtils"));
|
|
27
27
|
const chalk_1 = __importDefault(require("chalk"));
|
|
28
28
|
const HeapAnalysisSnapshotFileOption_1 = __importDefault(require("../options/HeapAnalysisSnapshotFileOption"));
|
|
29
|
+
const HeapAnalysisOutputOption_1 = __importDefault(require("../options/HeapAnalysisOutputOption"));
|
|
30
|
+
const MAX_COLLECTION_STAT_ITEMS = 20;
|
|
29
31
|
function initCollectionStat(collection) {
|
|
30
32
|
return {
|
|
31
33
|
collection,
|
|
@@ -75,7 +77,7 @@ class CollectionsHoldingStaleAnalysis extends BaseAnalysis_1.default {
|
|
|
75
77
|
}
|
|
76
78
|
/** @internal */
|
|
77
79
|
getOptions() {
|
|
78
|
-
return [new HeapAnalysisSnapshotFileOption_1.default()];
|
|
80
|
+
return [new HeapAnalysisSnapshotFileOption_1.default(), new HeapAnalysisOutputOption_1.default()];
|
|
79
81
|
}
|
|
80
82
|
/** @internal */
|
|
81
83
|
analyzeSnapshotsInDirectory(directory) {
|
|
@@ -90,7 +92,12 @@ class CollectionsHoldingStaleAnalysis extends BaseAnalysis_1.default {
|
|
|
90
92
|
return __awaiter(this, void 0, void 0, function* () {
|
|
91
93
|
const snapshot = yield PluginUtils_1.default.loadHeapSnapshot(options);
|
|
92
94
|
const collectionsStat = this.getCollectionsWithStaleValues(snapshot);
|
|
93
|
-
|
|
95
|
+
if (core_1.config.outputFormat === core_1.OutputFormat.Json) {
|
|
96
|
+
this.printJson(collectionsStat);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.print(collectionsStat);
|
|
100
|
+
}
|
|
94
101
|
});
|
|
95
102
|
}
|
|
96
103
|
getCollectionsWithStaleValues(snapshot) {
|
|
@@ -119,7 +126,7 @@ class CollectionsHoldingStaleAnalysis extends BaseAnalysis_1.default {
|
|
|
119
126
|
core_1.info.topLevel(head('\nCollections holding stale objects:'));
|
|
120
127
|
}
|
|
121
128
|
collections.sort((c1, c2) => c2.staleRetainedSize - c1.staleRetainedSize);
|
|
122
|
-
collections = collections.slice(0,
|
|
129
|
+
collections = collections.slice(0, MAX_COLLECTION_STAT_ITEMS);
|
|
123
130
|
for (const stat of collections) {
|
|
124
131
|
const collection = stat.collection;
|
|
125
132
|
const collectionSize = core_1.utils.getReadableBytes(collection.retainedSize);
|
|
@@ -139,5 +146,19 @@ class CollectionsHoldingStaleAnalysis extends BaseAnalysis_1.default {
|
|
|
139
146
|
core_1.info.topLevel(` ${childrenDesc}`);
|
|
140
147
|
}
|
|
141
148
|
}
|
|
149
|
+
printJson(collections) {
|
|
150
|
+
collections.sort((c1, c2) => c2.staleRetainedSize - c1.staleRetainedSize);
|
|
151
|
+
const output = collections
|
|
152
|
+
.slice(0, MAX_COLLECTION_STAT_ITEMS)
|
|
153
|
+
.map(stat => ({
|
|
154
|
+
id: stat.collection.id,
|
|
155
|
+
size: core_1.utils.getReadableBytes(stat.collection.retainedSize),
|
|
156
|
+
childrenSize: stat.childrenSize,
|
|
157
|
+
staleChildrenSize: stat.staleChildren.length,
|
|
158
|
+
staleChildrenIds: stat.staleChildren.map(node => node.id),
|
|
159
|
+
}));
|
|
160
|
+
core_1.info.writeOutput(JSON.stringify(output));
|
|
161
|
+
core_1.info.writeOutput('\n');
|
|
162
|
+
}
|
|
142
163
|
}
|
|
143
164
|
exports.default = CollectionsHoldingStaleAnalysis;
|
|
@@ -18,6 +18,7 @@ declare class GlobalVariableAnalysis extends BaseAnalysis {
|
|
|
18
18
|
getOptions(): BaseOption[];
|
|
19
19
|
/** @internal */
|
|
20
20
|
process(options: HeapAnalysisOptions): Promise<void>;
|
|
21
|
+
private print;
|
|
21
22
|
/** @internal */
|
|
22
23
|
analyzeSnapshotsInDirectory(directory: string): Promise<AnalyzeSnapshotResult>;
|
|
23
24
|
/** @internal */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectContentAnalysis.d.ts","sourceRoot":"","sources":["../../src/plugins/ObjectContentAnalysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAG/E,OAAO,EAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"ObjectContentAnalysis.d.ts","sourceRoot":"","sources":["../../src/plugins/ObjectContentAnalysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AAG/E,OAAO,EAAC,UAAU,EAAoC,MAAM,cAAc,CAAC;AAG3E,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAI3C,cAAM,sBAAuB,SAAQ,YAAY;IAC/C,cAAc,IAAI,MAAM;IAIxB,gBAAgB;IAChB,cAAc,IAAI,MAAM;IAIxB,gBAAgB;IAChB,UAAU,IAAI,UAAU,EAAE;IAI1B,gBAAgB;IACV,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB1D,OAAO,CAAC,KAAK;IA8Bb,gBAAgB;IACH,2BAA2B,CACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,CAAC;IAQjC,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IAY3B,gBAAgB;IAChB,OAAO,CAAC,sBAAsB;CAW/B;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -27,6 +27,7 @@ const HeapAnalysisNodeIdOption_1 = __importDefault(require("../options/HeapAnaly
|
|
|
27
27
|
const HeapAnalysisSnapshotFileOption_1 = __importDefault(require("../options/HeapAnalysisSnapshotFileOption"));
|
|
28
28
|
const BaseAnalysis_1 = __importDefault(require("../BaseAnalysis"));
|
|
29
29
|
const PluginUtils_1 = __importDefault(require("../PluginUtils"));
|
|
30
|
+
const HeapAnalysisOutputOption_1 = __importDefault(require("../options/HeapAnalysisOutputOption"));
|
|
30
31
|
class GlobalVariableAnalysis extends BaseAnalysis_1.default {
|
|
31
32
|
getCommandName() {
|
|
32
33
|
return 'object';
|
|
@@ -37,7 +38,7 @@ class GlobalVariableAnalysis extends BaseAnalysis_1.default {
|
|
|
37
38
|
}
|
|
38
39
|
/** @internal */
|
|
39
40
|
getOptions() {
|
|
40
|
-
return [new HeapAnalysisSnapshotFileOption_1.default(), new HeapAnalysisNodeIdOption_1.default()];
|
|
41
|
+
return [new HeapAnalysisSnapshotFileOption_1.default(), new HeapAnalysisNodeIdOption_1.default(), new HeapAnalysisOutputOption_1.default()];
|
|
41
42
|
}
|
|
42
43
|
/** @internal */
|
|
43
44
|
process(options) {
|
|
@@ -50,34 +51,41 @@ class GlobalVariableAnalysis extends BaseAnalysis_1.default {
|
|
|
50
51
|
core_1.info.lowLevel(`Specify an object by --node-id`);
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const numReferences = chalk_1.default.grey(`${node.edge_count}`);
|
|
59
|
-
core_1.info.topLevel(` # of references: ${numReferences}`);
|
|
60
|
-
const numReferrers = chalk_1.default.grey(`${node.referrers.length}`);
|
|
61
|
-
core_1.info.topLevel(` # of referrers: ${numReferrers}`);
|
|
62
|
-
const selfSize = chalk_1.default.grey(`${node.self_size}`);
|
|
63
|
-
core_1.info.topLevel(` shallow size: ${selfSize}`);
|
|
64
|
-
const retainedSize = chalk_1.default.grey(`${node.retainedSize}`);
|
|
65
|
-
core_1.info.topLevel(` retained size: ${retainedSize}`);
|
|
66
|
-
const dominatorNode = node.dominatorNode;
|
|
67
|
-
if (dominatorNode) {
|
|
68
|
-
const dominatorNodeId = chalk_1.default.grey(`@${dominatorNode.id}`);
|
|
69
|
-
core_1.info.topLevel(` dominator node: ${dominatorNodeId}`);
|
|
54
|
+
if (core_1.config.outputFormat === core_1.OutputFormat.Json) {
|
|
55
|
+
PluginUtils_1.default.printNodeInTerminal(node);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.print(node, snapshot);
|
|
70
59
|
}
|
|
71
|
-
// print object references
|
|
72
|
-
core_1.info.topLevel('\n' + chalk_1.default.bold('REFERENCES:'));
|
|
73
|
-
let list = this.getObjectProperties(snapshot, node);
|
|
74
|
-
PluginUtils_1.default.printReferencesInTerminal(list);
|
|
75
|
-
core_1.info.topLevel('\n' + chalk_1.default.bold('REFERRERS:'));
|
|
76
|
-
// print object referrers
|
|
77
|
-
list = this.getObjectReferrerEdges(snapshot, node);
|
|
78
|
-
PluginUtils_1.default.printReferrersInTerminal(list);
|
|
79
60
|
});
|
|
80
61
|
}
|
|
62
|
+
print(node, snapshot) {
|
|
63
|
+
const id = chalk_1.default.grey(`@${node.id}`);
|
|
64
|
+
core_1.info.topLevel(`Heap node (${node.type}) ${id}`);
|
|
65
|
+
const name = chalk_1.default.grey(`${node.name}`);
|
|
66
|
+
core_1.info.topLevel(` name: ${name}`);
|
|
67
|
+
const numReferences = chalk_1.default.grey(`${node.edge_count}`);
|
|
68
|
+
core_1.info.topLevel(` # of references: ${numReferences}`);
|
|
69
|
+
const numReferrers = chalk_1.default.grey(`${node.referrers.length}`);
|
|
70
|
+
core_1.info.topLevel(` # of referrers: ${numReferrers}`);
|
|
71
|
+
const selfSize = chalk_1.default.grey(`${node.self_size}`);
|
|
72
|
+
core_1.info.topLevel(` shallow size: ${selfSize}`);
|
|
73
|
+
const retainedSize = chalk_1.default.grey(`${node.retainedSize}`);
|
|
74
|
+
core_1.info.topLevel(` retained size: ${retainedSize}`);
|
|
75
|
+
const dominatorNode = node.dominatorNode;
|
|
76
|
+
if (dominatorNode) {
|
|
77
|
+
const dominatorNodeId = chalk_1.default.grey(`@${dominatorNode.id}`);
|
|
78
|
+
core_1.info.topLevel(` dominator node: ${dominatorNodeId}`);
|
|
79
|
+
}
|
|
80
|
+
// print object references
|
|
81
|
+
core_1.info.topLevel('\n' + chalk_1.default.bold('REFERENCES:'));
|
|
82
|
+
let list = this.getObjectProperties(snapshot, node);
|
|
83
|
+
PluginUtils_1.default.printReferencesInTerminal(list);
|
|
84
|
+
core_1.info.topLevel('\n' + chalk_1.default.bold('REFERRERS:'));
|
|
85
|
+
// print object referrers
|
|
86
|
+
list = this.getObjectReferrerEdges(snapshot, node);
|
|
87
|
+
PluginUtils_1.default.printReferrersInTerminal(list);
|
|
88
|
+
}
|
|
81
89
|
/** @internal */
|
|
82
90
|
analyzeSnapshotsInDirectory(directory) {
|
|
83
91
|
return __awaiter(this, void 0, void 0, function* () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/heap-analysis",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "heap analysis plugins for memlab",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"LICENSE"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@memlab/core": "^1.1.
|
|
24
|
-
"@memlab/e2e": "^1.0.
|
|
23
|
+
"@memlab/core": "^1.1.36",
|
|
24
|
+
"@memlab/e2e": "^1.0.36",
|
|
25
25
|
"ansi": "^0.3.1",
|
|
26
26
|
"babar": "^0.2.0",
|
|
27
27
|
"chalk": "^4.0.0",
|