chrome-devtools-frontend 1.0.1626437 → 1.0.1626840
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/front_end/core/host/UserMetrics.ts +11 -6
- package/front_end/core/root/ExperimentNames.ts +1 -1
- package/front_end/core/sdk/HeapProfilerModel.ts +1 -11
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -1
- package/front_end/entrypoints/main/MainImpl.ts +4 -29
- package/front_end/generated/InspectorBackendCommands.ts +3 -2
- package/front_end/generated/protocol-mapping.d.ts +5 -0
- package/front_end/generated/protocol-proxy-api.d.ts +4 -0
- package/front_end/generated/protocol.ts +21 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +11 -5
- package/front_end/models/lighthouse/RunTypes.ts +1 -1
- package/front_end/models/workspace/UISourceCode.ts +0 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -3
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +9 -0
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +18 -0
- package/front_end/panels/profiler/profiler-meta.ts +0 -71
- package/front_end/panels/profiler/profiler.ts +0 -2
- package/front_end/panels/sources/ProfilePlugin.ts +12 -65
- package/front_end/panels/sources/UISourceCodeFrame.ts +1 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +4213 -4208
- package/front_end/third_party/lighthouse/locales/en-US.json +26 -8
- package/front_end/third_party/lighthouse/locales/en-XL.json +26 -8
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +7 -1
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +8 -1
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -56
- package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -35
- package/front_end/ui/legacy/components/perf_ui/perf_ui.ts +0 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -1
- package/front_end/panels/profiler/LiveHeapProfileView.ts +0 -405
- package/front_end/panels/profiler/liveHeapProfile.css +0 -22
- package/front_end/ui/legacy/components/perf_ui/LiveHeapProfile.ts +0 -113
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
// Copyright 2019 The Chromium Authors
|
|
2
|
-
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
|
-
|
|
6
|
-
import '../../ui/legacy/legacy.js';
|
|
7
|
-
|
|
8
|
-
import * as Common from '../../core/common/common.js';
|
|
9
|
-
import * as i18n from '../../core/i18n/i18n.js';
|
|
10
|
-
import * as Platform from '../../core/platform/platform.js';
|
|
11
|
-
import * as SDK from '../../core/sdk/sdk.js';
|
|
12
|
-
import type * as Protocol from '../../generated/protocol.js';
|
|
13
|
-
import * as Workspace from '../../models/workspace/workspace.js';
|
|
14
|
-
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
|
|
15
|
-
import * as UI from '../../ui/legacy/legacy.js';
|
|
16
|
-
|
|
17
|
-
import liveHeapProfileStyles from './liveHeapProfile.css.js';
|
|
18
|
-
|
|
19
|
-
const UIStrings = {
|
|
20
|
-
/**
|
|
21
|
-
* @description Text for a heap profile type
|
|
22
|
-
*/
|
|
23
|
-
jsHeap: 'JS Heap',
|
|
24
|
-
/**
|
|
25
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
26
|
-
*/
|
|
27
|
-
allocatedJsHeapSizeCurrentlyIn: 'Allocated JS heap size currently in use',
|
|
28
|
-
/**
|
|
29
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
30
|
-
*/
|
|
31
|
-
vms: 'VMs',
|
|
32
|
-
/**
|
|
33
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
34
|
-
*/
|
|
35
|
-
numberOfVmsSharingTheSameScript: 'Number of VMs sharing the same script source',
|
|
36
|
-
/**
|
|
37
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
38
|
-
*/
|
|
39
|
-
scriptUrl: 'Script URL',
|
|
40
|
-
/**
|
|
41
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
42
|
-
*/
|
|
43
|
-
urlOfTheScriptSource: 'URL of the script source',
|
|
44
|
-
/**
|
|
45
|
-
* @description Data grid name for Heap Profile data grids
|
|
46
|
-
*/
|
|
47
|
-
heapProfile: 'Heap Profile',
|
|
48
|
-
/**
|
|
49
|
-
* @description Text in Live Heap Profile View of a profiler tool
|
|
50
|
-
* @example {1} PH1
|
|
51
|
-
*/
|
|
52
|
-
anonymousScriptS: '(Anonymous Script {PH1})',
|
|
53
|
-
/**
|
|
54
|
-
* @description A unit
|
|
55
|
-
*/
|
|
56
|
-
kb: 'kB',
|
|
57
|
-
} as const;
|
|
58
|
-
const str_ = i18n.i18n.registerUIStrings('panels/profiler/LiveHeapProfileView.ts', UIStrings);
|
|
59
|
-
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
60
|
-
let liveHeapProfileViewInstance: LiveHeapProfileView;
|
|
61
|
-
export class LiveHeapProfileView extends UI.Widget.VBox {
|
|
62
|
-
readonly gridNodeByUrl: Map<string, GridNode>;
|
|
63
|
-
setting: Common.Settings.Setting<boolean>;
|
|
64
|
-
readonly toggleRecordAction: UI.ActionRegistration.Action;
|
|
65
|
-
readonly toggleRecordButton: UI.Toolbar.ToolbarToggle;
|
|
66
|
-
readonly startWithReloadButton: UI.Toolbar.ToolbarButton|undefined;
|
|
67
|
-
readonly dataGrid: DataGrid.SortableDataGrid.SortableDataGrid<GridNode>;
|
|
68
|
-
currentPollId: number;
|
|
69
|
-
|
|
70
|
-
private constructor() {
|
|
71
|
-
super({useShadowDom: true});
|
|
72
|
-
this.gridNodeByUrl = new Map();
|
|
73
|
-
this.registerRequiredCSS(liveHeapProfileStyles);
|
|
74
|
-
|
|
75
|
-
this.setting = Common.Settings.Settings.instance().moduleSetting('memory-live-heap-profile');
|
|
76
|
-
const toolbar = this.contentElement.createChild('devtools-toolbar', 'live-heap-profile-toolbar');
|
|
77
|
-
this.toggleRecordAction =
|
|
78
|
-
UI.ActionRegistry.ActionRegistry.instance().getAction('live-heap-profile.toggle-recording');
|
|
79
|
-
this.toggleRecordButton =
|
|
80
|
-
(UI.Toolbar.Toolbar.createActionButton(this.toggleRecordAction) as UI.Toolbar.ToolbarToggle);
|
|
81
|
-
this.toggleRecordButton.setToggled(this.setting.get());
|
|
82
|
-
toolbar.appendToolbarItem(this.toggleRecordButton);
|
|
83
|
-
|
|
84
|
-
const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
85
|
-
if (mainTarget?.model(SDK.ResourceTreeModel.ResourceTreeModel)) {
|
|
86
|
-
const startWithReloadAction =
|
|
87
|
-
UI.ActionRegistry.ActionRegistry.instance().getAction('live-heap-profile.start-with-reload');
|
|
88
|
-
this.startWithReloadButton = UI.Toolbar.Toolbar.createActionButton(startWithReloadAction);
|
|
89
|
-
toolbar.appendToolbarItem(this.startWithReloadButton);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
this.dataGrid = this.createDataGrid();
|
|
93
|
-
this.dataGrid.asWidget().show(this.contentElement);
|
|
94
|
-
|
|
95
|
-
this.currentPollId = 0;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
static instance(): LiveHeapProfileView {
|
|
99
|
-
if (!liveHeapProfileViewInstance) {
|
|
100
|
-
liveHeapProfileViewInstance = new LiveHeapProfileView();
|
|
101
|
-
}
|
|
102
|
-
return liveHeapProfileViewInstance;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
createDataGrid(): DataGrid.SortableDataGrid.SortableDataGrid<GridNode> {
|
|
106
|
-
const defaultColumnConfig = {
|
|
107
|
-
title: Common.UIString.LocalizedEmptyString,
|
|
108
|
-
fixedWidth: true,
|
|
109
|
-
sortable: true,
|
|
110
|
-
align: DataGrid.DataGrid.Align.RIGHT,
|
|
111
|
-
sort: DataGrid.DataGrid.Order.Descending,
|
|
112
|
-
};
|
|
113
|
-
const columns: Array<{tooltip: Common.UIString.LocalizedString}&DataGrid.DataGrid.ColumnDescriptor> = [
|
|
114
|
-
{
|
|
115
|
-
...defaultColumnConfig,
|
|
116
|
-
id: 'size',
|
|
117
|
-
title: i18nString(UIStrings.jsHeap),
|
|
118
|
-
width: '72px',
|
|
119
|
-
fixedWidth: true,
|
|
120
|
-
sortable: true,
|
|
121
|
-
align: DataGrid.DataGrid.Align.RIGHT,
|
|
122
|
-
sort: DataGrid.DataGrid.Order.Descending,
|
|
123
|
-
tooltip: i18nString(UIStrings.allocatedJsHeapSizeCurrentlyIn),
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
...defaultColumnConfig,
|
|
127
|
-
id: 'isolates',
|
|
128
|
-
title: i18nString(UIStrings.vms),
|
|
129
|
-
width: '40px',
|
|
130
|
-
fixedWidth: true,
|
|
131
|
-
align: DataGrid.DataGrid.Align.RIGHT,
|
|
132
|
-
tooltip: i18nString(UIStrings.numberOfVmsSharingTheSameScript),
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
...defaultColumnConfig,
|
|
136
|
-
id: 'url',
|
|
137
|
-
title: i18nString(UIStrings.scriptUrl),
|
|
138
|
-
fixedWidth: false,
|
|
139
|
-
sortable: true,
|
|
140
|
-
tooltip: i18nString(UIStrings.urlOfTheScriptSource),
|
|
141
|
-
},
|
|
142
|
-
];
|
|
143
|
-
const dataGrid = new DataGrid.SortableDataGrid.SortableDataGrid({
|
|
144
|
-
displayName: i18nString(UIStrings.heapProfile),
|
|
145
|
-
columns,
|
|
146
|
-
});
|
|
147
|
-
dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.LAST);
|
|
148
|
-
dataGrid.element.classList.add('flex-auto');
|
|
149
|
-
dataGrid.element.addEventListener('keydown', this.onKeyDown.bind(this), false);
|
|
150
|
-
dataGrid.addEventListener(DataGrid.DataGrid.Events.OPENED_NODE, this.revealSourceForSelectedNode, this);
|
|
151
|
-
dataGrid.addEventListener(DataGrid.DataGrid.Events.SORTING_CHANGED, this.sortingChanged, this);
|
|
152
|
-
for (const info of columns) {
|
|
153
|
-
const headerCell = dataGrid.headerTableHeader(info.id);
|
|
154
|
-
if (headerCell) {
|
|
155
|
-
headerCell.setAttribute('title', info.tooltip);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return dataGrid;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
override wasShown(): void {
|
|
162
|
-
super.wasShown();
|
|
163
|
-
void this.poll();
|
|
164
|
-
this.setting.addChangeListener(this.settingChanged, this);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
override willHide(): void {
|
|
168
|
-
super.willHide();
|
|
169
|
-
++this.currentPollId;
|
|
170
|
-
this.setting.removeChangeListener(this.settingChanged, this);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
settingChanged(value: Common.EventTarget.EventTargetEvent<boolean>): void {
|
|
174
|
-
this.toggleRecordButton.setToggled(value.data);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async poll(): Promise<void> {
|
|
178
|
-
const pollId = this.currentPollId;
|
|
179
|
-
do {
|
|
180
|
-
const isolates = Array.from(SDK.IsolateManager.IsolateManager.instance().isolates());
|
|
181
|
-
const profiles = await Promise.all(isolates.map(isolate => {
|
|
182
|
-
const heapProfilerModel = isolate.heapProfilerModel();
|
|
183
|
-
if (!heapProfilerModel) {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return heapProfilerModel.getSamplingProfile();
|
|
188
|
-
}));
|
|
189
|
-
if (this.currentPollId !== pollId) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
this.update(isolates, profiles);
|
|
193
|
-
await new Promise(r => window.setTimeout(r, 3000));
|
|
194
|
-
} while (this.currentPollId === pollId);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
update(
|
|
198
|
-
isolates: SDK.IsolateManager.Isolate[] = [],
|
|
199
|
-
profiles: Array<Protocol.HeapProfiler.SamplingHeapProfile|null> = []): void {
|
|
200
|
-
const dataByUrl = new Map<string, {
|
|
201
|
-
size: number,
|
|
202
|
-
isolates: Set<SDK.IsolateManager.Isolate>,
|
|
203
|
-
}>();
|
|
204
|
-
profiles.forEach((profile, index) => {
|
|
205
|
-
if (profile) {
|
|
206
|
-
processNodeTree(isolates[index], '', profile.head);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
const rootNode = this.dataGrid.rootNode();
|
|
211
|
-
const existingNodes = new Set<GridNode>();
|
|
212
|
-
for (const pair of dataByUrl) {
|
|
213
|
-
const url = (pair[0]);
|
|
214
|
-
const size = (pair[1].size);
|
|
215
|
-
const isolateCount = (pair[1].isolates.size);
|
|
216
|
-
if (!url) {
|
|
217
|
-
console.info(`Node with empty URL: ${size} bytes`); // eslint-disable-line no-console
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
let node = this.gridNodeByUrl.get(url);
|
|
221
|
-
if (node) {
|
|
222
|
-
node.updateNode(size, isolateCount);
|
|
223
|
-
} else {
|
|
224
|
-
node = new GridNode(url, size, isolateCount);
|
|
225
|
-
this.gridNodeByUrl.set(url, node);
|
|
226
|
-
rootNode.appendChild(node);
|
|
227
|
-
}
|
|
228
|
-
existingNodes.add(node);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
for (const node of rootNode.children.slice()) {
|
|
232
|
-
const gridNode = node as GridNode;
|
|
233
|
-
if (!existingNodes.has(gridNode)) {
|
|
234
|
-
gridNode.remove();
|
|
235
|
-
}
|
|
236
|
-
this.gridNodeByUrl.delete(gridNode.url);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
this.sortingChanged();
|
|
240
|
-
|
|
241
|
-
function processNodeTree(
|
|
242
|
-
isolate: SDK.IsolateManager.Isolate, parentUrl: string,
|
|
243
|
-
node: Protocol.HeapProfiler.SamplingHeapProfileNode): void {
|
|
244
|
-
const url = node.callFrame.url || parentUrl || systemNodeName(node) || anonymousScriptName(node);
|
|
245
|
-
node.children.forEach(processNodeTree.bind(null, isolate, url));
|
|
246
|
-
if (!node.selfSize) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
let data = dataByUrl.get(url);
|
|
250
|
-
if (!data) {
|
|
251
|
-
data = {size: 0, isolates: new Set()};
|
|
252
|
-
dataByUrl.set(url, data);
|
|
253
|
-
}
|
|
254
|
-
data.size += node.selfSize;
|
|
255
|
-
data.isolates.add(isolate);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function systemNodeName(node: Protocol.HeapProfiler.SamplingHeapProfileNode): string {
|
|
259
|
-
const name = node.callFrame.functionName;
|
|
260
|
-
return name.startsWith('(') && name !== '(root)' ? name : '';
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function anonymousScriptName(node: Protocol.HeapProfiler.SamplingHeapProfileNode): string {
|
|
264
|
-
return Number(node.callFrame.scriptId) ? i18nString(UIStrings.anonymousScriptS, {PH1: node.callFrame.scriptId}) :
|
|
265
|
-
'';
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
onKeyDown(event: KeyboardEvent): void {
|
|
270
|
-
if (!(event.key === 'Enter')) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
event.consume(true);
|
|
274
|
-
this.revealSourceForSelectedNode();
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
revealSourceForSelectedNode(): void {
|
|
278
|
-
const node = (this.dataGrid.selectedNode as GridNode);
|
|
279
|
-
if (!node?.url) {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const sourceCode =
|
|
283
|
-
Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(node.url as Platform.DevToolsPath.UrlString);
|
|
284
|
-
if (sourceCode) {
|
|
285
|
-
void Common.Revealer.reveal(sourceCode);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
sortingChanged(): void {
|
|
290
|
-
const columnId = this.dataGrid.sortColumnId();
|
|
291
|
-
if (!columnId) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function sortByUrl(
|
|
296
|
-
a: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>,
|
|
297
|
-
b: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>): number {
|
|
298
|
-
return (b as GridNode).url.localeCompare((a as GridNode).url);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function sortBySize(
|
|
302
|
-
a: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>,
|
|
303
|
-
b: DataGrid.SortableDataGrid.SortableDataGridNode<GridNode>): number {
|
|
304
|
-
return (b as GridNode).size - (a as GridNode).size;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const sortFunction = columnId === 'url' ? sortByUrl : sortBySize;
|
|
308
|
-
this.dataGrid.sortNodes(sortFunction, this.dataGrid.isSortOrderAscending());
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
toggleRecording(): void {
|
|
312
|
-
const enable = !this.setting.get();
|
|
313
|
-
if (enable) {
|
|
314
|
-
this.startRecording(false);
|
|
315
|
-
} else {
|
|
316
|
-
void this.stopRecording();
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
startRecording(reload?: boolean): void {
|
|
321
|
-
this.setting.set(true);
|
|
322
|
-
if (!reload) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
326
|
-
if (!mainTarget) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
const resourceTreeModel = (mainTarget.model(SDK.ResourceTreeModel.ResourceTreeModel));
|
|
330
|
-
if (resourceTreeModel) {
|
|
331
|
-
resourceTreeModel.reloadPage();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async stopRecording(): Promise<void> {
|
|
336
|
-
this.setting.set(false);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode<unknown> {
|
|
341
|
-
url: string;
|
|
342
|
-
size: number;
|
|
343
|
-
isolateCount: number;
|
|
344
|
-
|
|
345
|
-
constructor(url: string, size: number, isolateCount: number) {
|
|
346
|
-
super();
|
|
347
|
-
this.url = url;
|
|
348
|
-
this.size = size;
|
|
349
|
-
this.isolateCount = isolateCount;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
updateNode(size: number, isolateCount: number): void {
|
|
353
|
-
if (this.size === size && this.isolateCount === isolateCount) {
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
this.size = size;
|
|
357
|
-
this.isolateCount = isolateCount;
|
|
358
|
-
this.refresh();
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
override createCell(columnId: string): HTMLElement {
|
|
362
|
-
const cell = this.createTD(columnId);
|
|
363
|
-
switch (columnId) {
|
|
364
|
-
case 'url':
|
|
365
|
-
cell.textContent = this.url;
|
|
366
|
-
break;
|
|
367
|
-
case 'size':
|
|
368
|
-
cell.textContent = Platform.NumberUtilities.withThousandsSeparator(Math.round(this.size / 1e3));
|
|
369
|
-
cell.createChild('span', 'size-units').textContent = i18nString(UIStrings.kb);
|
|
370
|
-
break;
|
|
371
|
-
case 'isolates':
|
|
372
|
-
cell.textContent = `${this.isolateCount}`;
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
return cell;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
380
|
-
handleAction(_context: UI.Context.Context, actionId: string): boolean {
|
|
381
|
-
void (async () => {
|
|
382
|
-
const profileViewId = 'live-heap-profile';
|
|
383
|
-
await UI.ViewManager.ViewManager.instance().showView(profileViewId);
|
|
384
|
-
const view = UI.ViewManager.ViewManager.instance().view(profileViewId);
|
|
385
|
-
if (view) {
|
|
386
|
-
const widget = await view.widget();
|
|
387
|
-
this.innerHandleAction((widget as LiveHeapProfileView), actionId);
|
|
388
|
-
}
|
|
389
|
-
})();
|
|
390
|
-
return true;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
innerHandleAction(profilerView: LiveHeapProfileView, actionId: string): void {
|
|
394
|
-
switch (actionId) {
|
|
395
|
-
case 'live-heap-profile.toggle-recording':
|
|
396
|
-
profilerView.toggleRecording();
|
|
397
|
-
break;
|
|
398
|
-
case 'live-heap-profile.start-with-reload':
|
|
399
|
-
profilerView.startRecording(true);
|
|
400
|
-
break;
|
|
401
|
-
default:
|
|
402
|
-
console.assert(false, `Unknown action: ${actionId}`);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2019 The Chromium Authors
|
|
3
|
-
* Use of this source code is governed by a BSD-style license that can be
|
|
4
|
-
* found in the LICENSE file.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
.data-grid {
|
|
8
|
-
border: none;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.data-grid td .size-units {
|
|
12
|
-
margin-left: 4px;
|
|
13
|
-
font-size: 75%;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.data-grid tr:not(.selected) td .size-units {
|
|
17
|
-
color: var(--sys-color-token-subtle);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
devtools-toolbar {
|
|
21
|
-
border-bottom: 1px solid var(--sys-color-divider);
|
|
22
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// Copyright 2019 The Chromium Authors
|
|
2
|
-
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
-
// found in the LICENSE file.
|
|
4
|
-
|
|
5
|
-
import * as Common from '../../../../core/common/common.js';
|
|
6
|
-
import * as Host from '../../../../core/host/host.js';
|
|
7
|
-
import * as SDK from '../../../../core/sdk/sdk.js';
|
|
8
|
-
import type * as Protocol from '../../../../generated/protocol.js';
|
|
9
|
-
|
|
10
|
-
import {Memory} from './LineLevelProfile.js';
|
|
11
|
-
|
|
12
|
-
let liveHeapProfileInstance: LiveHeapProfile;
|
|
13
|
-
export class LiveHeapProfile implements Common.Runnable.Runnable,
|
|
14
|
-
SDK.TargetManager.SDKModelObserver<SDK.HeapProfilerModel.HeapProfilerModel> {
|
|
15
|
-
private running: boolean;
|
|
16
|
-
private sessionId: number;
|
|
17
|
-
private loadEventCallback: (arg0?: () => void|null) => void;
|
|
18
|
-
private readonly setting: Common.Settings.Setting<boolean>;
|
|
19
|
-
|
|
20
|
-
private constructor() {
|
|
21
|
-
this.running = false;
|
|
22
|
-
this.sessionId = 0;
|
|
23
|
-
this.loadEventCallback = () => {};
|
|
24
|
-
this.setting = Common.Settings.Settings.instance().moduleSetting('memory-live-heap-profile');
|
|
25
|
-
this.setting.addChangeListener(event => event.data ? this.startProfiling() : this.stopProfiling());
|
|
26
|
-
if (this.setting.get()) {
|
|
27
|
-
void this.startProfiling();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
static instance(opts: {forceNew: boolean|null} = {forceNew: null}): LiveHeapProfile {
|
|
32
|
-
const {forceNew} = opts;
|
|
33
|
-
if (!liveHeapProfileInstance || forceNew) {
|
|
34
|
-
liveHeapProfileInstance = new LiveHeapProfile();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return liveHeapProfileInstance;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async run(): Promise<void> {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
modelAdded(model: SDK.HeapProfilerModel.HeapProfilerModel): void {
|
|
45
|
-
void model.startSampling(1e4);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
modelRemoved(_model: SDK.HeapProfilerModel.HeapProfilerModel): void {
|
|
49
|
-
// Cannot do much when the model has already been removed.
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private async startProfiling(): Promise<void> {
|
|
53
|
-
if (this.running) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
this.running = true;
|
|
57
|
-
const sessionId = this.sessionId;
|
|
58
|
-
SDK.TargetManager.TargetManager.instance().observeModels(SDK.HeapProfilerModel.HeapProfilerModel, this);
|
|
59
|
-
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
60
|
-
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);
|
|
61
|
-
|
|
62
|
-
do {
|
|
63
|
-
const models = SDK.TargetManager.TargetManager.instance().models(SDK.HeapProfilerModel.HeapProfilerModel);
|
|
64
|
-
const profiles = await Promise.all(models.map(model => model.getSamplingProfile()));
|
|
65
|
-
if (sessionId !== this.sessionId) {
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const profilesAndTargets: Array<{
|
|
70
|
-
profile: Protocol.HeapProfiler.SamplingHeapProfile,
|
|
71
|
-
target: SDK.Target.Target,
|
|
72
|
-
}> = [];
|
|
73
|
-
for (let i = 0; i < profiles.length; ++i) {
|
|
74
|
-
const profile = profiles[i];
|
|
75
|
-
if (!profile) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const target = models[i].target();
|
|
80
|
-
profilesAndTargets.push({profile, target});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
Memory.instance().initialize(profilesAndTargets);
|
|
84
|
-
|
|
85
|
-
await Promise.race([
|
|
86
|
-
new Promise(r => window.setTimeout(r, Host.InspectorFrontendHost.isUnderTest() ? 10 : 5000)),
|
|
87
|
-
new Promise(r => {
|
|
88
|
-
this.loadEventCallback = r;
|
|
89
|
-
}),
|
|
90
|
-
]);
|
|
91
|
-
} while (sessionId === this.sessionId);
|
|
92
|
-
|
|
93
|
-
SDK.TargetManager.TargetManager.instance().unobserveModels(SDK.HeapProfilerModel.HeapProfilerModel, this);
|
|
94
|
-
SDK.TargetManager.TargetManager.instance().removeModelListener(
|
|
95
|
-
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);
|
|
96
|
-
for (const model of SDK.TargetManager.TargetManager.instance().models(SDK.HeapProfilerModel.HeapProfilerModel)) {
|
|
97
|
-
void model.stopSampling();
|
|
98
|
-
}
|
|
99
|
-
Memory.instance().reset();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private stopProfiling(): void {
|
|
103
|
-
if (!this.running) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
this.running = false;
|
|
107
|
-
this.sessionId++;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private loadEventFired(): void {
|
|
111
|
-
this.loadEventCallback();
|
|
112
|
-
}
|
|
113
|
-
}
|