| OLD | NEW |
| 1 // Copyright (c) 2017, 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 |
| 1 import 'dart:async'; | 5 import 'dart:async'; |
| 2 import 'dart:convert'; | 6 import 'dart:convert'; |
| 3 import 'dart:math'; | 7 import 'dart:math'; |
| 4 import 'dart:io'; | 8 import 'dart:io'; |
| 5 | 9 |
| 6 import 'standard_deviation.dart'; | 10 import 'standard_deviation.dart'; |
| 7 | 11 |
| 8 const String bRootPath = const String.fromEnvironment("bRoot"); | 12 const String bRootPath = const String.fromEnvironment("bRoot"); |
| 9 const int iterations = const int.fromEnvironment("iterations", defaultValue: 1); | 13 const int abIterations = |
| 14 const int.fromEnvironment("abIterations", defaultValue: 15); |
| 15 const int iterations = |
| 16 const int.fromEnvironment("iterations", defaultValue: 15); |
| 10 | 17 |
| 11 /// Compare the performance of two different fast implementations | 18 /// Compare the performance of two different fast implementations |
| 12 /// by alternately launching the compile application in this directory | 19 /// by alternately launching the compile application in this directory |
| 13 /// and the compile application location in the repo specified by "bRoot" | 20 /// and the compile application location in the repo specified by "bRoot" |
| 14 /// via -DbRoot=/absolute/path/to/other/sdk/repo | 21 /// via -DbRoot=/absolute/path/to/other/sdk/repo |
| 15 main(List<String> args) async { | 22 main(List<String> args) async { |
| 16 print(args); | 23 print(args); |
| 17 if (bRootPath == null) { | 24 if (bRootPath == null) { |
| 18 print('Expected -DbRoot=/absolute/path/to/other/sdk/repo'); | 25 print('Expected -DbRoot=/absolute/path/to/other/sdk/repo'); |
| 19 exit(1); | 26 exit(1); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 40 | 47 |
| 41 print('Comparing:'); | 48 print('Comparing:'); |
| 42 print('A: $aCompile'); | 49 print('A: $aCompile'); |
| 43 print('B: $bCompile'); | 50 print('B: $bCompile'); |
| 44 print(''); | 51 print(''); |
| 45 | 52 |
| 46 List<double> aCold = <double>[]; | 53 List<double> aCold = <double>[]; |
| 47 List<double> aWarm = <double>[]; | 54 List<double> aWarm = <double>[]; |
| 48 List<double> bCold = <double>[]; | 55 List<double> bCold = <double>[]; |
| 49 List<double> bWarm = <double>[]; | 56 List<double> bWarm = <double>[]; |
| 50 for (int count = 0; count < 15; ++count) { | 57 |
| 58 var stopwatch = new Stopwatch()..start(); |
| 59 for (int count = 0; count < abIterations; ++count) { |
| 60 print('A/B iteration ${count + 1} of $abIterations ...'); |
| 51 await run(aRoot, aCompile, args, aCold, aWarm); | 61 await run(aRoot, aCompile, args, aCold, aWarm); |
| 52 await run(bRoot, bCompile, args, bCold, bWarm); | 62 await run(bRoot, bCompile, args, bCold, bWarm); |
| 53 } | 63 } |
| 64 stopwatch.stop(); |
| 65 print('Overall run time: ${stopwatch.elapsed.inMinutes} minutes'); |
| 54 | 66 |
| 55 print(''); | 67 print(''); |
| 56 print('Raw data:'); | 68 print('Raw data:'); |
| 57 print('A cold, A warm, B cold, B warm'); | 69 print('A cold, A warm, B cold, B warm'); |
| 58 for (int index = 0; index < aCold.length; ++index) { | 70 for (int index = 0; index < aCold.length; ++index) { |
| 59 print('${aCold[index]}, ${aWarm[index]}, ${bCold[index]}, ${bWarm[index]}'); | 71 print('${aCold[index]}, ${aWarm[index]}, ${bCold[index]}, ${bWarm[index]}'); |
| 60 } | 72 } |
| 61 | 73 |
| 74 if (aWarm.length < 1) { |
| 75 return; |
| 76 } |
| 77 |
| 62 double aColdMean = average(aCold); | 78 double aColdMean = average(aCold); |
| 63 double aWarmMean = average(aWarm); | 79 double aWarmMean = average(aWarm); |
| 64 double bColdMean = average(bCold); | 80 double bColdMean = average(bCold); |
| 65 double bWarmMean = average(bWarm); | 81 double bWarmMean = average(bWarm); |
| 66 | 82 |
| 67 print(''); | 83 print(''); |
| 68 print('Average:'); | 84 print('Average:'); |
| 69 print('$aColdMean, $aWarmMean, $bColdMean, $bWarmMean'); | 85 print('$aColdMean, $aWarmMean, $bColdMean, $bWarmMean'); |
| 70 | 86 |
| 87 if (aWarm.length < 2) { |
| 88 return; |
| 89 } |
| 90 |
| 71 double aColdStdDev = standardDeviation(aColdMean, aCold); | 91 double aColdStdDev = standardDeviation(aColdMean, aCold); |
| 72 double aWarmStdDev = standardDeviation(aWarmMean, aWarm); | 92 double aWarmStdDev = standardDeviation(aWarmMean, aWarm); |
| 73 double bColdStdDev = standardDeviation(bColdMean, bCold); | 93 double bColdStdDev = standardDeviation(bColdMean, bCold); |
| 74 double bWarmStdDev = standardDeviation(bWarmMean, bWarm); | 94 double bWarmStdDev = standardDeviation(bWarmMean, bWarm); |
| 75 | 95 |
| 76 double aColdStdDevMean = standardDeviationOfTheMean(aCold, aColdStdDev); | 96 double aColdSDM = standardDeviationOfTheMean(aCold, aColdStdDev); |
| 77 double aWarmStdDevMean = standardDeviationOfTheMean(aWarm, aWarmStdDev); | 97 double aWarmSDM = standardDeviationOfTheMean(aWarm, aWarmStdDev); |
| 78 double bColdStdDevMean = standardDeviationOfTheMean(bCold, bColdStdDev); | 98 double bColdSDM = standardDeviationOfTheMean(bCold, bColdStdDev); |
| 79 double bWarmStdDevMean = standardDeviationOfTheMean(bWarm, bWarmStdDev); | 99 double bWarmSDM = standardDeviationOfTheMean(bWarm, bWarmStdDev); |
| 80 | 100 |
| 81 print(''); | 101 print(''); |
| 82 print('Uncertainty:'); | 102 print('Uncertainty:'); |
| 83 print( | 103 print('$aColdSDM, $aWarmSDM, $bColdSDM, $bWarmSDM'); |
| 84 '$aColdStdDevMean, $aWarmStdDevMean, $bColdStdDevMean, $bWarmStdDevMean'); | |
| 85 | 104 |
| 86 double coldDelta = aColdMean - bColdMean; | 105 double coldDelta = aColdMean - bColdMean; |
| 87 double coldStdDevMean = | 106 double coldUncertainty = sqrt(pow(aColdSDM, 2) + pow(bColdSDM, 2)); |
| 88 sqrt(pow(aColdStdDevMean, 2) + pow(bColdStdDevMean, 2)); | |
| 89 double warmDelta = aWarmMean - bWarmMean; | 107 double warmDelta = aWarmMean - bWarmMean; |
| 90 double warmStdDevMean = | 108 double warmUncertainty = sqrt(pow(aWarmSDM, 2) + pow(bWarmSDM, 2)); |
| 91 sqrt(pow(aWarmStdDevMean, 2) + pow(bWarmStdDevMean, 2)); | 109 |
| 110 double coldDeltaPercent = (coldDelta / bColdMean * 1000).round() / 10; |
| 111 double coldUncertaintyPercent = |
| 112 (coldUncertainty / bColdMean * 1000).round() / 10; |
| 113 double warmDeltaPercent = (warmDelta / bWarmMean * 1000).round() / 10; |
| 114 double warmUncertaintyPercent = |
| 115 (warmUncertainty / bWarmMean * 1000).round() / 10; |
| 116 |
| 117 double coldBest = coldDelta - 3 * coldUncertainty; |
| 118 double coldBestPercent = coldDeltaPercent - 3 * coldUncertaintyPercent; |
| 119 double coldWorst = coldDelta + 3 * coldUncertainty; |
| 120 double coldWorstPercent = coldDeltaPercent + 3 * coldUncertaintyPercent; |
| 121 |
| 122 double warmBest = warmDelta - 3 * warmUncertainty; |
| 123 double warmBestPercent = warmDeltaPercent - 3 * warmUncertaintyPercent; |
| 124 double warmWorst = warmDelta + 3 * warmUncertainty; |
| 125 double warmWorstPercent = warmDeltaPercent + 3 * warmUncertaintyPercent; |
| 92 | 126 |
| 93 print(''); | 127 print(''); |
| 94 print('Summary:'); | 128 print('Summary:'); |
| 95 print(' A cold start - B cold start : $coldDelta'); | 129 print('$coldDelta, $coldDeltaPercent%, A cold start - B cold start'); |
| 96 print(' Uncertainty : $coldStdDevMean'); | 130 print('$coldUncertainty, $coldUncertaintyPercent%, Propagated uncertainty'); |
| 131 print('$coldBest, $coldBestPercent%, 99.9% best case'); |
| 132 print('$coldWorst, $coldWorstPercent%, 99.9% worst case'); |
| 97 print(''); | 133 print(''); |
| 98 print(' A warm runs - B warm runs : $warmDelta'); | 134 print('$warmDelta, $warmDeltaPercent%, A warm runs - B warm runs'); |
| 99 print(' Uncertainty : $warmStdDevMean'); | 135 print('$warmUncertainty, $warmUncertaintyPercent%, Propagated uncertainty'); |
| 136 print('$warmBest, $warmBestPercent%, 99.9% best case'); |
| 137 print('$warmWorst, $warmWorstPercent%, 99.9% worst case'); |
| 100 } | 138 } |
| 101 | 139 |
| 102 const String _wroteProgram = 'Wrote program to'; | 140 const String _iterationTag = '=== Iteration '; |
| 103 const String _coldStart = 'Cold start (first run):'; | 141 const String _summaryTag = 'Summary: {"'; |
| 104 const String _warmRun = 'Warm run average (runs #4'; | |
| 105 | 142 |
| 106 /// Launch the specified dart program, forwarding all arguments and environment | 143 /// Launch the specified dart program, forwarding all arguments and environment |
| 107 /// that was passed to this program | 144 /// that was passed to this program |
| 108 Future<Null> run(Uri workingDir, Uri dartApp, List<String> args, | 145 Future<Null> run(Uri workingDir, Uri dartApp, List<String> args, |
| 109 List<double> cold, List<double> warm) async { | 146 List<double> cold, List<double> warm) async { |
| 110 print('Running $dartApp'); | 147 print('Running $dartApp'); |
| 111 | 148 |
| 112 void processLine(String line) { | 149 void processLine(String line) { |
| 113 if (line.contains(_wroteProgram)) { | 150 if (line.startsWith(_iterationTag)) { |
| 114 // Show progress | 151 // Show progress |
| 115 stdout | 152 stdout |
| 116 ..write('.') | 153 ..write('.') |
| 117 ..flush(); | 154 ..flush(); |
| 118 return; | 155 return; |
| 119 } | 156 } |
| 120 int index = line.indexOf(_coldStart); | 157 if (line.startsWith(_summaryTag)) { |
| 121 if (index >= 0) { | 158 String json = line.substring(_summaryTag.length - 2); |
| 122 cold.add(double.parse(line.substring(index + _coldStart.length))); | 159 Map<String, dynamic> results = JSON.decode(json); |
| 123 print('\ncold: ${cold.last}'); | 160 List<double> elapsedTimes = results['elapsedTimes']; |
| 124 return; | 161 print('\nElapse times: $elapsedTimes'); |
| 125 } | 162 if (elapsedTimes.length > 0) { |
| 126 index = line.indexOf(_warmRun); | 163 cold.add(elapsedTimes[0]); |
| 127 if (index >= 0) { | 164 } |
| 128 index = line.indexOf(':', index + _warmRun.length); | 165 if (elapsedTimes.length > 4) { |
| 129 warm.add(double.parse(line.substring(index + 1))); | 166 // Drop the first 3 and average the remaining |
| 130 print('warm: ${warm.last}'); | 167 warm.add(average(elapsedTimes.sublist(3))); |
| 168 } |
| 131 return; | 169 return; |
| 132 } | 170 } |
| 133 } | 171 } |
| 134 | 172 |
| 135 String workingDirPath = workingDir.toFilePath(); | 173 String workingDirPath = workingDir.toFilePath(); |
| 136 List<String> procArgs = <String>[ | 174 List<String> procArgs = <String>[ |
| 137 '-Diterations=$iterations', | 175 '-Diterations=$iterations', |
| 176 '-Dsummary=true', |
| 138 dartApp.toFilePath() | 177 dartApp.toFilePath() |
| 139 ]; | 178 ]; |
| 140 procArgs.addAll(args); | 179 procArgs.addAll(args); |
| 141 | 180 |
| 142 Process process = await Process.start(Platform.executable, procArgs, | 181 Process process = await Process.start(Platform.executable, procArgs, |
| 143 workingDirectory: workingDirPath); | 182 workingDirectory: workingDirPath); |
| 144 stderr.addStream(process.stderr); | 183 stderr.addStream(process.stderr); |
| 145 StreamSubscription<String> stdOutSubscription; | 184 StreamSubscription<String> stdOutSubscription; |
| 146 stdOutSubscription = process.stdout | 185 stdOutSubscription = process.stdout |
| 147 .transform(UTF8.decoder) | 186 .transform(UTF8.decoder) |
| 148 .transform(new LineSplitter()) | 187 .transform(new LineSplitter()) |
| 149 .listen(processLine, onDone: () { | 188 .listen(processLine, onDone: () { |
| 150 stdOutSubscription.cancel(); | 189 stdOutSubscription.cancel(); |
| 151 }, onError: (e) { | 190 }, onError: (e) { |
| 152 print('Error: $e'); | 191 print('Error: $e'); |
| 153 stdOutSubscription.cancel(); | 192 stdOutSubscription.cancel(); |
| 154 }); | 193 }); |
| 155 int code = await process.exitCode; | 194 int code = await process.exitCode; |
| 156 if (code != 0) { | 195 if (code != 0) { |
| 157 throw 'fail: $code'; | 196 throw 'fail: $code'; |
| 158 } | 197 } |
| 159 print(''); | 198 print(''); |
| 160 } | 199 } |
| OLD | NEW |