| <!DOCTYPE html> |
| <!-- |
| Copyright 2016 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="/tracing/base/raf.html"> |
| <link rel="import" href="/tracing/metrics/metric_map_function.html"> |
| <link rel="import" href="/tracing/metrics/metric_registry.html"> |
| <link rel="import" href="/tracing/model/event_set.html"> |
| <link rel="import" href="/tracing/mre/mre_result.html"> |
| <link rel="import" href="/tracing/ui/base/dom_helpers.html"> |
| <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> |
| <link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> |
| <link rel="import" href="/tracing/value/ui/value_set_view.html"> |
| <link rel="import" href="/tracing/value/value_set.html"> |
| |
| <dom-module id="tr-ui-sp-metrics-side-panel"> |
| <template> |
| <style> |
| :host { |
| display: flex; |
| flex-direction: column; |
| } |
| div#error { |
| color: red; |
| } |
| </style> |
| |
| <top-left-controls id="top_left_controls"></top-left-controls> |
| <tr-v-ui-value-set-view id="results"></tr-v-ui-value-set-view> |
| <div id="error"></div> |
| </template> |
| </dom-module> |
| |
| <script> |
| 'use strict'; |
| tr.exportTo('tr.ui', function() { |
| Polymer({ |
| is: 'tr-ui-sp-metrics-side-panel', |
| behaviors: [tr.ui.behaviors.SidePanel], |
| |
| ready: function() { |
| this.model_ = undefined; |
| |
| this.rangeOfInterest_ = undefined; |
| this.metricLatenciesMs_ = []; |
| |
| this.metrics_ = []; |
| tr.metrics.MetricRegistry.getAllRegisteredTypeInfos().forEach( |
| function(m) { |
| if (m.constructor.name === 'sampleMetric') |
| return; |
| this.metrics_.push({ |
| label: m.constructor.name, |
| value: m.constructor.name |
| }); |
| }, this); |
| |
| this.settingsKey_ = 'metrics-side-panel-metric-name'; |
| this.currentMetricName_ = 'systemHealthMetrics'; |
| var metricSelector = tr.ui.b.createSelector( |
| this, 'currentMetricName_', |
| this.settingsKey_, |
| this.currentMetricName_, |
| this.metrics_); |
| Polymer.dom(this.$.top_left_controls).appendChild(metricSelector); |
| metricSelector.addEventListener('change', |
| this.onMetricChange_.bind(this)); |
| this.currentMetricTypeInfo_ = |
| tr.metrics.MetricRegistry.findTypeInfoWithName( |
| this.currentMetricName_); |
| |
| this.recomputeButton_ = tr.ui.b.createButton( |
| 'Recompute', this.onRecompute_, this); |
| Polymer.dom(this.$.top_left_controls).appendChild(this.recomputeButton_); |
| }, |
| |
| /** |
| * Return an estimate of how many milliseconds it would take to re-run the |
| * metric. If the metric has not been run, return undefined. |
| * |
| * @return {undefined|number} |
| */ |
| get metricLatencyMs() { |
| return tr.b.Statistics.mean(this.metricLatenciesMs_); |
| }, |
| |
| onMetricChange_: function() { |
| this.currentMetricTypeInfo_ = |
| tr.metrics.MetricRegistry.findTypeInfoWithName( |
| this.currentMetricName_); |
| this.metricLatenciesMs_ = []; |
| this.updateContents_(); |
| }, |
| |
| onRecompute_: function() { |
| this.updateContents_(); |
| }, |
| |
| get textLabel() { |
| return 'Metrics'; |
| }, |
| |
| supportsModel: function(m) { |
| if (!m) { |
| return { |
| supported: false, |
| reason: 'No model available' |
| }; |
| } |
| |
| return { |
| supported: true |
| }; |
| }, |
| |
| get model() { |
| return this.model_; |
| }, |
| |
| set model(model) { |
| this.model_ = model; |
| this.updateContents_(); |
| }, |
| |
| get selection() { |
| // Not applicable to metrics. |
| }, |
| |
| set selection(_) { |
| // Not applicable to metrics. |
| }, |
| |
| /** |
| * @return {undefined|!tr.b.Range} |
| */ |
| get rangeOfInterest() { |
| return this.rangeOfInterest_; |
| }, |
| |
| /** |
| * This may be called rapidly as the mouse is moved. |
| * If the metric supportsRangeOfInterest and takes less than 100ms, then it |
| * will be re-run immediately; otherwise, the Recompute button will be |
| * enabled. |
| * |
| * @param {!tr.b.Range} range |
| */ |
| set rangeOfInterest(range) { |
| this.rangeOfInterest_ = range; |
| |
| if (this.currentMetricTypeInfo_ && |
| this.currentMetricTypeInfo_.metadata.supportsRangeOfInterest) { |
| if ((this.metricLatencyMs === undefined) || |
| (this.metricLatencyMs < 100)) { |
| this.updateContents_(); |
| } else { |
| this.recomputeButton_.style.background = 'red'; |
| } |
| } |
| }, |
| |
| updateContents_: function() { |
| this.style.width = ''; |
| Polymer.dom(this.$.error).textContent = ''; |
| this.$.results.style.display = 'none'; |
| |
| if (!this.model_) { |
| Polymer.dom(this.$.error).textContent = 'Missing model'; |
| return; |
| } |
| |
| var options = {metrics: [this.currentMetricName_]}; |
| |
| if (this.currentMetricTypeInfo_ && |
| this.currentMetricTypeInfo_.metadata.supportsRangeOfInterest && |
| this.rangeOfInterest && |
| !this.rangeOfInterest.isEmpty) |
| options.rangeOfInterest = this.rangeOfInterest; |
| |
| var startDate = new Date(); |
| try { |
| var values = tr.metrics.runMetrics(this.model_, options); |
| } catch (err) { |
| console.warn( |
| this.currentMetricName_ + |
| ' could not be computed for the current model:\n' + |
| err.stack); |
| Polymer.dom(this.$.error).textContent = err.message; |
| return; |
| } |
| |
| this.metricLatenciesMs_.push(new Date() - startDate); |
| while (this.metricLatenciesMs_.length > 20) |
| this.metricLatenciesMs_.shift(); |
| |
| this.recomputeButton_.style.background = ''; |
| |
| this.$.results.style.display = ''; |
| this.$.results.values = values; |
| |
| tr.b.requestAnimationFrame(function() { |
| var width = this.$.results.getBoundingClientRect().width + 15; |
| this.style.width = width + 'px'; |
| }, this); |
| } |
| }); |
| |
| tr.ui.side_panel.SidePanelRegistry.register(function() { |
| return document.createElement('tr-ui-sp-metrics-side-panel'); |
| }); |
| |
| return {}; |
| }); |
| </script> |