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 | |
5 /** | 4 /** |
6 * @constructor | |
7 * @param {!WebInspector.Target} target | |
8 * @param {!WebInspector.TimelineLifecycleDelegate} delegate | |
9 * @param {!WebInspector.TracingModel} tracingModel | |
10 * @implements {WebInspector.TargetManager.Observer} | 5 * @implements {WebInspector.TargetManager.Observer} |
11 * @implements {WebInspector.TracingManagerClient} | 6 * @implements {WebInspector.TracingManagerClient} |
| 7 * @unrestricted |
12 */ | 8 */ |
13 WebInspector.TimelineController = function(target, delegate, tracingModel) | 9 WebInspector.TimelineController = class { |
14 { | 10 /** |
| 11 * @param {!WebInspector.Target} target |
| 12 * @param {!WebInspector.TimelineLifecycleDelegate} delegate |
| 13 * @param {!WebInspector.TracingModel} tracingModel |
| 14 */ |
| 15 constructor(target, delegate, tracingModel) { |
15 this._delegate = delegate; | 16 this._delegate = delegate; |
16 this._target = target; | 17 this._target = target; |
17 this._tracingModel = tracingModel; | 18 this._tracingModel = tracingModel; |
18 this._targets = []; | 19 this._targets = []; |
19 WebInspector.targetManager.observeTargets(this); | 20 WebInspector.targetManager.observeTargets(this); |
| 21 } |
| 22 |
| 23 /** |
| 24 * @param {boolean} captureCauses |
| 25 * @param {boolean} enableJSSampling |
| 26 * @param {boolean} captureMemory |
| 27 * @param {boolean} capturePictures |
| 28 * @param {boolean} captureFilmStrip |
| 29 */ |
| 30 startRecording(captureCauses, enableJSSampling, captureMemory, capturePictures
, captureFilmStrip) { |
| 31 this._extensionTraceProviders = WebInspector.extensionServer.traceProviders(
).slice(); |
| 32 |
| 33 function disabledByDefault(category) { |
| 34 return 'disabled-by-default-' + category; |
| 35 } |
| 36 var categoriesArray = [ |
| 37 '-*', 'devtools.timeline', 'v8.execute', disabledByDefault('devtools.timel
ine'), |
| 38 disabledByDefault('devtools.timeline.frame'), WebInspector.TracingModel.To
pLevelEventCategory, |
| 39 WebInspector.TimelineModel.Category.Console, WebInspector.TimelineModel.Ca
tegory.UserTiming |
| 40 ]; |
| 41 categoriesArray.push(WebInspector.TimelineModel.Category.LatencyInfo); |
| 42 |
| 43 if (Runtime.experiments.isEnabled('timelineFlowEvents')) { |
| 44 categoriesArray.push(disabledByDefault('toplevel.flow'), disabledByDefault
('ipc.flow')); |
| 45 } |
| 46 if (Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && enableJSS
ampling) |
| 47 categoriesArray.push(disabledByDefault('v8.runtime_stats')); |
| 48 if (Runtime.experiments.isEnabled('timelineTracingJSProfile') && enableJSSam
pling) { |
| 49 categoriesArray.push(disabledByDefault('v8.cpu_profiler')); |
| 50 if (WebInspector.moduleSetting('highResolutionCpuProfiling').get()) |
| 51 categoriesArray.push(disabledByDefault('v8.cpu_profiler.hires')); |
| 52 } |
| 53 if (captureCauses || enableJSSampling) |
| 54 categoriesArray.push(disabledByDefault('devtools.timeline.stack')); |
| 55 if (captureCauses && Runtime.experiments.isEnabled('timelineInvalidationTrac
king')) |
| 56 categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTrac
king')); |
| 57 if (capturePictures) { |
| 58 categoriesArray.push( |
| 59 disabledByDefault('devtools.timeline.layers'), disabledByDefault('devt
ools.timeline.picture'), |
| 60 disabledByDefault('blink.graphics_context_annotations')); |
| 61 } |
| 62 if (captureFilmStrip) |
| 63 categoriesArray.push(disabledByDefault('devtools.screenshot')); |
| 64 |
| 65 for (var traceProvider of this._extensionTraceProviders) |
| 66 traceProvider.start(); |
| 67 |
| 68 var categories = categoriesArray.join(','); |
| 69 this._startRecordingWithCategories(categories, enableJSSampling); |
| 70 } |
| 71 |
| 72 stopRecording() { |
| 73 var tracingStoppedPromises = []; |
| 74 tracingStoppedPromises.push(new Promise(resolve => this._tracingCompleteCall
back = resolve)); |
| 75 tracingStoppedPromises.push(this._stopProfilingOnAllTargets()); |
| 76 this._target.tracingManager.stop(); |
| 77 tracingStoppedPromises.push(WebInspector.targetManager.resumeAllTargets()); |
| 78 Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished()); |
| 79 |
| 80 this._delegate.loadingStarted(); |
| 81 |
| 82 for (var traceProvider of this._extensionTraceProviders) |
| 83 traceProvider.stop(); |
| 84 } |
| 85 |
| 86 /** |
| 87 * @override |
| 88 * @param {!WebInspector.Target} target |
| 89 */ |
| 90 targetAdded(target) { |
| 91 this._targets.push(target); |
| 92 if (this._profiling) |
| 93 this._startProfilingOnTarget(target); |
| 94 } |
| 95 |
| 96 /** |
| 97 * @override |
| 98 * @param {!WebInspector.Target} target |
| 99 */ |
| 100 targetRemoved(target) { |
| 101 this._targets.remove(target, true); |
| 102 // FIXME: We'd like to stop profiling on the target and retrieve a profile |
| 103 // but it's too late. Backend connection is closed. |
| 104 } |
| 105 |
| 106 /** |
| 107 * @param {!WebInspector.Target} target |
| 108 * @return {!Promise} |
| 109 */ |
| 110 _startProfilingOnTarget(target) { |
| 111 return target.hasJSCapability() ? target.profilerAgent().start() : Promise.r
esolve(); |
| 112 } |
| 113 |
| 114 /** |
| 115 * @return {!Promise} |
| 116 */ |
| 117 _startProfilingOnAllTargets() { |
| 118 var intervalUs = WebInspector.moduleSetting('highResolutionCpuProfiling').ge
t() ? 100 : 1000; |
| 119 this._target.profilerAgent().setSamplingInterval(intervalUs); |
| 120 this._profiling = true; |
| 121 return Promise.all(this._targets.map(this._startProfilingOnTarget)); |
| 122 } |
| 123 |
| 124 /** |
| 125 * @param {!WebInspector.Target} target |
| 126 * @return {!Promise} |
| 127 */ |
| 128 _stopProfilingOnTarget(target) { |
| 129 return target.hasJSCapability() ? target.profilerAgent().stop(this._addCpuPr
ofile.bind(this, target.id())) : |
| 130 Promise.resolve(); |
| 131 } |
| 132 |
| 133 /** |
| 134 * @param {number} targetId |
| 135 * @param {?Protocol.Error} error |
| 136 * @param {?ProfilerAgent.Profile} cpuProfile |
| 137 */ |
| 138 _addCpuProfile(targetId, error, cpuProfile) { |
| 139 if (!cpuProfile) { |
| 140 WebInspector.console.warn(WebInspector.UIString('CPU profile for a target
is not available. %s', error || '')); |
| 141 return; |
| 142 } |
| 143 if (!this._cpuProfiles) |
| 144 this._cpuProfiles = new Map(); |
| 145 this._cpuProfiles.set(targetId, cpuProfile); |
| 146 } |
| 147 |
| 148 /** |
| 149 * @return {!Promise} |
| 150 */ |
| 151 _stopProfilingOnAllTargets() { |
| 152 var targets = this._profiling ? this._targets : []; |
| 153 this._profiling = false; |
| 154 return Promise.all(targets.map(this._stopProfilingOnTarget, this)); |
| 155 } |
| 156 |
| 157 /** |
| 158 * @param {string} categories |
| 159 * @param {boolean=} enableJSSampling |
| 160 * @param {function(?string)=} callback |
| 161 */ |
| 162 _startRecordingWithCategories(categories, enableJSSampling, callback) { |
| 163 WebInspector.targetManager.suspendAllTargets(); |
| 164 var profilingStartedPromise = enableJSSampling && !Runtime.experiments.isEna
bled('timelineTracingJSProfile') ? |
| 165 this._startProfilingOnAllTargets() : |
| 166 Promise.resolve(); |
| 167 var samplingFrequencyHz = WebInspector.moduleSetting('highResolutionCpuProfi
ling').get() ? 10000 : 1000; |
| 168 var options = 'sampling-frequency=' + samplingFrequencyHz; |
| 169 var target = this._target; |
| 170 var tracingManager = target.tracingManager; |
| 171 WebInspector.targetManager.suspendReload(target); |
| 172 profilingStartedPromise.then(tracingManager.start.bind(tracingManager, this,
categories, options, onTraceStarted)); |
| 173 /** |
| 174 * @param {?string} error |
| 175 */ |
| 176 function onTraceStarted(error) { |
| 177 WebInspector.targetManager.resumeReload(target); |
| 178 if (callback) |
| 179 callback(error); |
| 180 } |
| 181 } |
| 182 |
| 183 /** |
| 184 * @override |
| 185 */ |
| 186 tracingStarted() { |
| 187 this._tracingModel.reset(); |
| 188 this._delegate.recordingStarted(); |
| 189 } |
| 190 |
| 191 /** |
| 192 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events |
| 193 * @override |
| 194 */ |
| 195 traceEventsCollected(events) { |
| 196 this._tracingModel.addEvents(events); |
| 197 } |
| 198 |
| 199 /** |
| 200 * @override |
| 201 */ |
| 202 tracingComplete() { |
| 203 this._tracingCompleteCallback(); |
| 204 this._tracingCompleteCallback = null; |
| 205 } |
| 206 |
| 207 _allSourcesFinished() { |
| 208 this._injectCpuProfileEvents(); |
| 209 this._tracingModel.tracingComplete(); |
| 210 this._delegate.loadingComplete(true); |
| 211 } |
| 212 |
| 213 /** |
| 214 * @param {number} pid |
| 215 * @param {number} tid |
| 216 * @param {?ProfilerAgent.Profile} cpuProfile |
| 217 */ |
| 218 _injectCpuProfileEvent(pid, tid, cpuProfile) { |
| 219 if (!cpuProfile) |
| 220 return; |
| 221 var cpuProfileEvent = /** @type {!WebInspector.TracingManager.EventPayload}
*/ ({ |
| 222 cat: WebInspector.TracingModel.DevToolsMetadataEventCategory, |
| 223 ph: WebInspector.TracingModel.Phase.Instant, |
| 224 ts: this._tracingModel.maximumRecordTime() * 1000, |
| 225 pid: pid, |
| 226 tid: tid, |
| 227 name: WebInspector.TimelineModel.RecordType.CpuProfile, |
| 228 args: {data: {cpuProfile: cpuProfile}} |
| 229 }); |
| 230 this._tracingModel.addEvents([cpuProfileEvent]); |
| 231 } |
| 232 |
| 233 _injectCpuProfileEvents() { |
| 234 if (!this._cpuProfiles) |
| 235 return; |
| 236 |
| 237 var metadataEventTypes = WebInspector.TimelineModel.DevToolsMetadataEvent; |
| 238 var metadataEvents = this._tracingModel.devToolsMetadataEvents(); |
| 239 var mainMetaEvent = |
| 240 metadataEvents.filter(event => event.name === metadataEventTypes.Tracing
StartedInPage).peekLast(); |
| 241 if (!mainMetaEvent) |
| 242 return; |
| 243 |
| 244 var pid = mainMetaEvent.thread.process().id(); |
| 245 var mainCpuProfile = this._cpuProfiles.get(this._target.id()); |
| 246 this._injectCpuProfileEvent(pid, mainMetaEvent.thread.id(), mainCpuProfile); |
| 247 |
| 248 var workerMetaEvents = metadataEvents.filter(event => event.name === metadat
aEventTypes.TracingSessionIdForWorker); |
| 249 for (var metaEvent of workerMetaEvents) { |
| 250 var workerId = metaEvent.args['data']['workerId']; |
| 251 var workerTarget = this._target.subTargetsManager ? this._target.subTarget
sManager.targetForId(workerId) : null; |
| 252 if (!workerTarget) |
| 253 continue; |
| 254 var cpuProfile = this._cpuProfiles.get(workerTarget.id()); |
| 255 this._injectCpuProfileEvent(pid, metaEvent.args['data']['workerThreadId'],
cpuProfile); |
| 256 } |
| 257 this._cpuProfiles = null; |
| 258 } |
| 259 |
| 260 /** |
| 261 * @param {number} usage |
| 262 * @override |
| 263 */ |
| 264 tracingBufferUsage(usage) { |
| 265 this._delegate.recordingProgress(usage); |
| 266 } |
| 267 |
| 268 /** |
| 269 * @param {number} progress |
| 270 * @override |
| 271 */ |
| 272 eventsRetrievalProgress(progress) { |
| 273 this._delegate.loadingProgress(progress); |
| 274 } |
20 }; | 275 }; |
21 | |
22 WebInspector.TimelineController.prototype = { | |
23 /** | |
24 * @param {boolean} captureCauses | |
25 * @param {boolean} enableJSSampling | |
26 * @param {boolean} captureMemory | |
27 * @param {boolean} capturePictures | |
28 * @param {boolean} captureFilmStrip | |
29 */ | |
30 startRecording: function(captureCauses, enableJSSampling, captureMemory, cap
turePictures, captureFilmStrip) | |
31 { | |
32 this._extensionTraceProviders = WebInspector.extensionServer.traceProvid
ers().slice(); | |
33 | |
34 function disabledByDefault(category) | |
35 { | |
36 return "disabled-by-default-" + category; | |
37 } | |
38 var categoriesArray = [ | |
39 "-*", | |
40 "devtools.timeline", | |
41 "v8.execute", | |
42 disabledByDefault("devtools.timeline"), | |
43 disabledByDefault("devtools.timeline.frame"), | |
44 WebInspector.TracingModel.TopLevelEventCategory, | |
45 WebInspector.TimelineModel.Category.Console, | |
46 WebInspector.TimelineModel.Category.UserTiming | |
47 ]; | |
48 categoriesArray.push(WebInspector.TimelineModel.Category.LatencyInfo); | |
49 | |
50 if (Runtime.experiments.isEnabled("timelineFlowEvents")) { | |
51 categoriesArray.push(disabledByDefault("toplevel.flow"), | |
52 disabledByDefault("ipc.flow")); | |
53 } | |
54 if (Runtime.experiments.isEnabled("timelineV8RuntimeCallStats") && enabl
eJSSampling) | |
55 categoriesArray.push(disabledByDefault("v8.runtime_stats")); | |
56 if (Runtime.experiments.isEnabled("timelineTracingJSProfile") && enableJ
SSampling) { | |
57 categoriesArray.push(disabledByDefault("v8.cpu_profiler")); | |
58 if (WebInspector.moduleSetting("highResolutionCpuProfiling").get()) | |
59 categoriesArray.push(disabledByDefault("v8.cpu_profiler.hires"))
; | |
60 } | |
61 if (captureCauses || enableJSSampling) | |
62 categoriesArray.push(disabledByDefault("devtools.timeline.stack")); | |
63 if (captureCauses && Runtime.experiments.isEnabled("timelineInvalidation
Tracking")) | |
64 categoriesArray.push(disabledByDefault("devtools.timeline.invalidati
onTracking")); | |
65 if (capturePictures) { | |
66 categoriesArray.push(disabledByDefault("devtools.timeline.layers"), | |
67 disabledByDefault("devtools.timeline.picture"), | |
68 disabledByDefault("blink.graphics_context_annot
ations")); | |
69 } | |
70 if (captureFilmStrip) | |
71 categoriesArray.push(disabledByDefault("devtools.screenshot")); | |
72 | |
73 for (var traceProvider of this._extensionTraceProviders) | |
74 traceProvider.start(); | |
75 | |
76 var categories = categoriesArray.join(","); | |
77 this._startRecordingWithCategories(categories, enableJSSampling); | |
78 }, | |
79 | |
80 stopRecording: function() | |
81 { | |
82 var tracingStoppedPromises = []; | |
83 tracingStoppedPromises.push(new Promise(resolve => this._tracingComplete
Callback = resolve)); | |
84 tracingStoppedPromises.push(this._stopProfilingOnAllTargets()); | |
85 this._target.tracingManager.stop(); | |
86 tracingStoppedPromises.push(WebInspector.targetManager.resumeAllTargets(
)); | |
87 Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished(
)); | |
88 | |
89 this._delegate.loadingStarted(); | |
90 | |
91 for (var traceProvider of this._extensionTraceProviders) | |
92 traceProvider.stop(); | |
93 }, | |
94 | |
95 /** | |
96 * @override | |
97 * @param {!WebInspector.Target} target | |
98 */ | |
99 targetAdded: function(target) | |
100 { | |
101 this._targets.push(target); | |
102 if (this._profiling) | |
103 this._startProfilingOnTarget(target); | |
104 }, | |
105 | |
106 /** | |
107 * @override | |
108 * @param {!WebInspector.Target} target | |
109 */ | |
110 targetRemoved: function(target) | |
111 { | |
112 this._targets.remove(target, true); | |
113 // FIXME: We'd like to stop profiling on the target and retrieve a profi
le | |
114 // but it's too late. Backend connection is closed. | |
115 }, | |
116 | |
117 /** | |
118 * @param {!WebInspector.Target} target | |
119 * @return {!Promise} | |
120 */ | |
121 _startProfilingOnTarget: function(target) | |
122 { | |
123 return target.hasJSCapability() ? target.profilerAgent().start() : Promi
se.resolve(); | |
124 }, | |
125 | |
126 /** | |
127 * @return {!Promise} | |
128 */ | |
129 _startProfilingOnAllTargets: function() | |
130 { | |
131 var intervalUs = WebInspector.moduleSetting("highResolutionCpuProfiling"
).get() ? 100 : 1000; | |
132 this._target.profilerAgent().setSamplingInterval(intervalUs); | |
133 this._profiling = true; | |
134 return Promise.all(this._targets.map(this._startProfilingOnTarget)); | |
135 }, | |
136 | |
137 /** | |
138 * @param {!WebInspector.Target} target | |
139 * @return {!Promise} | |
140 */ | |
141 _stopProfilingOnTarget: function(target) | |
142 { | |
143 return target.hasJSCapability() ? target.profilerAgent().stop(this._addC
puProfile.bind(this, target.id())) : Promise.resolve(); | |
144 }, | |
145 | |
146 /** | |
147 * @param {number} targetId | |
148 * @param {?Protocol.Error} error | |
149 * @param {?ProfilerAgent.Profile} cpuProfile | |
150 */ | |
151 _addCpuProfile: function(targetId, error, cpuProfile) | |
152 { | |
153 if (!cpuProfile) { | |
154 WebInspector.console.warn(WebInspector.UIString("CPU profile for a t
arget is not available. %s", error || "")); | |
155 return; | |
156 } | |
157 if (!this._cpuProfiles) | |
158 this._cpuProfiles = new Map(); | |
159 this._cpuProfiles.set(targetId, cpuProfile); | |
160 }, | |
161 | |
162 /** | |
163 * @return {!Promise} | |
164 */ | |
165 _stopProfilingOnAllTargets: function() | |
166 { | |
167 var targets = this._profiling ? this._targets : []; | |
168 this._profiling = false; | |
169 return Promise.all(targets.map(this._stopProfilingOnTarget, this)); | |
170 }, | |
171 | |
172 /** | |
173 * @param {string} categories | |
174 * @param {boolean=} enableJSSampling | |
175 * @param {function(?string)=} callback | |
176 */ | |
177 _startRecordingWithCategories: function(categories, enableJSSampling, callba
ck) | |
178 { | |
179 WebInspector.targetManager.suspendAllTargets(); | |
180 var profilingStartedPromise = enableJSSampling && !Runtime.experiments.i
sEnabled("timelineTracingJSProfile") ? | |
181 this._startProfilingOnAllTargets() : Promise.resolve(); | |
182 var samplingFrequencyHz = WebInspector.moduleSetting("highResolutionCpuP
rofiling").get() ? 10000 : 1000; | |
183 var options = "sampling-frequency=" + samplingFrequencyHz; | |
184 var target = this._target; | |
185 var tracingManager = target.tracingManager; | |
186 WebInspector.targetManager.suspendReload(target); | |
187 profilingStartedPromise.then(tracingManager.start.bind(tracingManager, t
his, categories, options, onTraceStarted)); | |
188 /** | |
189 * @param {?string} error | |
190 */ | |
191 function onTraceStarted(error) | |
192 { | |
193 WebInspector.targetManager.resumeReload(target); | |
194 if (callback) | |
195 callback(error); | |
196 } | |
197 }, | |
198 | |
199 /** | |
200 * @override | |
201 */ | |
202 tracingStarted: function() | |
203 { | |
204 this._tracingModel.reset(); | |
205 this._delegate.recordingStarted(); | |
206 }, | |
207 | |
208 /** | |
209 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
210 * @override | |
211 */ | |
212 traceEventsCollected: function(events) | |
213 { | |
214 this._tracingModel.addEvents(events); | |
215 }, | |
216 | |
217 /** | |
218 * @override | |
219 */ | |
220 tracingComplete: function() | |
221 { | |
222 this._tracingCompleteCallback(); | |
223 this._tracingCompleteCallback = null; | |
224 }, | |
225 | |
226 _allSourcesFinished: function() | |
227 { | |
228 this._injectCpuProfileEvents(); | |
229 this._tracingModel.tracingComplete(); | |
230 this._delegate.loadingComplete(true); | |
231 }, | |
232 | |
233 /** | |
234 * @param {number} pid | |
235 * @param {number} tid | |
236 * @param {?ProfilerAgent.Profile} cpuProfile | |
237 */ | |
238 _injectCpuProfileEvent: function(pid, tid, cpuProfile) | |
239 { | |
240 if (!cpuProfile) | |
241 return; | |
242 var cpuProfileEvent = /** @type {!WebInspector.TracingManager.EventPaylo
ad} */ ({ | |
243 cat: WebInspector.TracingModel.DevToolsMetadataEventCategory, | |
244 ph: WebInspector.TracingModel.Phase.Instant, | |
245 ts: this._tracingModel.maximumRecordTime() * 1000, | |
246 pid: pid, | |
247 tid: tid, | |
248 name: WebInspector.TimelineModel.RecordType.CpuProfile, | |
249 args: { data: { cpuProfile: cpuProfile } } | |
250 }); | |
251 this._tracingModel.addEvents([cpuProfileEvent]); | |
252 }, | |
253 | |
254 _injectCpuProfileEvents: function() | |
255 { | |
256 if (!this._cpuProfiles) | |
257 return; | |
258 | |
259 var metadataEventTypes = WebInspector.TimelineModel.DevToolsMetadataEven
t; | |
260 var metadataEvents = this._tracingModel.devToolsMetadataEvents(); | |
261 var mainMetaEvent = metadataEvents.filter(event => event.name === metada
taEventTypes.TracingStartedInPage).peekLast(); | |
262 if (!mainMetaEvent) | |
263 return; | |
264 | |
265 var pid = mainMetaEvent.thread.process().id(); | |
266 var mainCpuProfile = this._cpuProfiles.get(this._target.id()); | |
267 this._injectCpuProfileEvent(pid, mainMetaEvent.thread.id(), mainCpuProfi
le); | |
268 | |
269 var workerMetaEvents = metadataEvents.filter(event => event.name === met
adataEventTypes.TracingSessionIdForWorker); | |
270 for (var metaEvent of workerMetaEvents) { | |
271 var workerId = metaEvent.args["data"]["workerId"]; | |
272 var workerTarget = this._target.subTargetsManager ? this._target.sub
TargetsManager.targetForId(workerId) : null; | |
273 if (!workerTarget) | |
274 continue; | |
275 var cpuProfile = this._cpuProfiles.get(workerTarget.id()); | |
276 this._injectCpuProfileEvent(pid, metaEvent.args["data"]["workerThrea
dId"], cpuProfile); | |
277 } | |
278 this._cpuProfiles = null; | |
279 }, | |
280 | |
281 /** | |
282 * @param {number} usage | |
283 * @override | |
284 */ | |
285 tracingBufferUsage: function(usage) | |
286 { | |
287 this._delegate.recordingProgress(usage); | |
288 }, | |
289 | |
290 /** | |
291 * @param {number} progress | |
292 * @override | |
293 */ | |
294 eventsRetrievalProgress: function(progress) | |
295 { | |
296 this._delegate.loadingProgress(progress); | |
297 } | |
298 }; | |
OLD | NEW |