From 59061e3224828ab8cf7ef84cbc29e813e6202ce3 Mon Sep 17 00:00:00 2001 From: yjbanov Date: Mon, 24 Oct 2016 14:16:46 -0700 Subject: [PATCH] set and display goals for each metric --- app/bin/build_and_test.sh | 2 -- app/lib/components/benchmark_grid.dart | 44 ++++++++++++++++++++------ app/lib/model.dart | 2 ++ app/test/benchmark_grid_test.dart | 1 + app/web/benchmarks.css | 19 +++++++++++ db/schema.go | 3 ++ 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/app/bin/build_and_test.sh b/app/bin/build_and_test.sh index 6247d72edc..05afeace9b 100755 --- a/app/bin/build_and_test.sh +++ b/app/bin/build_and_test.sh @@ -15,8 +15,6 @@ dartanalyzer --strong bin/*.dart web/*.dart test/*.dart pub run test -p vm pub run test -p dartium pub build -cp web/*.dart build/web/ -cp -RL packages build/web/ echo echo "Build succeeded! To deploy to App Engine run the following command after replacing {VERSION}:" diff --git a/app/lib/components/benchmark_grid.dart b/app/lib/components/benchmark_grid.dart index 8ca391e5a5..fdc52b7e9f 100644 --- a/app/lib/components/benchmark_grid.dart +++ b/app/lib/components/benchmark_grid.dart @@ -61,12 +61,17 @@ class BenchmarkGrid implements OnInit, OnDestroy { {{unit}}
{{label}}
-
+
''', directives: const [NgIf, NgFor, NgStyle], ) -class BenchmarkCard implements AfterViewInit { +class BenchmarkCard implements AfterViewInit, OnDestroy { + /// The total height of the chart. This value must be in sync with the height + /// specified for benchmark-card in benchmarks.css. + static const int _kChartHeight = 100; + BenchmarkData _data; + DivElement _tooltip; @ViewChild('chartContainer') ElementRef chartContainer; @@ -75,6 +80,7 @@ class BenchmarkCard implements AfterViewInit { _data = newData; } + double get goal => _data.timeseries.timeseries.goal; String get id => _data.timeseries.timeseries.id; String get taskName => _data.timeseries.timeseries.taskName; String get label => _data.timeseries.timeseries.label; @@ -99,31 +105,49 @@ class BenchmarkCard implements AfterViewInit { if (_data.values.isEmpty) return; double maxValue = _data.values .map((TimeseriesValue v) => v.value) - .reduce(math.max); + .fold(goal, math.max); + + // Leave a bit of room to bars don't fill the height of the card + maxValue *= 1.1; + + chartContainer.nativeElement.children.add( + new DivElement() + ..classes.add('metric-goal') + ..style.height = '${_kChartHeight * goal / maxValue}px' + ); for (TimeseriesValue value in _data.values.reversed) { DivElement bar = new DivElement() ..classes.add('metric-value-bar') - ..style.height = '${100 * value.value / maxValue}px'; + ..style.height = '${_kChartHeight * value.value / maxValue}px'; + + if (value.value > goal) { + bar.classes.add('metric-value-bar-underperformed'); + } - DivElement tooltip; bar.onMouseOver.listen((_) { - tooltip = new DivElement() + _tooltip = new DivElement() ..text = '${value.value}$unit\n' 'Flutter revision: ${value.revision}\n' - 'Recorded on: ${new DateTime.fromMillisecondsSinceEpoch(value.createTimestamp)}' + 'Recorded on: ${new DateTime.fromMillisecondsSinceEpoch(value.createTimestamp)}\n' + 'Goal: $goal$unit' ..classes.add('metric-value-tooltip') ..style.top = '${bar.getBoundingClientRect().top}px' ..style.left = '${bar.getBoundingClientRect().right + 5}px'; bar.style.backgroundColor = '#11CC11'; - document.body.append(tooltip); + document.body.append(_tooltip); }); bar.onMouseOut.listen((_) { - bar.style.backgroundColor = '#AAFFAA'; - tooltip?.remove(); + bar.style.backgroundColor = ''; + _tooltip?.remove(); }); chartContainer.nativeElement.children.add(bar); } } + + @override + void ngOnDestroy() { + _tooltip?.remove(); + } } diff --git a/app/lib/model.dart b/app/lib/model.dart index 6c390ae052..f72305625e 100644 --- a/app/lib/model.dart +++ b/app/lib/model.dart @@ -256,6 +256,7 @@ class Timeseries extends Entity { 'TaskName': string(), 'Label': string(), 'Unit': string(), + 'Goal': number(), } ); @@ -265,6 +266,7 @@ class Timeseries extends Entity { String get taskName => this['TaskName']; String get label => this['Label']; String get unit => this['Unit']; + double get goal => this['Goal']; } class TimeseriesValue extends Entity { diff --git a/app/test/benchmark_grid_test.dart b/app/test/benchmark_grid_test.dart index 1b9683b5d3..ce952f0ca7 100644 --- a/app/test/benchmark_grid_test.dart +++ b/app/test/benchmark_grid_test.dart @@ -61,6 +61,7 @@ final _testData = { 'ID': 'series$i', 'Label': 'Series $i', 'Unit': 'ms', + 'Goal': i.toDouble(), }, }, 'Values': new List.generate(_rnd.nextInt(5), (int v) => { diff --git a/app/web/benchmarks.css b/app/web/benchmarks.css index e9bcb62672..3c07ab1d63 100644 --- a/app/web/benchmarks.css +++ b/app/web/benchmarks.css @@ -47,6 +47,21 @@ benchmark-card { pointer-events: none; } +.metric-chart-container { + display: flex; + flex-direction: row-reverse; + align-items: flex-end; +} + +.metric-goal { + position: absolute; + left: 0; + right: 0; + bottom: 0; + border-top: 1px dashed #81C784; + pointer-events: none; +} + .metric-value { font-size: 42px; font-weight: bold; @@ -58,6 +73,10 @@ benchmark-card { display: inline-block; } +.metric-value-bar-underperformed { + background-color: #FFAAAA; +} + .metric-value-tooltip { background-color: white; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); diff --git a/db/schema.go b/db/schema.go index a3a0eadb15..55c33b7d49 100644 --- a/db/schema.go +++ b/db/schema.go @@ -91,6 +91,9 @@ type Timeseries struct { Label string // The unit used for the values, e.g. "ms", "kg", "pumpkins". Unit string + // The current goal we want to reach for this metric. As of today, all our metrics are smaller + // is better. + Goal float64 } // TimeseriesEntity contains storage data on a Timeseries.