Commit 91d5ec53 authored by Alexei Filippov's avatar Alexei Filippov Committed by Commit Bot

DevTools: Support CPU profiles in OOPIFs

BUG=832313,820250

Change-Id: I53d730d4ff7e747eb0ccfe9a055738c1fe9858cf
Reviewed-on: https://chromium-review.googlesource.com/1011350
Commit-Queue: Alexei Filippov <alph@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553688}
parent 43d41bed
Test CPU profiles are recorded for OOPIFs.
name: CrRendererMain
url: http://127.0.0.1:8000/devtools/oopif/resources/page.html
has JSSample events: true
name: CrRendererMain
url: http://devtools.oopif.test:8000/devtools/oopif/resources/inner-iframe.html?second
has JSSample events: true
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function() {
TestRunner.addResult(`Test CPU profiles are recorded for OOPIFs.\n`);
await TestRunner.loadModule('performance_test_runner');
await TestRunner.showPanel('timeline');
await PerformanceTestRunner.startTimeline();
await TestRunner.navigatePromise('resources/page.html');
await PerformanceTestRunner.stopTimeline();
for (const track of PerformanceTestRunner.timelineModel().tracks().sort((a, b) => a.url > b.url)) {
if (track.type !== TimelineModel.TimelineModel.TrackType.MainThread)
continue;
TestRunner.addResult(`name: ${track.name}`);
TestRunner.addResult(`url: ${track.url}`);
TestRunner.addResult(`has JSSample events: ${track.events.some(e => e.name === 'JSSample')}\n`);
}
TestRunner.completeTest();
})();
......@@ -1204,13 +1204,10 @@ Multimap.prototype = {
/**
* @param {K} key
* @return {!Set.<!V>}
* @return {!Set<!V>}
*/
get: function(key) {
let result = this._map.get(key);
if (!result)
result = new Set();
return result;
return this._map.get(key) || new Set();
},
/**
......
......@@ -291,6 +291,14 @@ SDK.TracingModel = class {
return this._processByName.get(name);
}
/**
* @param {number} pid
* @return {?SDK.TracingModel.Process}
*/
processById(pid) {
return this._processById.get(pid) || null;
}
/**
* @param {string} processName
* @param {string} threadName
......
......@@ -26,6 +26,10 @@ Timeline.TimelineController = class {
SDK.targetManager.observeModels(SDK.CPUProfilerModel, this);
}
dispose() {
SDK.targetManager.unobserveModels(SDK.CPUProfilerModel, this);
}
/**
* @return {!SDK.Target}
*/
......@@ -224,20 +228,74 @@ Timeline.TimelineController = class {
this._tracingModel.addEvents([cpuProfileEvent]);
}
/**
* @return {?Map<string, number>}
*/
_buildTargetToProcessIdMap() {
const metadataEventTypes = TimelineModel.TimelineModel.DevToolsMetadataEvent;
const metadataEvents = this._tracingModel.devToolsMetadataEvents();
const browserMetaEvent = metadataEvents.find(e => e.name === metadataEventTypes.TracingStartedInBrowser);
if (!browserMetaEvent)
return null;
/** @type {!Multimap<string, string>} */
const pseudoPidToFrames = new Multimap();
/** @type {!Map<string, number>} */
const targetIdToPid = new Map();
const frames = browserMetaEvent.args.data['frames'];
for (const frameInfo of frames)
targetIdToPid.set(frameInfo.frame, frameInfo.processId);
for (const event of metadataEvents) {
const data = event.args.data;
switch (event.name) {
case metadataEventTypes.FrameCommittedInBrowser:
if (data.processId)
targetIdToPid.set(data.frame, data.processId);
else
pseudoPidToFrames.set(data.processPseudoId, data.frame);
break;
case metadataEventTypes.ProcessReadyInBrowser:
for (const frame of pseudoPidToFrames.get(data.processPseudoId) || [])
targetIdToPid.set(frame, data.processId);
break;
}
}
const mainFrame = frames.find(frame => !frame.parent);
const mainRendererProcessId = mainFrame.processId;
const mainProcess = this._tracingModel.processById(mainRendererProcessId);
if (mainProcess)
targetIdToPid.set(SDK.targetManager.mainTarget().id(), mainProcess.id());
return targetIdToPid;
}
_injectCpuProfileEvents() {
if (!this._cpuProfiles)
return;
const metadataEventTypes = TimelineModel.TimelineModel.DevToolsMetadataEvent;
const metadataEvents = this._tracingModel.devToolsMetadataEvents();
const mainMetaEvent =
metadataEvents.filter(event => event.name === metadataEventTypes.TracingStartedInPage).peekLast();
if (!mainMetaEvent)
return;
const pid = mainMetaEvent.thread.process().id();
const mainCpuProfile = this._cpuProfiles.get(this._tracingManager.target().id());
this._injectCpuProfileEvent(pid, mainMetaEvent.thread.id(), mainCpuProfile);
const targetIdToPid = this._buildTargetToProcessIdMap();
if (targetIdToPid) {
for (const [id, profile] of this._cpuProfiles) {
const pid = targetIdToPid.get(id);
if (!pid)
continue;
const process = this._tracingModel.processById(pid);
const thread = process && process.threadByName(TimelineModel.TimelineModel.RendererMainThreadName);
if (thread)
this._injectCpuProfileEvent(pid, thread.id(), profile);
}
} else {
// Legacy backends support.
const mainMetaEvent =
metadataEvents.filter(event => event.name === metadataEventTypes.TracingStartedInPage).peekLast();
if (mainMetaEvent) {
const pid = mainMetaEvent.thread.process().id();
const mainCpuProfile = this._cpuProfiles.get(this._tracingManager.target().id());
this._injectCpuProfileEvent(pid, mainMetaEvent.thread.id(), mainCpuProfile);
}
}
const workerMetaEvents =
metadataEvents.filter(event => event.name === metadataEventTypes.TracingSessionIdForWorker);
......
......@@ -504,6 +504,7 @@ Timeline.TimelinePanel = class extends UI.Panel {
this._setState(Timeline.TimelinePanel.State.StopPending);
this._performanceModel = await this._controller.stopRecording();
this._setUIControlsEnabled(true);
this._controller.dispose();
this._controller = null;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment