| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2014 The Chromium Authors. All rights reserved. | |
| 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 /** | |
| 8 * @constructor | |
| 9 * @implements {WebInspector.TimelineModeView} | |
| 10 * @implements {WebInspector.FlameChartDelegate} | |
| 11 * @extends {WebInspector.VBox} | |
| 12 * @param {!WebInspector.TimelineModeViewDelegate} delegate | |
| 13 * @param {!WebInspector.TracingModel} tracingModel | |
| 14 * @param {!WebInspector.TimelineModel} modelForMinimumBoundary | |
| 15 */ | |
| 16 WebInspector.TimelineTracingView = function(delegate, tracingModel, modelForMini
mumBoundary) | |
| 17 { | |
| 18 WebInspector.VBox.call(this); | |
| 19 this._delegate = delegate; | |
| 20 this._tracingModel = tracingModel; | |
| 21 this.element.classList.add("timeline-flamechart"); | |
| 22 this.registerRequiredCSS("flameChart.css"); | |
| 23 this._dataProvider = new WebInspector.TraceViewFlameChartDataProvider(this._
tracingModel, modelForMinimumBoundary); | |
| 24 this._mainView = new WebInspector.FlameChart(this._dataProvider, this, true)
; | |
| 25 this._mainView.show(this.element); | |
| 26 this._mainView.addEventListener(WebInspector.FlameChart.Events.EntrySelected
, this._onEntrySelected, this); | |
| 27 } | |
| 28 | |
| 29 WebInspector.TimelineTracingView.prototype = { | |
| 30 /** | |
| 31 * @param {number} windowStartTime | |
| 32 * @param {number} windowEndTime | |
| 33 */ | |
| 34 requestWindowTimes: function(windowStartTime, windowEndTime) | |
| 35 { | |
| 36 this._delegate.requestWindowTimes(windowStartTime, windowEndTime); | |
| 37 }, | |
| 38 | |
| 39 wasShown: function() | |
| 40 { | |
| 41 this._mainView.scheduleUpdate(); | |
| 42 }, | |
| 43 | |
| 44 /** | |
| 45 * @return {!WebInspector.View} | |
| 46 */ | |
| 47 view: function() | |
| 48 { | |
| 49 return this; | |
| 50 }, | |
| 51 | |
| 52 dispose: function() | |
| 53 { | |
| 54 }, | |
| 55 | |
| 56 reset: function() | |
| 57 { | |
| 58 this._dataProvider.reset(); | |
| 59 this._mainView.setWindowTimes(0, Infinity); | |
| 60 }, | |
| 61 | |
| 62 /** | |
| 63 * @param {?RegExp} textFilter | |
| 64 */ | |
| 65 refreshRecords: function(textFilter) | |
| 66 { | |
| 67 this._dataProvider.reset(); | |
| 68 this._mainView.scheduleUpdate(); | |
| 69 }, | |
| 70 | |
| 71 /** | |
| 72 * @param {!WebInspector.TimelineModel.Record} record | |
| 73 */ | |
| 74 addRecord: function(record) {}, | |
| 75 | |
| 76 /** | |
| 77 * @param {?WebInspector.TimelineModel.Record} record | |
| 78 * @param {string=} regex | |
| 79 * @param {boolean=} selectRecord | |
| 80 */ | |
| 81 highlightSearchResult: function(record, regex, selectRecord) {}, | |
| 82 | |
| 83 /** | |
| 84 * @param {number} startTime | |
| 85 * @param {number} endTime | |
| 86 */ | |
| 87 setWindowTimes: function(startTime, endTime) | |
| 88 { | |
| 89 this._mainView.setWindowTimes(startTime, endTime); | |
| 90 }, | |
| 91 | |
| 92 /** | |
| 93 * @param {number} width | |
| 94 */ | |
| 95 setSidebarSize: function(width) {}, | |
| 96 | |
| 97 /** | |
| 98 * @param {?WebInspector.TimelineSelection} selection | |
| 99 */ | |
| 100 setSelection: function(selection) {}, | |
| 101 | |
| 102 /** | |
| 103 * @param {!WebInspector.Event} event | |
| 104 */ | |
| 105 _onEntrySelected: function(event) | |
| 106 { | |
| 107 var index = /** @type {number} */ (event.data); | |
| 108 var record = this._dataProvider._recordAt(index); | |
| 109 if (!record || this._dataProvider._isHeaderRecord(record)) { | |
| 110 this._delegate.showInDetails("", document.createTextNode("")); | |
| 111 return; | |
| 112 } | |
| 113 var contentHelper = new WebInspector.TimelineDetailsContentHelper(null,
null, false); | |
| 114 contentHelper.appendTextRow(WebInspector.UIString("Name"), record.name); | |
| 115 contentHelper.appendTextRow(WebInspector.UIString("Category"), record.ca
tegory); | |
| 116 contentHelper.appendTextRow(WebInspector.UIString("Start"), Number.milli
sToString(record.startTime - this._tracingModel.minimumRecordTime(), true)); | |
| 117 contentHelper.appendTextRow(WebInspector.UIString("Duration"), Number.mi
llisToString(record.duration, true)); | |
| 118 if (!Object.isEmpty(record.args)) | |
| 119 contentHelper.appendElementRow(WebInspector.UIString("Arguments"), t
his._formatArguments(record.args)); | |
| 120 | |
| 121 function reveal() | |
| 122 { | |
| 123 WebInspector.Revealer.reveal(new WebInspector.DeferredTracingLayerTr
ee(record.thread.target(), record.args["snapshot"]["active_tree"]["root_layer"],
record.args["snapshot"]["device_viewport_size"])); | |
| 124 } | |
| 125 /** | |
| 126 * @param {!Node=} node | |
| 127 * @this {WebInspector.TimelineTracingView} | |
| 128 */ | |
| 129 function appendPreviewAndShowDetails(node) | |
| 130 { | |
| 131 if (node) | |
| 132 contentHelper.appendElementRow("Preview", node); | |
| 133 this._delegate.showInDetails(WebInspector.UIString("Selected Event")
, contentHelper.element); | |
| 134 } | |
| 135 var recordTypes = WebInspector.TracingTimelineModel.RecordType; | |
| 136 switch (record.name) { | |
| 137 case recordTypes.PictureSnapshot: | |
| 138 WebInspector.TracingTimelineUIUtils.buildPicturePreviewContent(this.
_tracingModel.target(), record.args["snapshot"]["skp64"], appendPreviewAndShowDe
tails.bind(this)); | |
| 139 break; | |
| 140 case recordTypes.LayerTreeHostImplSnapshot: | |
| 141 var link = document.createElement("span"); | |
| 142 link.classList.add("revealable-link"); | |
| 143 link.textContent = "show"; | |
| 144 link.addEventListener("click", reveal, false); | |
| 145 contentHelper.appendElementRow(WebInspector.UIString("Layer tree"),
link); | |
| 146 // Fall-through intended. | |
| 147 default: | |
| 148 this._delegate.showInDetails(WebInspector.UIString("Selected Event")
, contentHelper.element); | |
| 149 } | |
| 150 }, | |
| 151 | |
| 152 /** | |
| 153 * @param {!Object} args | |
| 154 * @return {!Element} | |
| 155 */ | |
| 156 _formatArguments: function(args) | |
| 157 { | |
| 158 var table = document.createElement("table"); | |
| 159 for (var name in args) { | |
| 160 var row = table.createChild("tr"); | |
| 161 row.createChild("td", "timeline-details-row-title").textContent = na
me + ":"; | |
| 162 var valueContainer = row.createChild("td", "timeline-details-row-dat
a"); | |
| 163 var value = args[name]; | |
| 164 if (typeof value === "object" && value) { | |
| 165 var localObject = new WebInspector.LocalJSONObject(value); | |
| 166 var propertiesSection = new WebInspector.ObjectPropertiesSection
(localObject, localObject.description); | |
| 167 valueContainer.appendChild(propertiesSection.element); | |
| 168 } else { | |
| 169 valueContainer.textContent = String(value); | |
| 170 } | |
| 171 } | |
| 172 return table; | |
| 173 }, | |
| 174 | |
| 175 __proto__: WebInspector.VBox.prototype | |
| 176 }; | |
| 177 | |
| 178 /** | |
| 179 * @constructor | |
| 180 * @implements {WebInspector.FlameChartDataProvider} | |
| 181 * @param {!WebInspector.TracingModel} model | |
| 182 * @param {!WebInspector.TimelineModel} timelineModelForMinimumBoundary | |
| 183 */ | |
| 184 WebInspector.TraceViewFlameChartDataProvider = function(model, timelineModelForM
inimumBoundary) | |
| 185 { | |
| 186 WebInspector.FlameChartDataProvider.call(this); | |
| 187 this._model = model; | |
| 188 this._timelineModelForMinimumBoundary = timelineModelForMinimumBoundary; | |
| 189 this._font = "12px " + WebInspector.fontFamily(); | |
| 190 this._palette = new WebInspector.TraceViewPalette(); | |
| 191 var dummyEventPayload = { | |
| 192 cat: "dummy", | |
| 193 pid: 0, | |
| 194 tid: 0, | |
| 195 ts: 0, | |
| 196 ph: "dummy", | |
| 197 name: "dummy", | |
| 198 args: {}, | |
| 199 dur: 0, | |
| 200 id: 0, | |
| 201 s: "" | |
| 202 } | |
| 203 this._processHeaderRecord = new WebInspector.TracingModel.Event(dummyEventPa
yload, 0, null); | |
| 204 this._threadHeaderRecord = new WebInspector.TracingModel.Event(dummyEventPay
load, 0, null); | |
| 205 } | |
| 206 | |
| 207 WebInspector.TraceViewFlameChartDataProvider.prototype = { | |
| 208 /** | |
| 209 * @return {number} | |
| 210 */ | |
| 211 barHeight: function() | |
| 212 { | |
| 213 return 20; | |
| 214 }, | |
| 215 | |
| 216 /** | |
| 217 * @return {number} | |
| 218 */ | |
| 219 textBaseline: function() | |
| 220 { | |
| 221 return 6; | |
| 222 }, | |
| 223 | |
| 224 /** | |
| 225 * @return {number} | |
| 226 */ | |
| 227 textPadding: function() | |
| 228 { | |
| 229 return 5; | |
| 230 }, | |
| 231 | |
| 232 /** | |
| 233 * @param {number} entryIndex | |
| 234 * @return {string} | |
| 235 */ | |
| 236 entryFont: function(entryIndex) | |
| 237 { | |
| 238 return this._font; | |
| 239 }, | |
| 240 | |
| 241 /** | |
| 242 * @param {number} entryIndex | |
| 243 * @return {?string} | |
| 244 */ | |
| 245 entryTitle: function(entryIndex) | |
| 246 { | |
| 247 var record = this._records[entryIndex]; | |
| 248 if (this._isHeaderRecord(record)) | |
| 249 return this._headerTitles[entryIndex] | |
| 250 return record.name; | |
| 251 }, | |
| 252 | |
| 253 /** | |
| 254 * @param {number} startTime | |
| 255 * @param {number} endTime | |
| 256 * @return {?Array.<number>} | |
| 257 */ | |
| 258 dividerOffsets: function(startTime, endTime) | |
| 259 { | |
| 260 return null; | |
| 261 }, | |
| 262 | |
| 263 reset: function() | |
| 264 { | |
| 265 this._timelineData = null; | |
| 266 /** @type {!Array.<!WebInspector.TracingModel.Event>} */ | |
| 267 this._records = []; | |
| 268 }, | |
| 269 | |
| 270 /** | |
| 271 * @return {!WebInspector.FlameChart.TimelineData} | |
| 272 */ | |
| 273 timelineData: function() | |
| 274 { | |
| 275 if (this._timelineData) | |
| 276 return this._timelineData; | |
| 277 | |
| 278 /** | |
| 279 * @type {?WebInspector.FlameChart.TimelineData} | |
| 280 */ | |
| 281 this._timelineData = { | |
| 282 entryLevels: [], | |
| 283 entryTotalTimes: [], | |
| 284 entryStartTimes: [] | |
| 285 }; | |
| 286 | |
| 287 this._currentLevel = 0; | |
| 288 this._headerTitles = {}; | |
| 289 this._minimumBoundary = this._timelineModelForMinimumBoundary.minimumRec
ordTime(); | |
| 290 this._timeSpan = Math.max(this._model.maximumRecordTime() - this._minimu
mBoundary, 1000); | |
| 291 var processes = this._model.sortedProcesses(); | |
| 292 for (var processIndex = 0; processIndex < processes.length; ++processInd
ex) { | |
| 293 var process = processes[processIndex]; | |
| 294 this._appendHeaderRecord(process.name(), this._processHeaderRecord); | |
| 295 var objectNames = process.sortedObjectNames(); | |
| 296 for (var objectNameIndex = 0; objectNameIndex < objectNames.length;
++objectNameIndex) { | |
| 297 this._appendHeaderRecord(WebInspector.UIString("Object %s", obje
ctNames[objectNameIndex]), this._threadHeaderRecord); | |
| 298 var objects = process.objectsByName(objectNames[objectNameIndex]
); | |
| 299 for (var objectIndex = 0; objectIndex < objects.length; ++object
Index) | |
| 300 this._appendRecord(objects[objectIndex], 0); | |
| 301 ++this._currentLevel; | |
| 302 } | |
| 303 var threads = process.sortedThreads(); | |
| 304 for (var threadIndex = 0; threadIndex < threads.length; ++threadInde
x) { | |
| 305 this._appendHeaderRecord(threads[threadIndex].name(), this._thre
adHeaderRecord); | |
| 306 var events = threads[threadIndex].events(); | |
| 307 for (var eventIndex = 0; eventIndex < events.length; ++eventInde
x) { | |
| 308 var event = events[eventIndex]; | |
| 309 if (event.duration) | |
| 310 this._appendRecord(event, event.level); | |
| 311 } | |
| 312 this._currentLevel += threads[threadIndex].maxStackDepth(); | |
| 313 } | |
| 314 ++this._currentLevel; | |
| 315 } | |
| 316 return this._timelineData; | |
| 317 }, | |
| 318 | |
| 319 /** | |
| 320 * @return {number} | |
| 321 */ | |
| 322 minimumBoundary: function() | |
| 323 { | |
| 324 return this._minimumBoundary; | |
| 325 }, | |
| 326 | |
| 327 /** | |
| 328 * @return {number} | |
| 329 */ | |
| 330 totalTime: function() | |
| 331 { | |
| 332 return this._timeSpan; | |
| 333 }, | |
| 334 | |
| 335 /** | |
| 336 * @return {number} | |
| 337 */ | |
| 338 maxStackDepth: function() | |
| 339 { | |
| 340 return this._currentLevel; | |
| 341 }, | |
| 342 | |
| 343 /** | |
| 344 * @param {number} entryIndex | |
| 345 * @return {?Array.<!{title: string, text: string}>} | |
| 346 */ | |
| 347 prepareHighlightedEntryInfo: function(entryIndex) | |
| 348 { | |
| 349 return null; | |
| 350 }, | |
| 351 | |
| 352 /** | |
| 353 * @param {number} entryIndex | |
| 354 * @return {boolean} | |
| 355 */ | |
| 356 canJumpToEntry: function(entryIndex) | |
| 357 { | |
| 358 var record = this._records[entryIndex]; | |
| 359 return record.phase === WebInspector.TracingModel.Phase.SnapshotObject; | |
| 360 }, | |
| 361 | |
| 362 /** | |
| 363 * @param {number} entryIndex | |
| 364 * @return {string} | |
| 365 */ | |
| 366 entryColor: function(entryIndex) | |
| 367 { | |
| 368 var record = this._records[entryIndex]; | |
| 369 if (record.phase === WebInspector.TracingModel.Phase.SnapshotObject) | |
| 370 return "rgb(20, 150, 20)"; | |
| 371 if (record === this._processHeaderRecord) | |
| 372 return "#555"; | |
| 373 if (record === this._threadHeaderRecord) | |
| 374 return "#777"; | |
| 375 return this._palette.colorForString(record.name); | |
| 376 }, | |
| 377 | |
| 378 /** | |
| 379 * @param {number} entryIndex | |
| 380 * @param {!CanvasRenderingContext2D} context | |
| 381 * @param {?string} text | |
| 382 * @param {number} barX | |
| 383 * @param {number} barY | |
| 384 * @param {number} barWidth | |
| 385 * @param {number} barHeight | |
| 386 * @param {function(number):number} timeToPosition | |
| 387 * @return {boolean} | |
| 388 */ | |
| 389 decorateEntry: function(entryIndex, context, text, barX, barY, barWidth, bar
Height, timeToPosition) | |
| 390 { | |
| 391 return false; | |
| 392 }, | |
| 393 | |
| 394 /** | |
| 395 * @param {number} entryIndex | |
| 396 * @return {boolean} | |
| 397 */ | |
| 398 forceDecoration: function(entryIndex) | |
| 399 { | |
| 400 return false; | |
| 401 }, | |
| 402 | |
| 403 /** | |
| 404 * @param {number} entryIndex | |
| 405 * @return {?{startTime: number, endTime: number}} | |
| 406 */ | |
| 407 highlightTimeRange: function(entryIndex) | |
| 408 { | |
| 409 var record = this._records[entryIndex]; | |
| 410 if (!record || this._isHeaderRecord(record)) | |
| 411 return null; | |
| 412 return { | |
| 413 startTime: record.startTime, | |
| 414 endTime: record.endTime | |
| 415 } | |
| 416 }, | |
| 417 | |
| 418 /** | |
| 419 * @return {number} | |
| 420 */ | |
| 421 paddingLeft: function() | |
| 422 { | |
| 423 return 0; | |
| 424 }, | |
| 425 | |
| 426 /** | |
| 427 * @param {number} entryIndex | |
| 428 * @return {string} | |
| 429 */ | |
| 430 textColor: function(entryIndex) | |
| 431 { | |
| 432 return "white"; | |
| 433 }, | |
| 434 | |
| 435 /** | |
| 436 * @param {string} title | |
| 437 * @param {!WebInspector.TracingModel.Event} record | |
| 438 */ | |
| 439 _appendHeaderRecord: function(title, record) | |
| 440 { | |
| 441 var index = this._records.length; | |
| 442 this._records.push(record); | |
| 443 this._timelineData.entryLevels[index] = this._currentLevel++; | |
| 444 this._timelineData.entryTotalTimes[index] = this.totalTime(); | |
| 445 this._timelineData.entryStartTimes[index] = this._minimumBoundary; | |
| 446 this._headerTitles[index] = title; | |
| 447 }, | |
| 448 | |
| 449 /** | |
| 450 * @param {!WebInspector.TracingModel.Event} record | |
| 451 * @param {number} level | |
| 452 */ | |
| 453 _appendRecord: function(record, level) | |
| 454 { | |
| 455 var index = this._records.length; | |
| 456 this._records.push(record); | |
| 457 this._timelineData.entryLevels[index] = this._currentLevel + level; | |
| 458 this._timelineData.entryTotalTimes[index] = record.phase === WebInspecto
r.TracingModel.Phase.SnapshotObject ? NaN : record.duration || 0; | |
| 459 this._timelineData.entryStartTimes[index] = record.startTime; | |
| 460 }, | |
| 461 | |
| 462 /** | |
| 463 * @param {!WebInspector.TracingModel.Event} record | |
| 464 */ | |
| 465 _isHeaderRecord: function(record) | |
| 466 { | |
| 467 return record === this._threadHeaderRecord || record === this._processHe
aderRecord; | |
| 468 }, | |
| 469 | |
| 470 /** | |
| 471 * @param {number} index | |
| 472 * @return {!WebInspector.TracingModel.Event|undefined} | |
| 473 */ | |
| 474 _recordAt: function(index) | |
| 475 { | |
| 476 return this._records[index]; | |
| 477 } | |
| 478 } | |
| 479 | |
| 480 // The below logic is shamelessly stolen from https://code.google.com/p/trace-vi
ewer/source/browse/trunk/trace_viewer/tracing/color_scheme.js | |
| 481 | |
| 482 /** | |
| 483 * @constructor | |
| 484 */ | |
| 485 WebInspector.TraceViewPalette = function() | |
| 486 { | |
| 487 this._palette = WebInspector.TraceViewPalette._paletteBase.map(WebInspector.
TraceViewPalette._rgbToString); | |
| 488 } | |
| 489 | |
| 490 WebInspector.TraceViewPalette._paletteBase = [ | |
| 491 [138, 113, 152], | |
| 492 [175, 112, 133], | |
| 493 [127, 135, 225], | |
| 494 [93, 81, 137], | |
| 495 [116, 143, 119], | |
| 496 [178, 214, 122], | |
| 497 [87, 109, 147], | |
| 498 [119, 155, 95], | |
| 499 [114, 180, 160], | |
| 500 [132, 85, 103], | |
| 501 [157, 210, 150], | |
| 502 [148, 94, 86], | |
| 503 [164, 108, 138], | |
| 504 [139, 191, 150], | |
| 505 [110, 99, 145], | |
| 506 [80, 129, 109], | |
| 507 [125, 140, 149], | |
| 508 [93, 124, 132], | |
| 509 [140, 85, 140], | |
| 510 [104, 163, 162], | |
| 511 [132, 141, 178], | |
| 512 [131, 105, 147], | |
| 513 [135, 183, 98], | |
| 514 [152, 134, 177], | |
| 515 [141, 188, 141], | |
| 516 [133, 160, 210], | |
| 517 [126, 186, 148], | |
| 518 [112, 198, 205], | |
| 519 [180, 122, 195], | |
| 520 [203, 144, 152] | |
| 521 ]; | |
| 522 | |
| 523 /** | |
| 524 * @param {string} string | |
| 525 * @return {number} | |
| 526 */ | |
| 527 WebInspector.TraceViewPalette._stringHash = function(string) | |
| 528 { | |
| 529 var hash = 0; | |
| 530 for (var i = 0; i < string.length; ++i) | |
| 531 hash = (hash + 37 * hash + 11 * string.charCodeAt(i)) % 0xFFFFFFFF; | |
| 532 return hash; | |
| 533 } | |
| 534 | |
| 535 /** | |
| 536 * @param {!Array.<number>} rgb | |
| 537 * @return {string} | |
| 538 */ | |
| 539 WebInspector.TraceViewPalette._rgbToString = function(rgb) | |
| 540 { | |
| 541 return "rgb(" + rgb.join(",") + ")"; | |
| 542 } | |
| 543 | |
| 544 WebInspector.TraceViewPalette.prototype = { | |
| 545 /** | |
| 546 * @param {string} string | |
| 547 * @return {string} | |
| 548 */ | |
| 549 colorForString: function(string) | |
| 550 { | |
| 551 var hash = WebInspector.TraceViewPalette._stringHash(string); | |
| 552 return this._palette[hash % this._palette.length]; | |
| 553 } | |
| 554 }; | |
| OLD | NEW |