| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <link rel="import" href="/base/base.html"> |
| <link rel="import" href="/core/auditor.html"> |
| <link rel="import" href="/core/trace_model/event_info.html"> |
| <link rel="import" href="/extras/audits/utils.html"> |
| <link rel="import" href="/extras/audits/chrome_model_helper.html"> |
| <link rel="import" href="/extras/audits/rail_ir_finder.html"> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * @fileoverview Base class for trace data Auditors. |
| */ |
| tv.exportTo('tv.e.audits', function() { |
| var Auditor = tv.c.Auditor; |
| |
| /** |
| * Auditor for Chrome-specific traces. |
| * @constructor |
| */ |
| function ChromeAuditor(model) { |
| this.model = model; |
| if (tv.e.audits.ChromeModelHelper.supportsModel(this.model)) { |
| var modelHelper = new tv.e.audits.ChromeModelHelper(this.model); |
| |
| // Must be a browser in order to do audits. |
| if (modelHelper.browser === undefined) |
| this.modelHelper = undefined; |
| else |
| this.modelHelper = modelHelper; |
| } else { |
| this.modelHelper = undefined; |
| } |
| }; |
| |
| ChromeAuditor.prototype = { |
| __proto__: Auditor.prototype, |
| |
| runAnnotate: function() { |
| if (!this.modelHelper) |
| return; |
| |
| this.model.getAllProcesses().forEach(function(process) { |
| if (process.labels !== undefined && |
| process.labels.length == 1 && |
| process.labels[0] == 'chrome://tracing') |
| process.important = false; |
| }); |
| }, |
| |
| runAudit: function() { |
| if (!this.modelHelper) |
| return; |
| |
| // ChromeAuditor is disabled when used directly inside about://tracing, |
| // for now. |
| if (window.profilingView) |
| return; |
| |
| var allLoadAndNetEvents = this.getAllLoadAndNetEvents(); |
| var allFrameEvents = this.getAllFrameEvents(); |
| var allLatencyEvents = this.getAllLatencyEvents(); |
| var allFrameAndLatencyEvents = []; |
| allFrameAndLatencyEvents.push.apply(allFrameAndLatencyEvents, |
| allFrameEvents); |
| allFrameAndLatencyEvents.push.apply(allFrameAndLatencyEvents, |
| allLatencyEvents); |
| |
| function mergeEventsIntoIR(title, colorId, events) { |
| var e0 = events[0]; |
| var eN = events[events.length - 1]; |
| var ir = new tv.c.trace_model.InteractionRecord( |
| title, colorId, |
| e0.start, eN.end - e0.start); |
| ir.events = events; |
| return ir; |
| } |
| |
| var addIRs = function(records) { |
| records.forEach(function(ir) { |
| this.model.addInteractionRecord(ir); |
| }, this); |
| }.bind(this); |
| |
| var mergedLoadIRs = tv.e.audits.mergeEvents( |
| allLoadAndNetEvents, 300, |
| mergeEventsIntoIR.bind( |
| undefined, 'Loading/Net', |
| tv.b.ui.getColorIdForGeneralPurposeString('mt_loading'))); |
| addIRs(mergedLoadIRs); |
| |
| var mergedFrameIRs = tv.e.audits.mergeEvents( |
| allFrameEvents, 150, |
| mergeEventsIntoIR.bind( |
| undefined, 'Rendering', |
| tv.b.ui.getColorIdForGeneralPurposeString('mt_rendering'))); |
| addIRs(mergedFrameIRs); |
| |
| if (tv.e.audits.RAILIRFinder.supportsModelHelper(this.modelHelper)) { |
| var rirf = new tv.e.audits.RAILIRFinder(this.model, this.modelHelper); |
| var railIRs = rirf.findAllInteractionRecords(); |
| addIRs(railIRs); |
| } |
| |
| this.addBigTaskAlerts(); |
| }, |
| |
| addBigTaskAlerts: function() { |
| var model = this.model; |
| tv.b.iterItems(this.modelHelper.renderers, function(pid, renderer) { |
| var slices = renderer.mainThread.sliceGroup.slices; |
| slices.forEach(function(slice) { |
| if (slice.category != 'toplevel') |
| return; |
| if (slice.duration > 75.0) { |
| var alertInfo = new tv.c.trace_model.EventInfo( |
| 'Task too long', |
| 'Tasks taking >= 75ms are bad, and should be broken up to' + |
| 'ensure the main thread is responsive'); |
| var center = slice.start + 0.5 * slice.duration; |
| var alert = new tv.c.trace_model.Alert( |
| alertInfo, center, [slice]); |
| model.alerts.push(alert); |
| } |
| }); |
| }); |
| }, |
| |
| getAllLoadAndNetEvents: function() { |
| var model = this.model; |
| if (this.modelHelper.browser === undefined) |
| return; |
| var browser = this.modelHelper.browser; |
| |
| var events = []; |
| events.push.apply( |
| events, browser.getLoadingEventsInRange(model.bounds)); |
| events.push.apply( |
| events, browser.getAllNetworkEventsInRange(model.bounds)); |
| return events; |
| }, |
| |
| getAllFrameEvents: function() { |
| var model = this.model; |
| var frameEvents = []; |
| if (this.modelHelper.browser) { |
| var fe = this.modelHelper.browser.getFrameEventsInRange( |
| tv.e.audits.IMPL_FRAMETIME_TYPE, |
| model.bounds); |
| frameEvents.push.apply(frameEvents, fe); |
| } |
| tv.b.iterItems(this.modelHelper.renderers, function(pid, renderer) { |
| var fe = renderer.getFrameEventsInRange(tv.e.audits.IMPL_FRAMETIME_TYPE, |
| model.bounds); |
| frameEvents.push.apply(frameEvents, fe); |
| }, this); |
| frameEvents.sort(function(x, y) { return x.start - y.start; }); |
| return frameEvents; |
| }, |
| |
| getAllLatencyEvents: function() { |
| if (!this.modelHelper.browser) |
| return []; |
| return this.modelHelper.browser.getLatencyEventsInRange( |
| this.model.bounds); |
| } |
| }; |
| |
| Auditor.register(ChromeAuditor); |
| |
| return { |
| ChromeAuditor: ChromeAuditor |
| }; |
| }); |
| </script> |