| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** Accessors for our Singleton variables. */ |
| 6 BenchmarkSuite get BENCHMARK_SUITE() { |
| 7 if (BenchmarkSuite._ONLY == null) { |
| 8 BenchmarkSuite._ONLY = new BenchmarkSuite._internal(); |
| 9 } |
| 10 return BenchmarkSuite._ONLY; |
| 11 } |
| 12 |
| 13 BenchmarkView get BENCHMARK_VIEW() { |
| 14 if (BenchmarkView._ONLY == null) { |
| 15 BenchmarkView._ONLY = new BenchmarkView._internal(); |
| 16 } |
| 17 return BenchmarkView._ONLY; |
| 18 } |
| 19 |
| 20 /** The superclass from which all benchmarks inherit from. */ |
| 21 class BenchmarkBase { |
| 22 /** Benchmark name. */ |
| 23 final String name; |
| 24 |
| 25 const BenchmarkBase(String name) : this.name = name; |
| 26 |
| 27 /** |
| 28 * The benchmark code. |
| 29 * This function is not used, if both [warmup] and [exercise] are overwritten. |
| 30 */ |
| 31 void run() { } |
| 32 |
| 33 /** Runs a short version of the benchmark. By default invokes [run] once. */ |
| 34 void warmup() { |
| 35 run(); |
| 36 } |
| 37 |
| 38 /** Exercices the benchmark. By default invokes [run] 10 times. */ |
| 39 void exercise() { |
| 40 for (int i = 0; i < 10; i++) { |
| 41 run(); |
| 42 } |
| 43 } |
| 44 |
| 45 /** Not measured setup code executed prior to the benchmark runs. */ |
| 46 void setup() { } |
| 47 |
| 48 /** Not measures teardown code executed after the benchark runs. */ |
| 49 void teardown() { } |
| 50 |
| 51 /** |
| 52 * Measures the score for this benchmark by executing it repeately until |
| 53 * time minimum has been reached. |
| 54 */ |
| 55 static double measureFor(Function f, int timeMinimum) { |
| 56 int time = 0; |
| 57 int iter = 0; |
| 58 Stopwatch watch = new Stopwatch(); |
| 59 watch.start(); |
| 60 int elapsed = 0; |
| 61 while (elapsed < timeMinimum || iter < 32) { |
| 62 f(); |
| 63 elapsed = watch.elapsedInMs(); |
| 64 iter++; |
| 65 } |
| 66 return (1000.0 * iter) / elapsed; |
| 67 } |
| 68 |
| 69 /** |
| 70 * Measures the score for the benchmark and returns it. |
| 71 * We measure iterations / sec (so bigger = better!). |
| 72 */ |
| 73 double measure() { |
| 74 setup(); |
| 75 // Warmup for at least 1000ms. Discard result. |
| 76 measureFor(() { this.warmup(); }, 1000); |
| 77 // Run the benchmark for at least 1000ms. |
| 78 double result = measureFor(() { this.exercise(); }, 1000); |
| 79 teardown(); |
| 80 return result; |
| 81 } |
| 82 |
| 83 void report() { |
| 84 num score = measure(); |
| 85 Map<String, int> normalizingDict = {'Smoketest': 100}; |
| 86 window.console.log(name + " " + score.toString()); |
| 87 score = score / normalizingDict[name]; |
| 88 BENCHMARK_SUITE.updateIndividualScore(name, score); |
| 89 } |
| 90 } |
| 91 |
| 92 /** The controller class that runs all of the benchmarks. */ |
| 93 class BenchmarkSuite { |
| 94 /** The set of benchmarks that have yet to run. */ |
| 95 List<Function> benchmarks; |
| 96 |
| 97 /** |
| 98 * The set of scores from the benchmarks that have already run. (Used for |
| 99 * calculating the Geometric mean). |
| 100 */ |
| 101 List<num> scores; |
| 102 |
| 103 /** The total number of benchmarks we will be running. */ |
| 104 int totalBenchmarks; |
| 105 |
| 106 /** Singleton pattern: There's only one BenchmarkSuite. */ |
| 107 static BenchmarkSuite _ONLY = null; |
| 108 |
| 109 BenchmarkSuite._internal() { |
| 110 scores = []; |
| 111 benchmarks = [() => Smoketest.main()]; |
| 112 totalBenchmarks = benchmarks.length; |
| 113 } |
| 114 |
| 115 /** Run all of the benchmarks that we have in our benchmarks list. */ |
| 116 runBenchmarks() { |
| 117 runBenchmarksHelper(benchmarks); |
| 118 } |
| 119 |
| 120 /** |
| 121 * Run the remaining benchmarks in our list. We chain the calls providing |
| 122 * little breaks for the main page to gain control, so we don't force the |
| 123 * entire page to hang the whole time. |
| 124 */ |
| 125 runBenchmarksHelper(List<Function> remainingBenchmarks) { |
| 126 // Remove the last benchmark, and run it. |
| 127 var benchmark = remainingBenchmarks.removeLast(); |
| 128 benchmark(); |
| 129 if (remainingBenchmarks.length > 0) { |
| 130 /* Provide small breaks between each benchmark, so that the browser |
| 131 doesn't get unhappy about long running scripts, and so the user |
| 132 can regain control of the UI to kill the page as needed. */ |
| 133 window.setTimeout(() => runBenchmarksHelper(remainingBenchmarks), 25); |
| 134 } else if (remainingBenchmarks.length == 0) { |
| 135 // We've run all of the benchmarks. Update the page with the score. |
| 136 BENCHMARK_VIEW.setScore(geometricMean(scores)); |
| 137 } |
| 138 } |
| 139 |
| 140 /** Store the results of a single benchmark run. */ |
| 141 updateIndividualScore(String name, num score) { |
| 142 scores.add(score); |
| 143 BENCHMARK_VIEW.incrementProgress(name, score, totalBenchmarks); |
| 144 } |
| 145 |
| 146 /** Computes the geometric mean of a set of numbers. */ |
| 147 geometricMean(numbers) { |
| 148 num log = 0; |
| 149 for (num n in numbers) { |
| 150 log += Math.log(n); |
| 151 } |
| 152 return Math.pow(Math.E, log / numbers.length); |
| 153 } |
| 154 } |
| 155 |
| 156 /** Controls how results are displayed to the user, by updating the HTML. */ |
| 157 class BenchmarkView { |
| 158 |
| 159 /** The number of benchmarks that have finished executing. */ |
| 160 int numCompleted = 0; |
| 161 |
| 162 /** Singleton pattern: There's only one BenchmarkSuite. */ |
| 163 static BenchmarkView _ONLY = null; |
| 164 |
| 165 BenchmarkView._internal(); |
| 166 |
| 167 /** Update the page HTML to show the calculated score. */ |
| 168 setScore(num score) { |
| 169 String newScore = formatScore(score * 100.0); |
| 170 Element status = document.query("#status"); |
| 171 status.innerHTML = "Score: $newScore <br>"; |
| 172 } |
| 173 |
| 174 /** |
| 175 * Update the page HTML to show how much progress we've made through the |
| 176 * benchmarks. |
| 177 */ |
| 178 incrementProgress(String name, num score, num totalBenchmarks) { |
| 179 String newScore = formatScore(score * 100.0); |
| 180 Element results = document.query("#results"); |
| 181 results.innerHTML += "$name: $newScore <br>"; |
| 182 |
| 183 Element status = document.query("#status"); |
| 184 numCompleted++; |
| 185 // Slightly incorrect (truncating) percentage, but this is just to show |
| 186 // the user we're making progress. |
| 187 num percentage = 100 * numCompleted ~/ totalBenchmarks; |
| 188 status.innerHTML = "Running: $percentage% completed."; |
| 189 } |
| 190 |
| 191 /** |
| 192 * Rounds the score to have at least three significant digits (hopefully) |
| 193 * helping readability of the scores. |
| 194 */ |
| 195 String formatScore(num value) { |
| 196 if (value > 100) { |
| 197 return value.toStringAsFixed(0); |
| 198 } else { |
| 199 return value.toStringAsFixed(2); |
| 200 } |
| 201 } |
| 202 } |
| OLD | NEW |