| OLD | NEW |
| 1 // Copyright (c) 2015, 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 library server.driver; | 5 library server.driver; |
| 2 | 6 |
| 3 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:math' show max; |
| 4 | 9 |
| 5 import 'package:logging/logging.dart'; | 10 import 'package:logging/logging.dart'; |
| 6 | 11 |
| 7 import '../integration/integration_test_methods.dart'; | 12 import '../integration/integration_test_methods.dart'; |
| 8 import '../integration/integration_tests.dart'; | 13 import '../integration/integration_tests.dart'; |
| 9 import 'operation.dart'; | 14 import 'operation.dart'; |
| 10 | 15 |
| 16 final SPACE = ' '.codeUnitAt(0); |
| 17 |
| 18 void _printColumn(StringBuffer sb, String text, int keyLen, |
| 19 {bool rightJustified: false}) { |
| 20 if (!rightJustified) { |
| 21 sb.write(text); |
| 22 sb.write(','); |
| 23 } |
| 24 for (int i = text.length; i < keyLen; ++i) { |
| 25 sb.writeCharCode(SPACE); |
| 26 } |
| 27 if (rightJustified) { |
| 28 sb.write(text); |
| 29 sb.write(','); |
| 30 } |
| 31 sb.writeCharCode(SPACE); |
| 32 } |
| 33 |
| 11 /** | 34 /** |
| 12 * [Driver] launches and manages an instance of analysis server, | 35 * [Driver] launches and manages an instance of analysis server, |
| 13 * reads a stream of operations, sends requests to analysis server | 36 * reads a stream of operations, sends requests to analysis server |
| 14 * based upon those operations, and evaluates the results. | 37 * based upon those operations, and evaluates the results. |
| 15 */ | 38 */ |
| 16 class Driver extends IntegrationTestMixin { | 39 class Driver extends IntegrationTestMixin { |
| 17 /** | 40 /** |
| 18 * The amount of time to give the server to respond to a shutdown request | 41 * The amount of time to give the server to respond to a shutdown request |
| 19 * before forcibly terminating it. | 42 * before forcibly terminating it. |
| 20 */ | 43 */ |
| 21 static const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 5); | 44 static const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 5); |
| 22 | 45 |
| 23 final Logger logger; | 46 final Logger logger; |
| 24 | 47 |
| 25 /** | 48 /** |
| 26 * A flag indicating whether the server is running. | 49 * A flag indicating whether the server is running. |
| 27 */ | 50 */ |
| 28 bool running = false; | 51 bool running = false; |
| 29 | 52 |
| 30 @override | 53 @override |
| 31 Server server; | 54 Server server; |
| 32 | 55 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 running = false; | 113 running = false; |
| 91 _resultsReady(); | 114 _resultsReady(); |
| 92 }); | 115 }); |
| 93 return serverConnected.future; | 116 return serverConnected.future; |
| 94 }); | 117 }); |
| 95 } | 118 } |
| 96 | 119 |
| 97 /** | 120 /** |
| 98 * Shutdown the analysis server if it is running. | 121 * Shutdown the analysis server if it is running. |
| 99 */ | 122 */ |
| 100 Future stopServer() async { | 123 Future stopServer([Duration timeout = SHUTDOWN_TIMEOUT]) async { |
| 101 if (running) { | 124 if (running) { |
| 102 logger.log(Level.FINE, 'requesting server shutdown'); | 125 logger.log(Level.FINE, 'requesting server shutdown'); |
| 103 // Give the server a short time to comply with the shutdown request; if it | 126 // Give the server a short time to comply with the shutdown request; if it |
| 104 // doesn't exit, then forcibly terminate it. | 127 // doesn't exit, then forcibly terminate it. |
| 105 sendServerShutdown(); | 128 sendServerShutdown(); |
| 106 await server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () { | 129 await server.exitCode.timeout(timeout, onTimeout: () { |
| 107 return server.kill(); | 130 return server.kill(); |
| 108 }); | 131 }); |
| 109 } | 132 } |
| 110 _resultsReady(); | 133 _resultsReady(); |
| 111 } | 134 } |
| 112 | 135 |
| 113 /** | 136 /** |
| 114 * If not already complete, signal the completer with the collected results. | 137 * If not already complete, signal the completer with the collected results. |
| 115 */ | 138 */ |
| 116 void _resultsReady() { | 139 void _resultsReady() { |
| 117 if (!_runCompleter.isCompleted) { | 140 if (!_runCompleter.isCompleted) { |
| 118 _runCompleter.complete(results); | 141 _runCompleter.complete(results); |
| 119 } | 142 } |
| 120 } | 143 } |
| 121 } | 144 } |
| 122 | 145 |
| 123 /** | 146 /** |
| 147 * [Measurement] tracks elapsed time for a given operation. |
| 148 */ |
| 149 class Measurement { |
| 150 final String tag; |
| 151 final List<Duration> elapsedTimes = new List<Duration>(); |
| 152 int errorCount = 0; |
| 153 |
| 154 Measurement(this.tag); |
| 155 |
| 156 void printSummary(int keyLen) { |
| 157 int count = 0; |
| 158 int totalTimeMicros = 0; |
| 159 for (Duration elapsed in elapsedTimes) { |
| 160 ++count; |
| 161 totalTimeMicros += elapsed.inMicroseconds; |
| 162 } |
| 163 int averageTimeMicros = (totalTimeMicros / count).round(); |
| 164 StringBuffer sb = new StringBuffer(); |
| 165 _printColumn(sb, tag, keyLen); |
| 166 _printColumn(sb, count.toString(), 5, rightJustified: true); |
| 167 _printColumn(sb, errorCount.toString(), 5, rightJustified: true); |
| 168 sb.write(' '); |
| 169 sb.write(new Duration(microseconds: averageTimeMicros)); |
| 170 sb.write(', '); |
| 171 sb.write(new Duration(microseconds: totalTimeMicros)); |
| 172 print(sb.toString()); |
| 173 } |
| 174 |
| 175 void record(bool success, Duration elapsed) { |
| 176 if (!success) { |
| 177 ++errorCount; |
| 178 } |
| 179 elapsedTimes.add(elapsed); |
| 180 } |
| 181 } |
| 182 |
| 183 /** |
| 124 * [Results] contains information gathered by [Driver] | 184 * [Results] contains information gathered by [Driver] |
| 125 * while running the analysis server | 185 * while running the analysis server |
| 126 */ | 186 */ |
| 127 class Results { | 187 class Results { |
| 128 Map<String, Measurement> measurements = new Map<String, Measurement>(); | 188 Map<String, Measurement> measurements = new Map<String, Measurement>(); |
| 129 | 189 |
| 130 /** | 190 /** |
| 131 * Display results on stdout. | 191 * Display results on stdout. |
| 132 */ | 192 */ |
| 133 void printResults() { | 193 void printResults() { |
| 134 print('=================================================================='); | 194 print('=================================================================='); |
| 135 print('Results:'); | 195 List<String> keys = measurements.keys.toList()..sort(); |
| 136 for (String tag in measurements.keys.toList()..sort()) { | 196 int keyLen = keys.fold(0, (int len, String key) => max(len, key.length)); |
| 137 measurements[tag].printResults(); | 197 StringBuffer sb = new StringBuffer(); |
| 198 _printColumn(sb, 'Results', keyLen); |
| 199 _printColumn(sb, 'count', 5); |
| 200 _printColumn(sb, 'errors', 5); |
| 201 sb.write(' average, total,'); |
| 202 print(sb.toString()); |
| 203 int totalCount = 0; |
| 204 int totalErrorCount = 0; |
| 205 for (String tag in keys) { |
| 206 Measurement m = measurements[tag]; |
| 207 m.printSummary(keyLen); |
| 208 totalCount += m.elapsedTimes.length; |
| 209 totalErrorCount += m.errorCount; |
| 138 } | 210 } |
| 211 sb.clear(); |
| 212 _printColumn(sb, 'Totals', keyLen); |
| 213 _printColumn(sb, totalCount.toString(), 5); |
| 214 _printColumn(sb, totalErrorCount.toString(), 5); |
| 215 print(sb.toString()); |
| 139 } | 216 } |
| 140 | 217 |
| 141 /** | 218 /** |
| 142 * Record the elapsed time for the given operation. | 219 * Record the elapsed time for the given operation. |
| 143 */ | 220 */ |
| 144 void record(String tag, Duration elapsed) { | 221 void record(String tag, Duration elapsed, {bool success: true}) { |
| 145 Measurement measurement = measurements[tag]; | 222 Measurement measurement = measurements[tag]; |
| 146 if (measurement == null) { | 223 if (measurement == null) { |
| 147 measurement = new Measurement(tag); | 224 measurement = new Measurement(tag); |
| 148 measurements[tag] = measurement; | 225 measurements[tag] = measurement; |
| 149 } | 226 } |
| 150 measurement.record(elapsed); | 227 measurement.record(success, elapsed); |
| 151 } | 228 } |
| 152 } | 229 } |
| 153 | |
| 154 /** | |
| 155 * [Measurement] tracks elapsed time for a given operation. | |
| 156 */ | |
| 157 class Measurement { | |
| 158 final String tag; | |
| 159 final List<Duration> elapsedTimes = new List<Duration>(); | |
| 160 | |
| 161 Measurement(this.tag); | |
| 162 | |
| 163 void record(Duration elapsed) { | |
| 164 elapsedTimes.add(elapsed); | |
| 165 } | |
| 166 | |
| 167 void printResults() { | |
| 168 if (elapsedTimes.length == 0) { | |
| 169 return; | |
| 170 } | |
| 171 print('=== $tag'); | |
| 172 for (Duration elapsed in elapsedTimes) { | |
| 173 print(elapsed); | |
| 174 } | |
| 175 } | |
| 176 } | |
| OLD | NEW |