blob: a7a15351e7c04da75a9eec3e484abb9d7c6aa9f3 [file] [log] [blame]
<!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>