2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 importScript("../sdk/CPUProfileModel.js");
33 importScript("CountersGraph.js");
34 importScript("Layers3DView.js");
35 importScript("MemoryCountersGraph.js");
36 importScript("TimelineModel.js");
37 importScript("TimelineModelImpl.js");
38 importScript("TimelineJSProfile.js");
39 importScript("TimelineOverviewPane.js");
40 importScript("TimelinePresentationModel.js");
41 importScript("TracingTimelineModel.js");
42 importScript("TimelineFrameModel.js");
43 importScript("TimelineEventOverview.js");
44 importScript("TimelineFrameOverview.js");
45 importScript("TimelineMemoryOverview.js");
46 importScript("TimelinePowerGraph.js");
47 importScript("TimelinePowerOverview.js");
48 importScript("TimelineFlameChart.js");
49 importScript("TimelineUIUtils.js");
50 importScript("TimelineUIUtilsImpl.js");
51 importScript("TimelineView.js");
52 importScript("TimelineTracingView.js");
53 importScript("TimelineLayersView.js");
54 importScript("TracingModel.js");
55 importScript("TracingTimelineUIUtils.js");
56 importScript("TransformController.js");
60 * @extends {WebInspector.Panel}
61 * @implements {WebInspector.TimelineModeViewDelegate}
62 * @implements {WebInspector.Searchable}
64 WebInspector.TimelinePanel = function()
66 WebInspector.Panel.call(this, "timeline");
67 this.registerRequiredCSS("timelinePanel.css");
68 this.registerRequiredCSS("layersPanel.css");
69 this.registerRequiredCSS("filter.css");
70 this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
72 this._detailsLinkifier = new WebInspector.Linkifier();
73 this._windowStartTime = 0;
74 this._windowEndTime = Infinity;
77 if (WebInspector.experimentsSettings.timelineTracingMode.isEnabled() ||
78 WebInspector.experimentsSettings.timelineOnTraceEvents.isEnabled()) {
79 this._tracingModel = new WebInspector.TracingModel(WebInspector.targetManager.activeTarget());
80 this._tracingModel.addEventListener(WebInspector.TracingModel.Events.BufferUsage, this._onTracingBufferUsage, this);
82 this._tracingTimelineModel = new WebInspector.TracingTimelineModel(this._tracingModel);
83 this._model = this._tracingTimelineModel;
84 this._uiUtils = new WebInspector.TracingTimelineUIUtils();
86 this._model = new WebInspector.TimelineModelImpl(WebInspector.timelineManager);
87 this._uiUtils = new WebInspector.TimelineUIUtilsImpl();
90 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingStarted, this._onRecordingStarted, this);
91 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingStopped, this._onRecordingStopped, this);
92 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
93 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingProgress, this._onRecordingProgress, this);
94 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordFilterChanged, this._refreshViews, this);
95 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this);
97 this._model.target().profilingLock.addEventListener(WebInspector.Lock.Events.StateChanged, this._onProfilingStateChanged, this);
99 this._categoryFilter = new WebInspector.TimelineCategoryFilter();
100 this._durationFilter = new WebInspector.TimelineIsLongFilter();
101 this._textFilter = new WebInspector.TimelineTextFilter(this._uiUtils);
103 this._model.addFilter(new WebInspector.TimelineHiddenFilter());
104 this._model.addFilter(this._categoryFilter);
105 this._model.addFilter(this._durationFilter);
106 this._model.addFilter(this._textFilter);
108 /** @type {!Array.<!WebInspector.TimelineModeView>} */
109 this._currentViews = [];
111 this._overviewModeSetting = WebInspector.settings.createSetting("timelineOverviewMode", WebInspector.TimelinePanel.OverviewMode.Events);
112 this._flameChartEnabledSetting = WebInspector.settings.createSetting("timelineFlameChartEnabled", false);
113 this._createStatusBarItems();
115 this._topPane = new WebInspector.SplitView(true, false);
116 this._topPane.element.id = "timeline-overview-panel";
117 this._topPane.show(this.element);
118 this._topPane.addEventListener(WebInspector.SplitView.Events.SidebarSizeChanged, this._sidebarResized, this);
119 this._topPane.setResizable(false);
120 this._createRecordingOptions();
122 // Create top overview component.
123 this._overviewPane = new WebInspector.TimelineOverviewPane(this._model, this._uiUtils);
124 this._overviewPane.addEventListener(WebInspector.TimelineOverviewPane.Events.WindowChanged, this._onWindowChanged.bind(this));
125 this._overviewPane.show(this._topPane.mainElement());
127 this._createFileSelector();
128 this._registerShortcuts();
130 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._willReloadPage, this);
131 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
133 // Create top level properties splitter.
134 this._detailsSplitView = new WebInspector.SplitView(false, true, "timelinePanelDetailsSplitViewState");
135 this._detailsSplitView.element.classList.add("timeline-details-split");
136 this._detailsSplitView.sidebarElement().classList.add("timeline-details");
137 this._detailsView = new WebInspector.TimelineDetailsView();
138 this._detailsSplitView.installResizer(this._detailsView.headerElement());
139 this._detailsView.show(this._detailsSplitView.sidebarElement());
141 this._searchableView = new WebInspector.SearchableView(this);
142 this._searchableView.setMinimumSize(0, 25);
143 this._searchableView.element.classList.add("searchable-view");
144 this._searchableView.show(this._detailsSplitView.mainElement());
146 this._stackView = new WebInspector.StackView(false);
147 this._stackView.show(this._searchableView.element);
148 this._stackView.element.classList.add("timeline-view-stack");
150 WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this));
151 WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this));
152 this._dockSideChanged();
154 this._onModeChanged();
155 this._detailsSplitView.show(this.element);
158 WebInspector.TimelinePanel.OverviewMode = {
163 // Define row and header height, should be in sync with styles for timeline graphs.
164 WebInspector.TimelinePanel.rowHeight = 18;
165 WebInspector.TimelinePanel.headerHeight = 20;
167 WebInspector.TimelinePanel.durationFilterPresetsMs = [0, 1, 15];
169 WebInspector.TimelinePanel.prototype = {
171 * @return {?WebInspector.SearchableView}
173 searchableView: function()
175 return this._searchableView;
180 if (!WebInspector.TimelinePanel._categoryStylesInitialized) {
181 WebInspector.TimelinePanel._categoryStylesInitialized = true;
182 var style = document.createElement("style");
183 var categories = WebInspector.TimelineUIUtils.categories();
184 style.textContent = Object.values(categories).map(WebInspector.TimelineUIUtils.createStyleRuleForCategory).join("\n");
185 document.head.appendChild(style);
189 _dockSideChanged: function()
191 var dockSide = WebInspector.dockController.dockSide();
192 var vertically = false;
193 if (dockSide === WebInspector.DockController.State.DockedToBottom)
196 vertically = !WebInspector.settings.splitVerticallyWhenDockedToRight.get();
197 this._detailsSplitView.setVertical(vertically);
198 this._detailsView.setVertical(vertically);
204 windowStartTime: function()
206 if (this._windowStartTime)
207 return this._windowStartTime;
208 return this._model.minimumRecordTime();
214 windowEndTime: function()
216 if (this._windowEndTime < Infinity)
217 return this._windowEndTime;
218 return this._model.maximumRecordTime() || Infinity;
222 * @param {!WebInspector.Event} event
224 _sidebarResized: function(event)
226 var width = /** @type {number} */ (event.data);
227 this._topPane.setSidebarSize(width);
228 for (var i = 0; i < this._currentViews.length; ++i)
229 this._currentViews[i].setSidebarSize(width);
233 * @param {!WebInspector.Event} event
235 _onWindowChanged: function(event)
237 this._windowStartTime = event.data.startTime;
238 this._windowEndTime = event.data.endTime;
240 for (var i = 0; i < this._currentViews.length; ++i)
241 this._currentViews[i].setWindowTimes(this._windowStartTime, this._windowEndTime);
242 this._updateSelectedRangeStats();
246 * @param {number} windowStartTime
247 * @param {number} windowEndTime
249 requestWindowTimes: function(windowStartTime, windowEndTime)
251 this._overviewPane.requestWindowTimes(windowStartTime, windowEndTime);
255 * @return {!WebInspector.TimelineFrameModelBase}
257 _frameModel: function()
259 if (this._lazyFrameModel)
260 return this._lazyFrameModel;
261 if (this._tracingModel) {
262 var tracingFrameModel = new WebInspector.TracingTimelineFrameModel(this._model.target());
263 tracingFrameModel.addTraceEvents(this._tracingTimelineModel.inspectedTargetEvents(), this._tracingModel.sessionId() || "");
264 this._lazyFrameModel = tracingFrameModel;
266 var frameModel = new WebInspector.TimelineFrameModel(this._model.target());
267 frameModel.setMergeRecords(!WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled() || !this._recordingInProgress);
268 frameModel.addRecords(this._model.records());
269 this._lazyFrameModel = frameModel;
271 return this._lazyFrameModel;
275 * @return {!WebInspector.TimelineView}
277 _timelineView: function()
279 if (!this._lazyTimelineView)
280 this._lazyTimelineView = new WebInspector.TimelineView(this, this._model, this._uiUtils);
281 return this._lazyTimelineView;
285 * @return {!WebInspector.View}
287 _layersView: function()
289 if (this._lazyLayersView)
290 return this._lazyLayersView;
291 this._lazyLayersView = new WebInspector.TimelineLayersView();
292 return this._lazyLayersView;
296 * @param {!WebInspector.TimelineModeView} modeView
298 _addModeView: function(modeView)
300 modeView.setWindowTimes(this.windowStartTime(), this.windowEndTime());
301 modeView.refreshRecords(this._textFilter._regex);
302 modeView.view().setSidebarSize(this._topPane.sidebarSize());
303 this._stackView.appendView(modeView.view(), "timelinePanelTimelineStackSplitViewState");
304 modeView.view().addEventListener(WebInspector.SplitView.Events.SidebarSizeChanged, this._sidebarResized, this);
305 this._currentViews.push(modeView);
308 _removeAllModeViews: function()
310 for (var i = 0; i < this._currentViews.length; ++i) {
311 this._currentViews[i].removeEventListener(WebInspector.SplitView.Events.SidebarSizeChanged, this._sidebarResized, this);
312 this._currentViews[i].dispose();
314 this._currentViews = [];
315 this._stackView.detachChildViews();
318 _createRecordingOptions: function()
320 var topPaneSidebarElement = this._topPane.sidebarElement();
322 this._captureStacksSetting = WebInspector.settings.createSetting("timelineCaptureStacks", true);
323 topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture stacks"),
324 this._captureStacksSetting, true, undefined,
325 WebInspector.UIString("Capture JavaScript stack on every timeline event")));
327 this._captureMemorySetting = WebInspector.settings.createSetting("timelineCaptureMemory", false);
328 topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture memory"),
329 this._captureMemorySetting, true, undefined,
330 WebInspector.UIString("Capture memory information on every timeline event")));
331 this._captureMemorySetting.addChangeListener(this._onModeChanged, this);
333 if (Capabilities.canProfilePower) {
334 this._capturePowerSetting = WebInspector.settings.createSetting("timelineCapturePower", false);
335 topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture power"),
336 this._capturePowerSetting, true, undefined,
337 WebInspector.UIString("Capture power information")));
338 this._capturePowerSetting.addChangeListener(this._onModeChanged, this);
341 if (WebInspector.experimentsSettings.timelineTracingMode.isEnabled()) {
342 this._captureTracingSetting = WebInspector.settings.createSetting("timelineCaptureTracing", false);
343 topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture tracing"),
344 this._captureTracingSetting, true, undefined,
345 WebInspector.UIString("Capture tracing information")));
346 this._captureTracingSetting.addChangeListener(this._onModeChanged, this);
347 } else if (WebInspector.experimentsSettings.timelineOnTraceEvents.isEnabled()) {
348 this._captureLayersAndPicturesSetting = WebInspector.settings.createSetting("timelineCaptureLayersAndPictures", false);
349 topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture pictures"),
350 this._captureLayersAndPicturesSetting, true, undefined,
351 WebInspector.UIString("Capture graphics layer positions and painted pictures")));
355 _createStatusBarItems: function()
357 var panelStatusBarElement = this.element.createChild("div", "panel-status-bar");
358 this._statusBarButtons = /** @type {!Array.<!WebInspector.StatusBarItem>} */ ([]);
360 this.toggleTimelineButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
361 this.toggleTimelineButton.addEventListener("click", this._toggleTimelineButtonClicked, this);
362 this._statusBarButtons.push(this.toggleTimelineButton);
363 panelStatusBarElement.appendChild(this.toggleTimelineButton.element);
364 this._updateToggleTimelineButton(false);
366 var clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item");
367 clearButton.addEventListener("click", this._onClearButtonClick, this);
368 this._statusBarButtons.push(clearButton);
369 panelStatusBarElement.appendChild(clearButton.element);
371 this._filterBar = this._createFilterBar();
372 panelStatusBarElement.appendChild(this._filterBar.filterButton().element);
374 var garbageCollectButton = new WebInspector.StatusBarButton(WebInspector.UIString("Collect Garbage"), "timeline-garbage-collect-status-bar-item");
375 garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
376 this._statusBarButtons.push(garbageCollectButton);
377 panelStatusBarElement.appendChild(garbageCollectButton.element);
379 var framesToggleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Frames mode"), "timeline-frames-status-bar-item");
380 framesToggleButton.toggled = this._overviewModeSetting.get() === WebInspector.TimelinePanel.OverviewMode.Frames;
381 framesToggleButton.addEventListener("click", this._overviewModeChanged.bind(this, framesToggleButton));
382 this._statusBarButtons.push(framesToggleButton);
383 panelStatusBarElement.appendChild(framesToggleButton.element);
385 if (WebInspector.experimentsSettings.timelineFlameChart.isEnabled()) {
386 var flameChartToggleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Tracing mode"), "timeline-flame-chart-status-bar-item");
387 flameChartToggleButton.toggled = this._flameChartEnabledSetting.get();
388 flameChartToggleButton.addEventListener("click", this._flameChartEnabledChanged.bind(this, flameChartToggleButton));
389 this._statusBarButtons.push(flameChartToggleButton);
390 panelStatusBarElement.appendChild(flameChartToggleButton.element);
393 this._miscStatusBarItems = panelStatusBarElement.createChild("div", "status-bar-item");
395 this._filtersContainer = this.element.createChild("div", "timeline-filters-header hidden");
396 this._filtersContainer.appendChild(this._filterBar.filtersElement());
397 this._filterBar.addEventListener(WebInspector.FilterBar.Events.FiltersToggled, this._onFiltersToggled, this);
398 this._filterBar.setName("timelinePanel");
402 * @return {!WebInspector.FilterBar}
404 _createFilterBar: function()
406 this._filterBar = new WebInspector.FilterBar();
408 this._filters._textFilterUI = new WebInspector.TextFilterUI();
409 this._filters._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._textFilterChanged, this);
410 this._filterBar.addFilter(this._filters._textFilterUI);
412 var durationOptions = [];
413 for (var presetIndex = 0; presetIndex < WebInspector.TimelinePanel.durationFilterPresetsMs.length; ++presetIndex) {
414 var durationMs = WebInspector.TimelinePanel.durationFilterPresetsMs[presetIndex];
415 var durationOption = {};
417 durationOption.label = WebInspector.UIString("All");
418 durationOption.title = WebInspector.UIString("Show all records");
420 durationOption.label = WebInspector.UIString("\u2265 %dms", durationMs);
421 durationOption.title = WebInspector.UIString("Hide records shorter than %dms", durationMs);
423 durationOption.value = durationMs;
424 durationOptions.push(durationOption);
426 this._filters._durationFilterUI = new WebInspector.ComboBoxFilterUI(durationOptions);
427 this._filters._durationFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._durationFilterChanged, this);
428 this._filterBar.addFilter(this._filters._durationFilterUI);
430 this._filters._categoryFiltersUI = {};
431 var categoryTypes = [];
432 var categories = WebInspector.TimelineUIUtils.categories();
433 for (var categoryName in categories) {
434 var category = categories[categoryName];
435 if (category.overviewStripGroupIndex < 0)
437 var filter = new WebInspector.CheckboxFilterUI(category.name, category.title);
438 this._filters._categoryFiltersUI[category.name] = filter;
439 filter.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._categoriesFilterChanged.bind(this, categoryName), this);
440 this._filterBar.addFilter(filter);
442 return this._filterBar;
445 _textFilterChanged: function(event)
447 var searchQuery = this._filters._textFilterUI.value();
448 this.searchCanceled();
449 this._textFilter.setRegex(searchQuery ? createPlainTextSearchRegex(searchQuery, "i") : null);
452 _durationFilterChanged: function()
454 var duration = this._filters._durationFilterUI.value();
455 var minimumRecordDuration = parseInt(duration, 10);
456 this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);
459 _categoriesFilterChanged: function(name, event)
461 var categories = WebInspector.TimelineUIUtils.categories();
462 categories[name].hidden = !this._filters._categoryFiltersUI[name].checked();
463 this._categoryFilter.notifyFilterChanged();
469 defaultFocusedElement: function()
474 _onFiltersToggled: function(event)
476 var toggled = /** @type {boolean} */ (event.data);
477 this._filtersContainer.classList.toggle("hidden", !toggled);
482 * @return {?WebInspector.ProgressIndicator}
484 _prepareToLoadTimeline: function()
486 if (this._operationInProgress)
488 if (this._recordingInProgress()) {
489 this._updateToggleTimelineButton(false);
490 this._stopRecording();
492 var progressIndicator = new WebInspector.ProgressIndicator();
493 progressIndicator.addEventListener(WebInspector.Progress.Events.Done, this._setOperationInProgress.bind(this, null));
494 this._setOperationInProgress(progressIndicator);
495 return progressIndicator;
499 * @param {?WebInspector.ProgressIndicator} indicator
501 _setOperationInProgress: function(indicator)
503 this._operationInProgress = !!indicator;
504 for (var i = 0; i < this._statusBarButtons.length; ++i)
505 this._statusBarButtons[i].setEnabled(!this._operationInProgress);
506 this._miscStatusBarItems.removeChildren();
508 this._miscStatusBarItems.appendChild(indicator.element);
511 _registerShortcuts: function()
513 this.registerShortcuts(WebInspector.ShortcutsScreen.TimelinePanelShortcuts.StartStopRecording, this._toggleTimelineButtonClicked.bind(this));
514 this.registerShortcuts(WebInspector.ShortcutsScreen.TimelinePanelShortcuts.SaveToFile, this._saveToFile.bind(this));
515 this.registerShortcuts(WebInspector.ShortcutsScreen.TimelinePanelShortcuts.LoadFromFile, this._selectFileToLoad.bind(this));
518 _createFileSelector: function()
520 if (this._fileSelectorElement)
521 this._fileSelectorElement.remove();
523 this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
524 this.element.appendChild(this._fileSelectorElement);
527 _contextMenu: function(event)
529 var contextMenu = new WebInspector.ContextMenu(event);
530 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save Timeline data\u2026" : "Save Timeline Data\u2026"), this._saveToFile.bind(this), this._operationInProgress);
531 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Load Timeline data\u2026" : "Load Timeline Data\u2026"), this._selectFileToLoad.bind(this), this._operationInProgress);
538 _saveToFile: function()
540 if (this._operationInProgress)
542 this._model.saveToFile();
549 _selectFileToLoad: function() {
550 this._fileSelectorElement.click();
555 * @param {!File} file
557 _loadFromFile: function(file)
559 var progressIndicator = this._prepareToLoadTimeline();
560 if (!progressIndicator)
562 this._model.loadFromFile(file, progressIndicator);
563 this._createFileSelector();
567 * @param {string} url
569 loadFromURL: function(url)
571 var progressIndicator = this._prepareToLoadTimeline();
572 if (!progressIndicator)
574 this._model.loadFromURL(url, progressIndicator);
577 _refreshViews: function()
579 for (var i = 0; i < this._currentViews.length; ++i) {
580 var view = this._currentViews[i];
581 view.refreshRecords(this._textFilter._regex);
583 this._updateSelectedRangeStats();
587 * @param {!WebInspector.StatusBarButton} button
589 _overviewModeChanged: function(button)
591 var oldMode = this._overviewModeSetting.get();
592 if (oldMode === WebInspector.TimelinePanel.OverviewMode.Events) {
593 this._overviewModeSetting.set(WebInspector.TimelinePanel.OverviewMode.Frames);
594 button.toggled = true;
596 this._overviewModeSetting.set(WebInspector.TimelinePanel.OverviewMode.Events);
597 button.toggled = false;
599 this._onModeChanged();
603 * @param {!WebInspector.StatusBarButton} button
605 _flameChartEnabledChanged: function(button)
607 var oldValue = this._flameChartEnabledSetting.get();
608 var newValue = !oldValue;
609 this._flameChartEnabledSetting.set(newValue);
610 button.toggled = newValue;
611 this._onModeChanged();
614 _onModeChanged: function()
616 this._stackView.detach();
618 var isFrameMode = this._overviewModeSetting.get() === WebInspector.TimelinePanel.OverviewMode.Frames;
619 this._removeAllModeViews();
620 this._overviewControls = [];
623 this._overviewControls.push(new WebInspector.TimelineFrameOverview(this._model, this._frameModel()));
625 this._overviewControls.push(new WebInspector.TimelineEventOverview(this._model, this._uiUtils));
627 if (WebInspector.experimentsSettings.timelineFlameChart.isEnabled() && this._flameChartEnabledSetting.get()) {
628 var tracingTimelineModel = WebInspector.experimentsSettings.timelineOnTraceEvents.isEnabled() ? this._tracingTimelineModel : null;
629 this._addModeView(new WebInspector.TimelineFlameChart(this, this._model, tracingTimelineModel, this._frameModel()));
631 this._addModeView(this._timelineView());
634 if (this._captureMemorySetting.get()) {
635 if (!isFrameMode) // Frame mode skews time, don't render aux overviews.
636 this._overviewControls.push(new WebInspector.TimelineMemoryOverview(this._model, this._uiUtils));
637 this._addModeView(new WebInspector.MemoryCountersGraph(this, this._model, this._uiUtils));
640 if (this._capturePowerSetting && this._capturePowerSetting.get()) {
641 if (!isFrameMode) // Frame mode skews time, don't render aux overviews.
642 this._overviewControls.push(new WebInspector.TimelinePowerOverview(this._model));
643 this._addModeView(new WebInspector.TimelinePowerGraph(this, this._model));
646 if (this._captureTracingSetting && this._captureTracingSetting.get())
647 this._addModeView(new WebInspector.TimelineTracingView(this, this._tracingModel, this._model));
649 this._timelineView().setFrameModel(isFrameMode ? this._frameModel() : null);
650 this._overviewPane.setOverviewControls(this._overviewControls);
652 this._updateSelectedRangeStats();
654 this._stackView.show(this._searchableView.element);
658 * @param {boolean} userInitiated
660 _startRecording: function(userInitiated)
662 this._userInitiatedRecording = userInitiated;
663 this._model.startRecording(this._captureStacksSetting.get(), this._captureMemorySetting.get(), this._captureLayersAndPicturesSetting && this._captureLayersAndPicturesSetting.get());
664 if (WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled() && this._lazyFrameModel)
665 this._lazyFrameModel.setMergeRecords(false);
667 for (var i = 0; i < this._overviewControls.length; ++i)
668 this._overviewControls[i].timelineStarted();
671 WebInspector.userMetrics.TimelineStarted.record();
674 _stopRecording: function()
676 this._stopPending = true;
677 this._updateToggleTimelineButton(false);
678 this._userInitiatedRecording = false;
679 this._model.stopRecording();
680 if (this._progressElement)
681 this._updateProgress(WebInspector.UIString("Retrieving events\u2026"));
683 for (var i = 0; i < this._overviewControls.length; ++i)
684 this._overviewControls[i].timelineStopped();
687 _onProfilingStateChanged: function()
689 this._updateToggleTimelineButton(this.toggleTimelineButton.toggled);
693 * @param {boolean} toggled
695 _updateToggleTimelineButton: function(toggled)
697 this.toggleTimelineButton.toggled = toggled;
699 this.toggleTimelineButton.title = WebInspector.UIString("Stop");
700 this.toggleTimelineButton.setEnabled(true);
701 } else if (this._stopPending) {
702 this.toggleTimelineButton.title = WebInspector.UIString("Stop pending");
703 this.toggleTimelineButton.setEnabled(false);
704 } else if (this._model.target().profilingLock.isAcquired()) {
705 this.toggleTimelineButton.title = WebInspector.UIString("Another profiler is already active");
706 this.toggleTimelineButton.setEnabled(false);
708 this.toggleTimelineButton.title = WebInspector.UIString("Record");
709 this.toggleTimelineButton.setEnabled(true);
716 _toggleTimelineButtonClicked: function()
718 if (!this.toggleTimelineButton.enabled())
720 if (this._operationInProgress)
722 if (this._recordingInProgress())
723 this._stopRecording();
725 this._startRecording(true);
729 _garbageCollectButtonClicked: function()
731 HeapProfilerAgent.collectGarbage();
734 _onClearButtonClick: function()
736 if (this._tracingModel)
737 this._tracingModel.reset();
741 _onRecordsCleared: function()
743 this.requestWindowTimes(0, Infinity);
744 delete this._selection;
745 if (this._lazyFrameModel)
746 this._lazyFrameModel.reset();
747 for (var i = 0; i < this._currentViews.length; ++i)
748 this._currentViews[i].reset();
749 for (var i = 0; i < this._overviewControls.length; ++i)
750 this._overviewControls[i].reset();
751 this._updateSelectedRangeStats();
754 _onRecordingStarted: function()
756 this._updateToggleTimelineButton(true);
757 if (WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled())
758 this._updateProgress(WebInspector.UIString("%d events collected", 0));
761 _recordingInProgress: function()
763 return this.toggleTimelineButton.toggled;
767 * @param {!WebInspector.Event} event
769 _onRecordingProgress: function(event)
771 if (!WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled())
773 this._updateProgress(WebInspector.UIString("%d events collected", event.data));
777 * @param {!WebInspector.Event} event
779 _onTracingBufferUsage: function(event)
781 var usage = /** @type {number} */ (event.data);
782 this._updateProgress(WebInspector.UIString("Buffer usage %d%", Math.round(usage * 100)));
786 * @param {string} progressMessage
788 _updateProgress: function(progressMessage)
790 if (!this._progressElement)
791 this._showProgressPane();
792 this._progressElement.textContent = progressMessage;
795 _showProgressPane: function()
797 this._hideProgressPane();
798 this._progressElement = this._detailsSplitView.mainElement().createChild("div", "timeline-progress-pane");
801 _hideProgressPane: function()
803 if (this._progressElement)
804 this._progressElement.remove();
805 delete this._progressElement;
808 _onRecordingStopped: function()
810 this._stopPending = false;
811 this._updateToggleTimelineButton(false);
812 if (this._lazyFrameModel) {
813 if (this._tracingTimelineModel) {
814 this._lazyFrameModel.reset();
815 this._lazyFrameModel.addTraceEvents(this._tracingTimelineModel.inspectedTargetEvents(), this._tracingModel.sessionId());
816 this._overviewPane.update();
817 } else if (WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled()) {
818 this._lazyFrameModel.reset();
819 this._lazyFrameModel.addRecords(this._model.records());
822 if (this._tracingTimelineModel) {
823 this.requestWindowTimes(this._tracingTimelineModel.minimumRecordTime(), this._tracingTimelineModel.maximumRecordTime());
824 this._refreshViews();
826 this._hideProgressPane();
829 _onRecordAdded: function(event)
831 this._addRecord(/** @type {!WebInspector.TimelineModel.Record} */(event.data));
835 * @param {!WebInspector.TimelineModel.Record} record
837 _addRecord: function(record)
839 if (this._lazyFrameModel && !this._tracingModel)
840 this._lazyFrameModel.addRecord(record);
841 for (var i = 0; i < this._currentViews.length; ++i)
842 this._currentViews[i].addRecord(record);
843 this._overviewPane.addRecord(record);
844 this._updateSearchHighlight(false, true);
848 * @param {!WebInspector.Event} event
850 _willReloadPage: function(event)
852 if (this._operationInProgress || this._userInitiatedRecording || !this.isShowing())
854 this._startRecording(false);
858 * @param {!WebInspector.Event} event
860 _loadEventFired: function(event)
862 if (!this._recordingInProgress() || this._userInitiatedRecording)
864 this._stopRecording();
867 // WebInspector.Searchable implementation
869 jumpToNextSearchResult: function()
871 if (!this._searchResults || !this._searchResults.length)
873 var index = this._selectedSearchResult ? this._searchResults.indexOf(this._selectedSearchResult) : -1;
874 this._jumpToSearchResult(index + 1);
877 jumpToPreviousSearchResult: function()
879 if (!this._searchResults || !this._searchResults.length)
881 var index = this._selectedSearchResult ? this._searchResults.indexOf(this._selectedSearchResult) : 0;
882 this._jumpToSearchResult(index - 1);
885 _jumpToSearchResult: function(index)
887 this._selectSearchResult((index + this._searchResults.length) % this._searchResults.length);
888 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this._searchRegex, true);
891 _selectSearchResult: function(index)
893 this._selectedSearchResult = this._searchResults[index];
894 this._searchableView.updateCurrentMatchIndex(index);
897 _clearHighlight: function()
899 this._currentViews[0].highlightSearchResult(null);
903 * @param {boolean} revealRecord
904 * @param {boolean} shouldJump
905 * @param {boolean=} jumpBackwards
907 _updateSearchHighlight: function(revealRecord, shouldJump, jumpBackwards)
909 if (!this._textFilter.isEmpty() || !this._searchRegex) {
910 this._clearHighlight();
914 if (!this._searchResults)
915 this._updateSearchResults(shouldJump, jumpBackwards);
916 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this._searchRegex, revealRecord);
920 * @param {boolean} shouldJump
921 * @param {boolean=} jumpBackwards
923 _updateSearchResults: function(shouldJump, jumpBackwards)
925 var searchRegExp = this._searchRegex;
932 * @param {!WebInspector.TimelineModel.Record} record
933 * @this {WebInspector.TimelinePanel}
935 function processRecord(record)
937 if (record.endTime() < this._windowStartTime ||
938 record.startTime() > this._windowEndTime)
940 if (this._uiUtils.testContentMatching(record, searchRegExp))
941 matches.push(record);
943 this._model.forAllFilteredRecords(processRecord.bind(this));
945 var matchesCount = matches.length;
947 this._searchResults = matches;
948 this._searchableView.updateSearchMatchesCount(matchesCount);
950 var selectedIndex = matches.indexOf(this._selectedSearchResult);
951 if (shouldJump && selectedIndex === -1)
952 selectedIndex = jumpBackwards ? this._searchResults.length - 1 : 0;
953 this._selectSearchResult(selectedIndex);
955 this._searchableView.updateSearchMatchesCount(0);
956 delete this._selectedSearchResult;
960 searchCanceled: function()
962 this._clearHighlight();
963 delete this._searchResults;
964 delete this._selectedSearchResult;
965 delete this._searchRegex;
969 * @param {string} query
970 * @param {boolean} shouldJump
971 * @param {boolean=} jumpBackwards
973 performSearch: function(query, shouldJump, jumpBackwards)
975 this._searchRegex = createPlainTextSearchRegex(query, "i");
976 delete this._searchResults;
977 this._updateSearchHighlight(true, shouldJump, jumpBackwards);
980 _updateSelectionDetails: function()
982 if (!this._selection) {
983 this._updateSelectedRangeStats();
986 switch (this._selection.type()) {
987 case WebInspector.TimelineSelection.Type.Record:
988 var record = /** @type {!WebInspector.TimelineModel.Record} */ (this._selection.object());
989 var title = this._uiUtils.titleForRecord(record);
990 this._uiUtils.generateDetailsContent(record, this._model, this._detailsLinkifier, this.showInDetails.bind(this, title), this._model.loadedFromFile());
992 case WebInspector.TimelineSelection.Type.TraceEvent:
993 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._selection.object());
994 var title = WebInspector.TracingTimelineUIUtils.styleForTraceEvent(event.name).title;
995 WebInspector.TracingTimelineUIUtils.buildTraceEventDetails(event, this._tracingTimelineModel, this._detailsLinkifier, this.showInDetails.bind(this, title), false, this._model.target());
997 case WebInspector.TimelineSelection.Type.Frame:
998 var frame = /** @type {!WebInspector.TimelineFrame} */ (this._selection.object());
999 this.showInDetails(WebInspector.UIString("Frame Statistics"), WebInspector.TimelineUIUtils.generateDetailsContentForFrame(this._lazyFrameModel, frame));
1000 if (frame.layerTree) {
1001 var layersView = this._layersView();
1002 layersView.showLayerTree(frame.layerTree);
1003 this._detailsView.appendTab("layers", WebInspector.UIString("Layers"), layersView);
1009 _updateSelectedRangeStats: function()
1011 if (this._selection)
1014 var startTime = this._windowStartTime;
1015 var endTime = this._windowEndTime;
1017 // Return early in case 0 selection window.
1021 var aggregatedStats = {};
1024 * @param {number} value
1025 * @param {!WebInspector.TimelineModel.Record} task
1028 function compareEndTime(value, task)
1030 return value < task.endTime() ? -1 : 1;
1034 * @param {!WebInspector.TimelineModel.Record} record
1036 function aggregateTimeForRecordWithinWindow(record)
1038 if (!record.endTime() || record.endTime() < startTime || record.startTime() > endTime)
1041 var childrenTime = 0;
1042 var children = record.children() || [];
1043 for (var i = 0; i < children.length; ++i) {
1044 var child = children[i];
1045 if (!child.endTime() || child.endTime() < startTime || child.startTime() > endTime)
1047 childrenTime += Math.min(endTime, child.endTime()) - Math.max(startTime, child.startTime());
1048 aggregateTimeForRecordWithinWindow(child);
1050 var categoryName = record.category().name;
1051 var ownTime = Math.min(endTime, record.endTime()) - Math.max(startTime, record.startTime()) - childrenTime;
1052 aggregatedStats[categoryName] = (aggregatedStats[categoryName] || 0) + ownTime;
1055 var mainThreadTasks = this._model.mainThreadTasks();
1056 var taskIndex = insertionIndexForObjectInListSortedByFunction(startTime, mainThreadTasks, compareEndTime);
1057 for (; taskIndex < mainThreadTasks.length; ++taskIndex) {
1058 var task = mainThreadTasks[taskIndex];
1059 if (task.startTime() > endTime)
1061 aggregateTimeForRecordWithinWindow(task);
1064 var aggregatedTotal = 0;
1065 for (var categoryName in aggregatedStats)
1066 aggregatedTotal += aggregatedStats[categoryName];
1067 aggregatedStats["idle"] = Math.max(0, endTime - startTime - aggregatedTotal);
1069 var pieChartContainer = document.createElement("div");
1070 pieChartContainer.classList.add("vbox", "timeline-range-summary");
1071 var startOffset = startTime - this._model.minimumRecordTime();
1072 var endOffset = endTime - this._model.minimumRecordTime();
1073 var title = WebInspector.UIString("Range: %s \u2013 %s", Number.millisToString(startOffset), Number.millisToString(endOffset));
1075 for (var i = 0; i < this._overviewControls.length; ++i) {
1076 if (this._overviewControls[i] instanceof WebInspector.TimelinePowerOverview) {
1077 var energy = this._overviewControls[i].calculateEnergy(startTime, endTime);
1078 title += WebInspector.UIString(" Energy: %.2f Joules", energy);
1082 pieChartContainer.appendChild(document.createTextNode(title));
1083 pieChartContainer.appendChild(WebInspector.TimelineUIUtils.generatePieChart(aggregatedStats));
1084 this.showInDetails(WebInspector.UIString("Selected Range"), pieChartContainer);
1088 * @param {?WebInspector.TimelineSelection} selection
1090 select: function(selection)
1092 this._detailsLinkifier.reset();
1093 this._selection = selection;
1095 for (var i = 0; i < this._currentViews.length; ++i) {
1096 var view = this._currentViews[i];
1097 view.setSelection(selection);
1099 this._updateSelectionDetails();
1103 * @param {string} title
1104 * @param {!Node} node
1106 showInDetails: function(title, node)
1108 this._detailsView.setContent(title, node);
1111 __proto__: WebInspector.Panel.prototype
1116 * @extends {WebInspector.TabbedPane}
1118 WebInspector.TimelineDetailsView = function()
1120 WebInspector.TabbedPane.call(this);
1122 this._defaultDetailsView = new WebInspector.VBox();
1123 this._defaultDetailsView.element.classList.add("timeline-details-view");
1124 this._defaultDetailsContentElement = this._defaultDetailsView.element.createChild("div", "timeline-details-view-body");
1126 this.appendTab("default", WebInspector.UIString("Details"), this._defaultDetailsView);
1128 this.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
1131 WebInspector.TimelineDetailsView.prototype = {
1133 * @param {string} title
1134 * @param {!Node} node
1136 setContent: function(title, node)
1138 this.changeTabTitle("default", WebInspector.UIString("Details: %s", title));
1139 var otherTabs = this.otherTabs("default");
1140 for (var i = 0; i < otherTabs.length; ++i)
1141 this.closeTab(otherTabs[i]);
1142 this._defaultDetailsContentElement.removeChildren();
1143 this._defaultDetailsContentElement.appendChild(node);
1147 * @param {boolean} vertical
1149 setVertical: function(vertical)
1151 this._defaultDetailsContentElement.classList.toggle("hbox", !vertical);
1152 this._defaultDetailsContentElement.classList.toggle("vbox", vertical);
1156 * @param {string} id
1157 * @param {string} tabTitle
1158 * @param {!WebInspector.View} view
1159 * @param {string=} tabTooltip
1161 appendTab: function(id, tabTitle, view, tabTooltip)
1163 WebInspector.TabbedPane.prototype.appendTab.call(this, id, tabTitle, view, tabTooltip);
1164 if (this._lastUserSelectedTabId === id)
1168 _tabSelected: function(event)
1170 if (!event.data.isUserGesture)
1173 this._lastUserSelectedTabId = event.data.tabId;
1176 __proto__: WebInspector.TabbedPane.prototype
1182 WebInspector.TimelineSelection = function()
1189 WebInspector.TimelineSelection.Type = {
1192 TraceEvent: "TraceEvent",
1196 * @param {!WebInspector.TimelineModel.Record} record
1197 * @return {!WebInspector.TimelineSelection}
1199 WebInspector.TimelineSelection.fromRecord = function(record)
1201 var selection = new WebInspector.TimelineSelection();
1202 selection._type = WebInspector.TimelineSelection.Type.Record;
1203 selection._object = record;
1208 * @param {!WebInspector.TimelineFrame} frame
1209 * @return {!WebInspector.TimelineSelection}
1211 WebInspector.TimelineSelection.fromFrame = function(frame)
1213 var selection = new WebInspector.TimelineSelection();
1214 selection._type = WebInspector.TimelineSelection.Type.Frame;
1215 selection._object = frame;
1220 * @param {!WebInspector.TracingModel.Event} event
1221 * @return {!WebInspector.TimelineSelection}
1223 WebInspector.TimelineSelection.fromTraceEvent = function(event)
1225 var selection = new WebInspector.TimelineSelection();
1226 selection._type = WebInspector.TimelineSelection.Type.TraceEvent;
1227 selection._object = event;
1231 WebInspector.TimelineSelection.prototype = {
1233 * @return {!WebInspector.TimelineSelection.Type}
1245 return this._object;
1251 * @extends {WebInspector.EventTarget}
1253 WebInspector.TimelineModeView = function()
1257 WebInspector.TimelineModeView.prototype = {
1259 * @return {!WebInspector.View}
1261 view: function() {},
1263 dispose: function() {},
1265 reset: function() {},
1268 * @param {?RegExp} textFilter
1270 refreshRecords: function(textFilter) {},
1273 * @param {!WebInspector.TimelineModel.Record} record
1275 addRecord: function(record) {},
1278 * @param {?WebInspector.TimelineModel.Record} record
1279 * @param {string=} regex
1280 * @param {boolean=} selectRecord
1282 highlightSearchResult: function(record, regex, selectRecord) {},
1285 * @param {number} startTime
1286 * @param {number} endTime
1288 setWindowTimes: function(startTime, endTime) {},
1291 * @param {number} width
1293 setSidebarSize: function(width) {},
1296 * @param {?WebInspector.TimelineSelection} selection
1298 setSelection: function(selection) {},
1304 WebInspector.TimelineModeViewDelegate = function() {}
1306 WebInspector.TimelineModeViewDelegate.prototype = {
1308 * @param {number} startTime
1309 * @param {number} endTime
1311 requestWindowTimes: function(startTime, endTime) {},
1314 * @param {?WebInspector.TimelineSelection} selection
1316 select: function(selection) {},
1319 * @param {string} title
1320 * @param {!Node} node
1322 showInDetails: function(title, node) {},
1327 * @extends {WebInspector.TimelineModel.Filter}
1329 WebInspector.TimelineCategoryFilter = function()
1331 WebInspector.TimelineModel.Filter.call(this);
1334 WebInspector.TimelineCategoryFilter.prototype = {
1336 * @param {!WebInspector.TimelineModel.Record} record
1339 accept: function(record)
1341 return !record.category().hidden;
1344 __proto__: WebInspector.TimelineModel.Filter.prototype
1349 * @extends {WebInspector.TimelineModel.Filter}
1351 WebInspector.TimelineIsLongFilter = function()
1353 WebInspector.TimelineModel.Filter.call(this);
1354 this._minimumRecordDuration = 0;
1357 WebInspector.TimelineIsLongFilter.prototype = {
1359 * @param {number} value
1361 setMinimumRecordDuration: function(value)
1363 this._minimumRecordDuration = value;
1364 this.notifyFilterChanged();
1368 * @param {!WebInspector.TimelineModel.Record} record
1371 accept: function(record)
1373 return this._minimumRecordDuration ? ((record.endTime() - record.startTime()) >= this._minimumRecordDuration) : true;
1376 __proto__: WebInspector.TimelineModel.Filter.prototype
1382 * @extends {WebInspector.TimelineModel.Filter}
1383 * @param {!WebInspector.TimelineUIUtils} uiUtils
1385 WebInspector.TimelineTextFilter = function(uiUtils)
1387 WebInspector.TimelineModel.Filter.call(this);
1388 this._uiUtils = uiUtils;
1391 WebInspector.TimelineTextFilter.prototype = {
1397 return !this._regex;
1401 * @param {?RegExp} regex
1403 setRegex: function(regex)
1405 this._regex = regex;
1406 this.notifyFilterChanged();
1410 * @param {!WebInspector.TimelineModel.Record} record
1413 accept: function(record)
1415 return !this._regex || this._uiUtils.testContentMatching(record, this._regex);
1418 __proto__: WebInspector.TimelineModel.Filter.prototype
1423 * @extends {WebInspector.TimelineModel.Filter}
1425 WebInspector.TimelineHiddenFilter = function()
1427 WebInspector.TimelineModel.Filter.call(this);
1428 this._hiddenRecords = {};
1429 this._hiddenRecords[WebInspector.TimelineModel.RecordType.MarkDOMContent] = 1;
1430 this._hiddenRecords[WebInspector.TimelineModel.RecordType.MarkLoad] = 1;
1431 this._hiddenRecords[WebInspector.TimelineModel.RecordType.MarkFirstPaint] = 1;
1432 this._hiddenRecords[WebInspector.TimelineModel.RecordType.GPUTask] = 1;
1433 this._hiddenRecords[WebInspector.TimelineModel.RecordType.ScheduleStyleRecalculation] = 1;
1434 this._hiddenRecords[WebInspector.TimelineModel.RecordType.InvalidateLayout] = 1;
1435 this._hiddenRecords[WebInspector.TimelineModel.RecordType.RequestMainThreadFrame] = 1;
1436 this._hiddenRecords[WebInspector.TimelineModel.RecordType.ActivateLayerTree] = 1;
1437 this._hiddenRecords[WebInspector.TimelineModel.RecordType.DrawFrame] = 1;
1438 this._hiddenRecords[WebInspector.TimelineModel.RecordType.BeginFrame] = 1;
1439 this._hiddenRecords[WebInspector.TimelineModel.RecordType.UpdateCounters] = 1;
1442 WebInspector.TimelineHiddenFilter.prototype = {
1444 * @param {!WebInspector.TimelineModel.Record} record
1447 accept: function(record)
1449 return !this._hiddenRecords[record.type()];
1452 __proto__: WebInspector.TimelineModel.Filter.prototype