| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @implements {SDK.TargetManager.Observer} | 6 * @implements {SDK.SDKModelObserver<!SDK.CPUProfilerModel>} |
| 7 * @implements {SDK.TracingManagerClient} | 7 * @implements {SDK.TracingManagerClient} |
| 8 * @unrestricted | 8 * @unrestricted |
| 9 */ | 9 */ |
| 10 Timeline.TimelineController = class { | 10 Timeline.TimelineController = class { |
| 11 /** | 11 /** |
| 12 * @param {!SDK.Target} target | 12 * @param {!SDK.Target} target |
| 13 * @param {!Timeline.PerformanceModel} performanceModel | 13 * @param {!Timeline.PerformanceModel} performanceModel |
| 14 * @param {!Timeline.TimelineController.Client} client | 14 * @param {!Timeline.TimelineController.Client} client |
| 15 */ | 15 */ |
| 16 constructor(target, performanceModel, client) { | 16 constructor(target, performanceModel, client) { |
| 17 this._target = target; | 17 this._target = target; |
| 18 this._performanceModel = performanceModel; | 18 this._performanceModel = performanceModel; |
| 19 this._client = client; | 19 this._client = client; |
| 20 | 20 |
| 21 this._tracingModelBackingStorage = new Bindings.TempFileBackingStorage('trac
ing'); | 21 this._tracingModelBackingStorage = new Bindings.TempFileBackingStorage('trac
ing'); |
| 22 this._tracingModel = new SDK.TracingModel(this._tracingModelBackingStorage); | 22 this._tracingModel = new SDK.TracingModel(this._tracingModelBackingStorage); |
| 23 | 23 |
| 24 this._performanceModel.setMainTarget(target); | 24 this._performanceModel.setMainTarget(target); |
| 25 | 25 |
| 26 /** @type {!Array<!SDK.Target>} */ | |
| 27 this._targets = []; | |
| 28 /** @type {!Array<!Timeline.ExtensionTracingSession>} */ | 26 /** @type {!Array<!Timeline.ExtensionTracingSession>} */ |
| 29 this._extensionSessions = []; | 27 this._extensionSessions = []; |
| 30 SDK.targetManager.observeTargets(this); | 28 SDK.targetManager.observeModels(SDK.CPUProfilerModel, this); |
| 31 } | 29 } |
| 32 | 30 |
| 33 /** | 31 /** |
| 34 * @param {!Timeline.TimelineController.RecordingOptions} options | 32 * @param {!Timeline.TimelineController.RecordingOptions} options |
| 35 * @param {!Array<!Extensions.ExtensionTraceProvider>} providers | 33 * @param {!Array<!Extensions.ExtensionTraceProvider>} providers |
| 36 */ | 34 */ |
| 37 startRecording(options, providers) { | 35 startRecording(options, providers) { |
| 38 this._extensionTraceProviders = Extensions.extensionServer.traceProviders().
slice(); | 36 this._extensionTraceProviders = Extensions.extensionServer.traceProviders().
slice(); |
| 39 | 37 |
| 40 /** | 38 /** |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 this._extensionSessions = | 70 this._extensionSessions = |
| 73 providers.map(provider => new Timeline.ExtensionTracingSession(provider,
this._performanceModel)); | 71 providers.map(provider => new Timeline.ExtensionTracingSession(provider,
this._performanceModel)); |
| 74 this._extensionSessions.forEach(session => session.start()); | 72 this._extensionSessions.forEach(session => session.start()); |
| 75 this._startRecordingWithCategories(categoriesArray.join(','), options.enable
JSSampling); | 73 this._startRecordingWithCategories(categoriesArray.join(','), options.enable
JSSampling); |
| 76 this._performanceModel.setRecordStartTime(Date.now()); | 74 this._performanceModel.setRecordStartTime(Date.now()); |
| 77 } | 75 } |
| 78 | 76 |
| 79 stopRecording() { | 77 stopRecording() { |
| 80 var tracingStoppedPromises = []; | 78 var tracingStoppedPromises = []; |
| 81 tracingStoppedPromises.push(new Promise(resolve => this._tracingCompleteCall
back = resolve)); | 79 tracingStoppedPromises.push(new Promise(resolve => this._tracingCompleteCall
back = resolve)); |
| 82 tracingStoppedPromises.push(this._stopProfilingOnAllTargets()); | 80 tracingStoppedPromises.push(this._stopProfilingOnAllModels()); |
| 83 this._target.tracingManager.stop(); | 81 this._target.tracingManager.stop(); |
| 84 tracingStoppedPromises.push(SDK.targetManager.resumeAllTargets()); | 82 tracingStoppedPromises.push(SDK.targetManager.resumeAllTargets()); |
| 85 | 83 |
| 86 this._client.loadingStarted(); | 84 this._client.loadingStarted(); |
| 87 | 85 |
| 88 var extensionCompletionPromises = this._extensionSessions.map(session => ses
sion.stop()); | 86 var extensionCompletionPromises = this._extensionSessions.map(session => ses
sion.stop()); |
| 89 if (extensionCompletionPromises.length) { | 87 if (extensionCompletionPromises.length) { |
| 90 var timerId; | 88 var timerId; |
| 91 var timeoutPromise = new Promise(fulfill => timerId = setTimeout(fulfill,
5000)); | 89 var timeoutPromise = new Promise(fulfill => timerId = setTimeout(fulfill,
5000)); |
| 92 tracingStoppedPromises.push( | 90 tracingStoppedPromises.push( |
| 93 Promise.race([Promise.all(extensionCompletionPromises).then(() => clea
rTimeout(timerId)), timeoutPromise])); | 91 Promise.race([Promise.all(extensionCompletionPromises).then(() => clea
rTimeout(timerId)), timeoutPromise])); |
| 94 } | 92 } |
| 95 Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished()); | 93 Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished()); |
| 96 } | 94 } |
| 97 | 95 |
| 98 /** | 96 /** |
| 99 * @override | 97 * @override |
| 100 * @param {!SDK.Target} target | 98 * @param {!SDK.CPUProfilerModel} cpuProfilerModel |
| 101 */ | 99 */ |
| 102 targetAdded(target) { | 100 modelAdded(cpuProfilerModel) { |
| 103 this._targets.push(target); | |
| 104 if (this._profiling) | 101 if (this._profiling) |
| 105 this._startProfilingOnTarget(target); | 102 cpuProfilerModel.startRecording(); |
| 106 } | 103 } |
| 107 | 104 |
| 108 /** | 105 /** |
| 109 * @override | 106 * @override |
| 110 * @param {!SDK.Target} target | 107 * @param {!SDK.CPUProfilerModel} cpuProfilerModel |
| 111 */ | 108 */ |
| 112 targetRemoved(target) { | 109 modelRemoved(cpuProfilerModel) { |
| 113 this._targets.remove(target, true); | |
| 114 // FIXME: We'd like to stop profiling on the target and retrieve a profile | 110 // FIXME: We'd like to stop profiling on the target and retrieve a profile |
| 115 // but it's too late. Backend connection is closed. | 111 // but it's too late. Backend connection is closed. |
| 116 } | 112 } |
| 117 | 113 |
| 118 /** | 114 /** |
| 119 * @param {!SDK.Target} target | |
| 120 * @return {!Promise} | 115 * @return {!Promise} |
| 121 */ | 116 */ |
| 122 _startProfilingOnTarget(target) { | 117 _startProfilingOnAllModels() { |
| 123 return target.hasJSCapability() ? target.profilerAgent().start() : Promise.r
esolve(); | |
| 124 } | |
| 125 | |
| 126 /** | |
| 127 * @return {!Promise} | |
| 128 */ | |
| 129 _startProfilingOnAllTargets() { | |
| 130 var intervalUs = Common.moduleSetting('highResolutionCpuProfiling').get() ?
100 : 1000; | |
| 131 this._target.profilerAgent().setSamplingInterval(intervalUs); | |
| 132 this._profiling = true; | 118 this._profiling = true; |
| 133 return Promise.all(this._targets.map(this._startProfilingOnTarget)); | 119 var models = SDK.targetManager.models(SDK.CPUProfilerModel); |
| 134 } | 120 return Promise.all(models.map(model => model.startRecording())); |
| 135 | |
| 136 /** | |
| 137 * @param {!SDK.Target} target | |
| 138 * @return {!Promise} | |
| 139 */ | |
| 140 _stopProfilingOnTarget(target) { | |
| 141 return target.hasJSCapability() ? target.profilerAgent().stop(this._addCpuPr
ofile.bind(this, target.id())) : | |
| 142 Promise.resolve(); | |
| 143 } | 121 } |
| 144 | 122 |
| 145 /** | 123 /** |
| 146 * @param {string} targetId | 124 * @param {string} targetId |
| 147 * @param {?Protocol.Error} error | |
| 148 * @param {?Protocol.Profiler.Profile} cpuProfile | 125 * @param {?Protocol.Profiler.Profile} cpuProfile |
| 149 */ | 126 */ |
| 150 _addCpuProfile(targetId, error, cpuProfile) { | 127 _addCpuProfile(targetId, cpuProfile) { |
| 151 if (!cpuProfile) { | 128 if (!cpuProfile) { |
| 152 Common.console.warn(Common.UIString('CPU profile for a target is not avail
able. %s', error || '')); | 129 Common.console.warn(Common.UIString('CPU profile for a target is not avail
able.')); |
| 153 return; | 130 return; |
| 154 } | 131 } |
| 155 if (!this._cpuProfiles) | 132 if (!this._cpuProfiles) |
| 156 this._cpuProfiles = new Map(); | 133 this._cpuProfiles = new Map(); |
| 157 this._cpuProfiles.set(targetId, cpuProfile); | 134 this._cpuProfiles.set(targetId, cpuProfile); |
| 158 } | 135 } |
| 159 | 136 |
| 160 /** | 137 /** |
| 161 * @return {!Promise} | 138 * @return {!Promise} |
| 162 */ | 139 */ |
| 163 _stopProfilingOnAllTargets() { | 140 _stopProfilingOnAllModels() { |
| 164 var targets = this._profiling ? this._targets : []; | 141 var models = this._profiling ? SDK.targetManager.models(SDK.CPUProfilerModel
) : []; |
| 165 this._profiling = false; | 142 this._profiling = false; |
| 166 return Promise.all(targets.map(this._stopProfilingOnTarget, this)); | 143 var promises = []; |
| 144 for (var model of models) { |
| 145 var targetId = model.target().id(); |
| 146 var modelPromise = model.stopRecording().then(this._addCpuProfile.bind(thi
s, targetId)); |
| 147 promises.push(modelPromise); |
| 148 } |
| 149 return Promise.all(promises); |
| 167 } | 150 } |
| 168 | 151 |
| 169 /** | 152 /** |
| 170 * @param {string} categories | 153 * @param {string} categories |
| 171 * @param {boolean=} enableJSSampling | 154 * @param {boolean=} enableJSSampling |
| 172 * @param {function(?string)=} callback | 155 * @param {function(?string)=} callback |
| 173 */ | 156 */ |
| 174 _startRecordingWithCategories(categories, enableJSSampling, callback) { | 157 _startRecordingWithCategories(categories, enableJSSampling, callback) { |
| 175 SDK.targetManager.suspendAllTargets(); | 158 SDK.targetManager.suspendAllTargets(); |
| 176 var profilingStartedPromise = enableJSSampling && !Runtime.experiments.isEna
bled('timelineTracingJSProfile') ? | 159 var profilingStartedPromise = enableJSSampling && !Runtime.experiments.isEna
bled('timelineTracingJSProfile') ? |
| 177 this._startProfilingOnAllTargets() : | 160 this._startProfilingOnAllModels() : |
| 178 Promise.resolve(); | 161 Promise.resolve(); |
| 179 var samplingFrequencyHz = Common.moduleSetting('highResolutionCpuProfiling')
.get() ? 10000 : 1000; | 162 var samplingFrequencyHz = Common.moduleSetting('highResolutionCpuProfiling')
.get() ? 10000 : 1000; |
| 180 var options = 'sampling-frequency=' + samplingFrequencyHz; | 163 var options = 'sampling-frequency=' + samplingFrequencyHz; |
| 181 var target = this._target; | 164 var target = this._target; |
| 182 var tracingManager = target.tracingManager; | 165 var tracingManager = target.tracingManager; |
| 183 SDK.targetManager.suspendReload(target); | 166 SDK.targetManager.suspendReload(target); |
| 184 profilingStartedPromise.then(tracingManager.start.bind(tracingManager, this,
categories, options, onTraceStarted)); | 167 profilingStartedPromise.then(tracingManager.start.bind(tracingManager, this,
categories, options, onTraceStarted)); |
| 185 /** | 168 /** |
| 186 * @param {?string} error | 169 * @param {?string} error |
| 187 */ | 170 */ |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 }; | 290 }; |
| 308 | 291 |
| 309 /** | 292 /** |
| 310 * @typedef {!{ | 293 * @typedef {!{ |
| 311 * enableJSSampling: (boolean|undefined), | 294 * enableJSSampling: (boolean|undefined), |
| 312 * capturePictures: (boolean|undefined), | 295 * capturePictures: (boolean|undefined), |
| 313 * captureFilmStrip: (boolean|undefined) | 296 * captureFilmStrip: (boolean|undefined) |
| 314 * }} | 297 * }} |
| 315 */ | 298 */ |
| 316 Timeline.TimelineController.RecordingOptions; | 299 Timeline.TimelineController.RecordingOptions; |
| OLD | NEW |