| 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 * @implements {Common.OutputStream} | 5 * @implements {Common.OutputStream} |
| 6 * @implements {Bindings.OutputStreamDelegate} | 6 * @implements {Bindings.OutputStreamDelegate} |
| 7 * @unrestricted | 7 * @unrestricted |
| 8 */ | 8 */ |
| 9 Timeline.TimelineLoader = class { | 9 Timeline.TimelineLoader = class { |
| 10 /** | 10 /** |
| 11 * @param {!Timeline.TimelineLoader.Client} client | 11 * @param {!Timeline.TimelineLoader.Client} client |
| 12 */ | 12 */ |
| 13 constructor(client) { | 13 constructor(client) { |
| 14 this._client = client; | 14 this._client = client; |
| 15 | 15 |
| 16 this._backingStorage = new Bindings.TempFileBackingStorage('tracing'); | 16 this._backingStorage = new Bindings.TempFileBackingStorage('tracing'); |
| 17 this._tracingModel = new SDK.TracingModel(this._backingStorage); | 17 this._tracingModel = new SDK.TracingModel(this._backingStorage); |
| 18 | 18 |
| 19 /** @type {?function()} */ | 19 /** @type {?function()} */ |
| 20 this._canceledCallback = null; | 20 this._canceledCallback = null; |
| 21 this._state = Timeline.TimelineLoader.State.Initial; | 21 this._state = Timeline.TimelineLoader.State.Initial; |
| 22 this._buffer = ''; | 22 this._buffer = ''; |
| 23 this._firstRawChunk = true; |
| 23 this._firstChunk = true; | 24 this._firstChunk = true; |
| 24 | 25 |
| 25 this._loadedBytes = 0; | 26 this._loadedBytes = 0; |
| 26 /** @type {number} */ | 27 /** @type {number} */ |
| 27 this._totalSize; | 28 this._totalSize; |
| 28 this._jsonTokenizer = new Common.TextUtils.BalancedJSONTokenizer(this._write
BalancedJSON.bind(this), true); | 29 this._jsonTokenizer = new Common.TextUtils.BalancedJSONTokenizer(this._write
BalancedJSON.bind(this), true); |
| 29 } | 30 } |
| 30 | 31 |
| 31 /** | 32 /** |
| 32 * @param {!File} file | 33 * @param {!File} file |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 } | 73 } |
| 73 | 74 |
| 74 /** | 75 /** |
| 75 * @override | 76 * @override |
| 76 * @param {string} chunk | 77 * @param {string} chunk |
| 77 */ | 78 */ |
| 78 write(chunk) { | 79 write(chunk) { |
| 79 if (!this._client) | 80 if (!this._client) |
| 80 return; | 81 return; |
| 81 this._loadedBytes += chunk.length; | 82 this._loadedBytes += chunk.length; |
| 82 if (!this._firstChunk) | 83 if (this._firstRawChunk) |
| 84 this._client.loadingStarted(); |
| 85 else |
| 83 this._client.loadingProgress(this._totalSize ? this._loadedBytes / this._t
otalSize : undefined); | 86 this._client.loadingProgress(this._totalSize ? this._loadedBytes / this._t
otalSize : undefined); |
| 87 this._firstRawChunk = false; |
| 84 | 88 |
| 85 if (this._state === Timeline.TimelineLoader.State.Initial) { | 89 if (this._state === Timeline.TimelineLoader.State.Initial) { |
| 86 if (chunk[0] === '{') { | 90 if (chunk.startsWith('{"nodes":[')) { |
| 91 this._state = Timeline.TimelineLoader.State.LoadingCPUProfileFormat; |
| 92 } else if (chunk[0] === '{') { |
| 87 this._state = Timeline.TimelineLoader.State.LookingForEvents; | 93 this._state = Timeline.TimelineLoader.State.LookingForEvents; |
| 88 } else if (chunk[0] === '[') { | 94 } else if (chunk[0] === '[') { |
| 89 this._state = Timeline.TimelineLoader.State.ReadingEvents; | 95 this._state = Timeline.TimelineLoader.State.ReadingEvents; |
| 90 } else { | 96 } else { |
| 91 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline da
ta: Unknown JSON format')); | 97 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline da
ta: Unknown JSON format')); |
| 92 return; | 98 return; |
| 93 } | 99 } |
| 94 } | 100 } |
| 95 | 101 |
| 102 if (this._state === Timeline.TimelineLoader.State.LoadingCPUProfileFormat) { |
| 103 this._buffer += chunk; |
| 104 return; |
| 105 } |
| 106 |
| 96 if (this._state === Timeline.TimelineLoader.State.LookingForEvents) { | 107 if (this._state === Timeline.TimelineLoader.State.LookingForEvents) { |
| 97 var objectName = '"traceEvents":'; | 108 var objectName = '"traceEvents":'; |
| 98 var startPos = this._buffer.length - objectName.length; | 109 var startPos = this._buffer.length - objectName.length; |
| 99 this._buffer += chunk; | 110 this._buffer += chunk; |
| 100 var pos = this._buffer.indexOf(objectName, startPos); | 111 var pos = this._buffer.indexOf(objectName, startPos); |
| 101 if (pos === -1) | 112 if (pos === -1) |
| 102 return; | 113 return; |
| 103 chunk = this._buffer.slice(pos + objectName.length); | 114 chunk = this._buffer.slice(pos + objectName.length); |
| 104 this._state = Timeline.TimelineLoader.State.ReadingEvents; | 115 this._state = Timeline.TimelineLoader.State.ReadingEvents; |
| 105 } | 116 } |
| 106 | 117 |
| 107 if (this._state !== Timeline.TimelineLoader.State.ReadingEvents) | 118 if (this._state !== Timeline.TimelineLoader.State.ReadingEvents) |
| 108 return; | 119 return; |
| 109 if (this._jsonTokenizer.write(chunk)) | 120 if (this._jsonTokenizer.write(chunk)) |
| 110 return; | 121 return; |
| 111 this._state = Timeline.TimelineLoader.State.SkippingTail; | 122 this._state = Timeline.TimelineLoader.State.SkippingTail; |
| 112 if (this._firstChunk) { | 123 if (this._firstChunk) { |
| 113 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline inpu
t, wrong JSON brackets balance')); | 124 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline inpu
t, wrong JSON brackets balance')); |
| 114 return; | 125 return; |
| 115 } | 126 } |
| 116 } | 127 } |
| 117 | 128 |
| 118 /** | 129 /** |
| 119 * @param {string} data | 130 * @param {string} data |
| 120 */ | 131 */ |
| 121 _writeBalancedJSON(data) { | 132 _writeBalancedJSON(data) { |
| 122 var json = data + ']'; | 133 var json = data + ']'; |
| 123 | 134 |
| 124 if (this._firstChunk) { | 135 if (!this._firstChunk) { |
| 125 this._client.loadingStarted(); | |
| 126 } else { | |
| 127 var commaIndex = json.indexOf(','); | 136 var commaIndex = json.indexOf(','); |
| 128 if (commaIndex !== -1) | 137 if (commaIndex !== -1) |
| 129 json = json.slice(commaIndex + 1); | 138 json = json.slice(commaIndex + 1); |
| 130 json = '[' + json; | 139 json = '[' + json; |
| 131 } | 140 } |
| 132 | 141 |
| 133 var items; | 142 var items; |
| 134 try { | 143 try { |
| 135 items = /** @type {!Array.<!SDK.TracingManager.EventPayload>} */ (JSON.par
se(json)); | 144 items = /** @type {!Array.<!SDK.TracingManager.EventPayload>} */ (JSON.par
se(json)); |
| 136 } catch (e) { | 145 } catch (e) { |
| 137 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data
: %s', e.toString())); | 146 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data
: %s', e.toString())); |
| 138 return; | 147 return; |
| 139 } | 148 } |
| 140 | 149 |
| 141 if (this._firstChunk) { | 150 if (this._firstChunk) { |
| 142 this._firstChunk = false; | 151 this._firstChunk = false; |
| 143 if (this._looksLikeAppVersion(items[0])) { | 152 if (this._looksLikeAppVersion(items[0])) { |
| 144 this._reportErrorAndCancelLoading(Common.UIString('Legacy Timeline forma
t is not supported.')); | 153 this._reportErrorAndCancelLoading(Common.UIString('Legacy Timeline forma
t is not supported.')); |
| 145 return; | 154 return; |
| 146 } | 155 } |
| 147 } | 156 } |
| 148 | 157 |
| 149 try { | 158 try { |
| 150 this._tracingModel.addEvents(items); | 159 this._tracingModel.addEvents(items); |
| 151 } catch (e) { | 160 } catch (e) { |
| 152 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data
: %s', e.toString())); | 161 this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data
: %s', e.toString())); |
| 153 return; | |
| 154 } | 162 } |
| 155 } | 163 } |
| 156 | 164 |
| 157 /** | 165 /** |
| 158 * @param {string=} message | 166 * @param {string=} message |
| 159 */ | 167 */ |
| 160 _reportErrorAndCancelLoading(message) { | 168 _reportErrorAndCancelLoading(message) { |
| 161 if (message) | 169 if (message) |
| 162 Common.console.error(message); | 170 Common.console.error(message); |
| 163 this.cancel(); | 171 this.cancel(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 175 * @override | 183 * @override |
| 176 */ | 184 */ |
| 177 close() { | 185 close() { |
| 178 if (!this._client) | 186 if (!this._client) |
| 179 return; | 187 return; |
| 180 this._client.processingStarted(); | 188 this._client.processingStarted(); |
| 181 setTimeout(() => this._finalizeTrace(), 0); | 189 setTimeout(() => this._finalizeTrace(), 0); |
| 182 } | 190 } |
| 183 | 191 |
| 184 _finalizeTrace() { | 192 _finalizeTrace() { |
| 193 if (this._state === Timeline.TimelineLoader.State.LoadingCPUProfileFormat) { |
| 194 this._parseCPUProfileFormat(this._buffer); |
| 195 this._buffer = ''; |
| 196 } |
| 185 this._tracingModel.tracingComplete(); | 197 this._tracingModel.tracingComplete(); |
| 186 this._client.loadingComplete(this._tracingModel, this._backingStorage); | 198 this._client.loadingComplete(this._tracingModel, this._backingStorage); |
| 187 } | 199 } |
| 188 | 200 |
| 189 /** | 201 /** |
| 190 * @override | 202 * @override |
| 191 */ | 203 */ |
| 192 onTransferStarted() { | 204 onTransferStarted() { |
| 193 } | 205 } |
| 194 | 206 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 218 case 'NotReadableError': | 230 case 'NotReadableError': |
| 219 this._reportErrorAndCancelLoading(Common.UIString('File "%s" is not read
able', reader.fileName())); | 231 this._reportErrorAndCancelLoading(Common.UIString('File "%s" is not read
able', reader.fileName())); |
| 220 break; | 232 break; |
| 221 case 'AbortError': | 233 case 'AbortError': |
| 222 break; | 234 break; |
| 223 default: | 235 default: |
| 224 this._reportErrorAndCancelLoading( | 236 this._reportErrorAndCancelLoading( |
| 225 Common.UIString('An error occurred while reading the file "%s"', rea
der.fileName())); | 237 Common.UIString('An error occurred while reading the file "%s"', rea
der.fileName())); |
| 226 } | 238 } |
| 227 } | 239 } |
| 240 |
| 241 /** |
| 242 * @param {string} text |
| 243 */ |
| 244 _parseCPUProfileFormat(text) { |
| 245 var traceEvents; |
| 246 try { |
| 247 var profile = JSON.parse(text); |
| 248 traceEvents = TimelineModel.TimelineJSProfileProcessor.buildTraceProfileFr
omCpuProfile(profile); |
| 249 } catch (e) { |
| 250 this._reportErrorAndCancelLoading(Common.UIString('Malformed CPU profile f
ormat')); |
| 251 return; |
| 252 } |
| 253 this._tracingModel.addEvents(traceEvents); |
| 254 } |
| 228 }; | 255 }; |
| 229 | 256 |
| 230 | 257 |
| 231 Timeline.TimelineLoader.TransferChunkLengthBytes = 5000000; | 258 Timeline.TimelineLoader.TransferChunkLengthBytes = 5000000; |
| 232 | 259 |
| 233 /** | 260 /** |
| 234 * @interface | 261 * @interface |
| 235 */ | 262 */ |
| 236 Timeline.TimelineLoader.Client = function() {}; | 263 Timeline.TimelineLoader.Client = function() {}; |
| 237 | 264 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 252 loadingComplete(tracingModel, backingStorage) {}, | 279 loadingComplete(tracingModel, backingStorage) {}, |
| 253 }; | 280 }; |
| 254 | 281 |
| 255 /** | 282 /** |
| 256 * @enum {symbol} | 283 * @enum {symbol} |
| 257 */ | 284 */ |
| 258 Timeline.TimelineLoader.State = { | 285 Timeline.TimelineLoader.State = { |
| 259 Initial: Symbol('Initial'), | 286 Initial: Symbol('Initial'), |
| 260 LookingForEvents: Symbol('LookingForEvents'), | 287 LookingForEvents: Symbol('LookingForEvents'), |
| 261 ReadingEvents: Symbol('ReadingEvents'), | 288 ReadingEvents: Symbol('ReadingEvents'), |
| 262 SkippingTail: Symbol('SkippingTail') | 289 SkippingTail: Symbol('SkippingTail'), |
| 290 LoadingCPUProfileFormat: Symbol('LoadingCPUProfileFormat') |
| 263 }; | 291 }; |
| 264 | 292 |
| 265 /** | 293 /** |
| 266 * @implements {Bindings.OutputStreamDelegate} | 294 * @implements {Bindings.OutputStreamDelegate} |
| 267 * @unrestricted | 295 * @unrestricted |
| 268 */ | 296 */ |
| 269 Timeline.TracingTimelineSaver = class { | 297 Timeline.TracingTimelineSaver = class { |
| 270 /** | 298 /** |
| 271 * @override | 299 * @override |
| 272 */ | 300 */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 290 * @override | 318 * @override |
| 291 * @param {!Bindings.ChunkedReader} reader | 319 * @param {!Bindings.ChunkedReader} reader |
| 292 * @param {!Event} event | 320 * @param {!Event} event |
| 293 */ | 321 */ |
| 294 onError(reader, event) { | 322 onError(reader, event) { |
| 295 var error = event.target.error; | 323 var error = event.target.error; |
| 296 Common.console.error( | 324 Common.console.error( |
| 297 Common.UIString('Failed to save timeline: %s (%s, %s)', error.message, e
rror.name, error.code)); | 325 Common.UIString('Failed to save timeline: %s (%s, %s)', error.message, e
rror.name, error.code)); |
| 298 } | 326 } |
| 299 }; | 327 }; |
| OLD | NEW |