| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env dart |
| 2 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. |
| 5 |
| 6 /** |
| 7 * Script that prints in a table format a comparison of two benchmark results. |
| 8 * The input is given as two json files containing the benchmark results. |
| 9 */ |
| 10 library test.perf.compare; |
| 11 |
| 12 import 'dart:io'; |
| 13 import 'dart:json'; |
| 14 import 'dart:math' as math; |
| 15 |
| 16 main() { |
| 17 var args = new Options().arguments; |
| 18 if (args.length < 2) { |
| 19 print('usage: compare.dart results1.json results2.json [filter]'); |
| 20 exit(1); |
| 21 } |
| 22 |
| 23 var path1 = args[0]; |
| 24 var path2 = args[1]; |
| 25 var file1 = new File(path1).readAsStringSync(); |
| 26 var file2 = new File(path2).readAsStringSync(); |
| 27 var filter = args.length > 2 ? new RegExp(args[2]) : null; |
| 28 |
| 29 var results = []; |
| 30 var map1 = JSON.parse(file1); |
| 31 var map2 = JSON.parse(file2); |
| 32 |
| 33 for (var key in map1.keys) { |
| 34 if (map2.containsKey(key)) { |
| 35 results.add(new ResultPair(key, map1[key], map2[key])); |
| 36 } else { |
| 37 results.add(new ResultPair(key, map1[key], null)); |
| 38 } |
| 39 } |
| 40 |
| 41 for (var key in map2.keys) { |
| 42 if (!map1.containsKey(key)) { |
| 43 results.add(new ResultPair(key, null, map2[key])); |
| 44 } |
| 45 } |
| 46 |
| 47 print('Comparing:\n (a) $path1\n (b) $path2'); |
| 48 _printLine('Benchmark', '(a)', '(b)', '% (b - a)/a'); |
| 49 _printLine('------------------------------', '--------------', |
| 50 '--------------', '--------------'); |
| 51 var times1 = []; |
| 52 var times2 = []; |
| 53 var someNull = false; |
| 54 if (filter != null) { |
| 55 results = results.filter((s) => filter.hasMatch(s.name)); |
| 56 } |
| 57 results.sort(); |
| 58 |
| 59 for (var entry in results) { |
| 60 print(entry); |
| 61 if (entry.time1 != null) { |
| 62 times1.add(entry.time1); |
| 63 } else { |
| 64 someNull = true; |
| 65 } |
| 66 if (entry.time2 != null) { |
| 67 times2.add(entry.time2); |
| 68 } else { |
| 69 someNull = true; |
| 70 } |
| 71 |
| 72 } |
| 73 _printLine('------------------------------', '--------------', |
| 74 '--------------', '--------------'); |
| 75 print(new ResultPair('Geometric mean', _geomean(times1), |
| 76 _geomean(times2))); |
| 77 |
| 78 if (someNull) { |
| 79 times1 = []; |
| 80 times2 = []; |
| 81 for (var entry in results) { |
| 82 if (entry.time1 != null && entry.time2 != null) { |
| 83 times1.add(entry.time1); |
| 84 times2.add(entry.time2); |
| 85 } |
| 86 } |
| 87 print(new ResultPair('Geometric mean (both avail)', |
| 88 _geomean(scores1), _geomean(times2))); |
| 89 } |
| 90 } |
| 91 |
| 92 class ResultPair implements Comparable { |
| 93 final String name; |
| 94 final num time1; |
| 95 final num time2; |
| 96 final num score1; |
| 97 final num score2; |
| 98 |
| 99 num get factor => score1 == null || score2 == null ? null |
| 100 : ((score2 - score1) * 100.0) / score1; |
| 101 |
| 102 ResultPair(this.name, double time1, double time2) |
| 103 : this.time1 = time1, this.time2 = time2, |
| 104 score1 = time1 == null ? null : 1000000.0 / time1, |
| 105 score2 = time2 == null ? null : 1000000.0 / time2; |
| 106 |
| 107 String toString() { |
| 108 var buff = new StringBuffer(); |
| 109 buff.add(name); |
| 110 _ensureColumn(buff, 30); |
| 111 _addNumber(buff, score1, 45); |
| 112 _addNumber(buff, score2, 60); |
| 113 _addNumber(buff, factor, 75, color: true); |
| 114 return buff.toString(); |
| 115 } |
| 116 |
| 117 int compareTo(ResultPair other) { |
| 118 if (name.startsWith('dart') && other.name.startsWith('js ')) return 1; |
| 119 if (name.startsWith('js ') && other.name.startsWith('dart')) return -1; |
| 120 if (factor != null && other.factor != null) { |
| 121 var res = factor.compareTo(other.factor); |
| 122 if (res != 0) return res; |
| 123 } |
| 124 return name.compareTo(other.name); |
| 125 } |
| 126 } |
| 127 |
| 128 _printLine(String col0, String col1, String col2, String col3) { |
| 129 var buff = new StringBuffer(); |
| 130 buff.add(col0); |
| 131 _ensureColumn(buff, 30); |
| 132 _padRight(buff, col1, 45); |
| 133 _padRight(buff, col2, 60); |
| 134 _padRight(buff, col3, 75); |
| 135 print(buff.toString()); |
| 136 } |
| 137 |
| 138 _ensureColumn(StringBuffer buff, int ensure) { |
| 139 while (buff.length < ensure) { |
| 140 buff.add(' '); |
| 141 } |
| 142 } |
| 143 |
| 144 _addNumber(StringBuffer buff, num value, int ensure, {bool color: false}) { |
| 145 var str; |
| 146 if (value == null) { |
| 147 str = '--'; |
| 148 } else { |
| 149 str = value.toStringAsFixed(value >= 100 ? 0 : (value >= 10 ? 1 : 2)); |
| 150 } |
| 151 |
| 152 while (buff.length + str.length < ensure) { |
| 153 buff.add(' '); |
| 154 } |
| 155 if (color) _addColor(buff, value); |
| 156 buff.add(str); |
| 157 if (color) _removeColor(buff, value); |
| 158 } |
| 159 |
| 160 _addColor(StringBuffer buff, num value) { |
| 161 if (value == null || value.abs() < 2) return; |
| 162 var color; |
| 163 if (value >= 2 && value < 7) { |
| 164 color = '[32m'; |
| 165 } else if (value >= 7) { |
| 166 color = '[32;1m'; |
| 167 } else if (value <= -2 && value > -7) { |
| 168 color = '[38;5;208m'; |
| 169 } else if (value <= -7) { |
| 170 color = '[31;1m'; |
| 171 } |
| 172 buff.add(color); |
| 173 } |
| 174 |
| 175 _removeColor(StringBuffer buff, num value) { |
| 176 if (value == null || value.abs() < 2) return; |
| 177 buff.add('[0m'); |
| 178 } |
| 179 |
| 180 _padRight(StringBuffer buff, String str, int ensure) { |
| 181 while (buff.length + str.length < ensure) { |
| 182 buff.add(' '); |
| 183 } |
| 184 buff.add(str); |
| 185 } |
| 186 |
| 187 _geomean(List<num> numbers) { |
| 188 var log = 0.0; |
| 189 for (var n in numbers) { |
| 190 log += math.log(n); |
| 191 } |
| 192 return math.pow(math.E, log / numbers.length); |
| 193 } |
| OLD | NEW |