Skip to content

Commit ecd6907

Browse files
JacksonGLfacebook-github-bot
authored andcommitted
feat(lens): add a status text widget for displaying memory stats
Summary: This diff adds the number of detected leaks in the MemLens control widgets. Differential Revision: D72519479 fbshipit-source-id: 721eb5d2c75bd4baff1b55c515e0a2f58130eefb
1 parent 430d30d commit ecd6907

File tree

10 files changed

+97
-7
lines changed

10 files changed

+97
-7
lines changed

packages/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"@types/node": "^12.16.3",
4949
"jest": "^29.6.2",
5050
"ts-jest": "^29.1.1",
51-
"typescript": "^4.6.3"
51+
"typescript": "^5.7.2"
5252
},
5353
"repository": {
5454
"type": "git",

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"@types/node": "^12.16.3",
5151
"jest": "^29.6.2",
5252
"ts-jest": "^29.1.1",
53-
"typescript": "^4.6.3"
53+
"typescript": "^5.7.2"
5454
},
5555
"repository": {
5656
"type": "git",

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@types/node": "^12.16.3",
5050
"jest": "^29.6.2",
5151
"ts-jest": "^29.1.1",
52-
"typescript": "^4.6.3"
52+
"typescript": "^5.7.2"
5353
},
5454
"repository": {
5555
"type": "git",

packages/e2e/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"@types/node": "^12.16.3",
4747
"jest": "^29.6.2",
4848
"ts-jest": "^29.1.1",
49-
"typescript": "^4.6.3"
49+
"typescript": "^5.7.2"
5050
},
5151
"repository": {
5252
"type": "git",

packages/heap-analysis/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@types/node": "^12.16.3",
4141
"jest": "^29.6.2",
4242
"ts-jest": "^29.1.1",
43-
"typescript": "^4.6.3"
43+
"typescript": "^5.7.2"
4444
},
4545
"repository": {
4646
"type": "git",

packages/lens/src/core/react-memory-scan.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,15 @@ export default class ReactMemoryScan {
287287
return [...utils.getDOMElements(), ...this.#domObserver.getDOMElements()];
288288
}
289289

290+
#runGC(): void {
291+
if ((window as AnyValue)?.gc != null) {
292+
(window as AnyValue).gc();
293+
}
294+
}
295+
290296
scan(): ScanResult {
291297
const start = Date.now();
298+
this.#runGC();
292299
const weakRefList = this.#elementWeakRefs;
293300
// TODO: associate elements with URL and other metadata
294301
const allElements = this.#getTrackedDOMRefs();

packages/lens/src/visual/components/control-widget.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,21 @@
77
* @format
88
* @oncall memory_lab
99
*/
10+
import {RegisterDataUpdateCallback} from '../dom-element-visualizer-interactive';
1011
import {setVisualizerElement} from '../visual-utils';
12+
import {createStatusText} from './status-text';
1113
import {createToggleButton} from './toggle-button';
1214

1315
export function createControlWidget(
1416
overlayDiv: HTMLDivElement,
1517
hideAllRef: {value: boolean},
18+
registerDataUpdateCallback: RegisterDataUpdateCallback,
1619
): HTMLDivElement {
1720
const controlWidget = document.createElement('div');
1821
controlWidget.style.position = 'fixed';
1922
controlWidget.style.top = '50px';
2023
controlWidget.style.right = '50px';
21-
controlWidget.style.width = '200px';
24+
controlWidget.style.width = '400px';
2225
controlWidget.style.height = '36px';
2326
controlWidget.style.background = 'rgba(0, 0, 0, 0.7)';
2427
controlWidget.style.border = 'none';
@@ -39,6 +42,9 @@ export function createControlWidget(
3942
const toggleButton = createToggleButton(overlayDiv, hideAllRef);
4043
controlWidget.append(toggleButton);
4144

45+
const statusText = createStatusText(registerDataUpdateCallback);
46+
controlWidget.append(toggleButton, statusText);
47+
4248
return controlWidget;
4349
}
4450

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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 memory_lab
9+
*/
10+
import {AnyValue} from '../../core/types';
11+
import {
12+
RegisterDataUpdateCallback,
13+
VisualizerData,
14+
} from '../dom-element-visualizer-interactive';
15+
import {setVisualizerElement} from '../visual-utils';
16+
17+
function formatBytes(bytes: number): string {
18+
if (bytes === 0) return '0 B';
19+
const k = 1024;
20+
const sizes = ['B', 'KB', 'MB', 'GB'];
21+
const i = Math.floor(Math.log(bytes) / Math.log(k));
22+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
23+
}
24+
25+
export function createStatusText(
26+
registerDataUpdateCallback: RegisterDataUpdateCallback,
27+
): HTMLDivElement {
28+
const statusWidget = document.createElement('div');
29+
statusWidget.style.marginLeft = '10px';
30+
statusWidget.style.color = 'white';
31+
statusWidget.style.fontSize = '10px';
32+
statusWidget.style.fontFamily = 'Inter, system-ui, sans-serif';
33+
statusWidget.style.overflow = 'hidden';
34+
statusWidget.style.whiteSpace = 'nowrap';
35+
statusWidget.style.textOverflow = 'ellipsis';
36+
statusWidget.textContent = '';
37+
38+
registerDataUpdateCallback((data: VisualizerData) => {
39+
const performance = (window as AnyValue).performance;
40+
const memory = performance?.memory;
41+
42+
const usedHeap = memory?.usedJSHeapSize ?? 0;
43+
const totalHeap = memory?.totalJSHeapSize ?? 0;
44+
const totalElements = data.totalDOMElementsCount ?? 0;
45+
const detachedElements = data.detachedDOMElementsCount ?? 0;
46+
47+
statusWidget.textContent =
48+
`DOM: ${totalElements} total, ${detachedElements} detached | ` +
49+
`Heap: ${formatBytes(usedHeap)} / ${formatBytes(totalHeap)}`;
50+
});
51+
52+
setVisualizerElement(statusWidget);
53+
return statusWidget;
54+
}

packages/lens/src/visual/dom-element-visualizer-interactive.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,22 @@ type ElementVisualizer = {
2121
visualizerElementRef: WeakRef<Element>;
2222
};
2323

24+
export type VisualizerData = {
25+
detachedDOMElementsCount: number;
26+
totalDOMElementsCount: number;
27+
};
28+
29+
export type DateUpdateCallback = (data: VisualizerData) => void;
30+
export type RegisterDataUpdateCallback = (cb: DateUpdateCallback) => void;
31+
2432
export default class DOMElementVisualizerInteractive extends DOMElementVisualizer {
2533
#elementIdToRectangle: Map<number, ElementVisualizer>;
2634
#visualizationOverlayDiv: HTMLDivElement;
2735
#controlWidget: HTMLDivElement;
2836
#selectedElementId: number | null;
2937
#blockedElementIds: Set<number>;
3038
#hideAllRef: {value: boolean};
39+
#updateDataCallbacks: Array<DateUpdateCallback> = [];
3140

3241
constructor() {
3342
super();
@@ -37,6 +46,9 @@ export default class DOMElementVisualizerInteractive extends DOMElementVisualize
3746
this.#controlWidget = createControlWidget(
3847
this.#visualizationOverlayDiv,
3948
this.#hideAllRef,
49+
cb => {
50+
this.#updateDataCallbacks.push(cb);
51+
},
4052
);
4153
tryToAttachOverlay(this.#controlWidget);
4254
this.#elementIdToRectangle = new Map();
@@ -160,11 +172,22 @@ export default class DOMElementVisualizerInteractive extends DOMElementVisualize
160172
}
161173
}
162174

175+
#updateVisualizerData() {
176+
const data = {
177+
detachedDOMElementsCount: this.#elementIdToRectangle.size,
178+
totalDOMElementsCount: document.querySelectorAll('*').length,
179+
};
180+
for (const cb of this.#updateDataCallbacks) {
181+
cb(data);
182+
}
183+
}
184+
163185
repaint(domElementInfoList: Array<DOMElementInfo>) {
164186
this.#controlWidget.remove();
165187
this.#visualizationOverlayDiv.remove();
166188
this.#cleanup(domElementInfoList);
167189
this.#paint(domElementInfoList);
190+
this.#updateVisualizerData();
168191
tryToAttachOverlay(this.#visualizationOverlayDiv);
169192
tryToAttachOverlay(this.#controlWidget);
170193
}

packages/memlab/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@types/node": "^12.16.3",
5050
"jest": "^29.6.2",
5151
"ts-jest": "^29.1.1",
52-
"typescript": "^4.6.3"
52+
"typescript": "^5.7.2"
5353
},
5454
"scripts": {
5555
"preinstall": "node bin/preinstall",

0 commit comments

Comments
 (0)