| 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.performance; | 5 library server.performance; |
| 2 | 6 |
| 3 import 'dart:async'; | 7 import 'dart:async'; |
| 4 import 'dart:convert'; | 8 import 'dart:convert'; |
| 5 import 'dart:io'; | 9 import 'dart:io'; |
| 6 | 10 |
| 7 import 'package:args/args.dart'; | 11 import 'package:args/args.dart'; |
| 8 import 'package:logging/logging.dart'; | 12 import 'package:logging/logging.dart'; |
| 9 | 13 |
| 10 import 'driver.dart'; | 14 import 'driver.dart'; |
| 11 import 'input_converter.dart'; | 15 import 'input_converter.dart'; |
| 12 import 'operation.dart'; | 16 import 'operation.dart'; |
| 13 | 17 |
| 14 /** | 18 /** |
| 19 * The amount of time to give the server to respond to a shutdown request |
| 20 * before forcibly terminating it. |
| 21 */ |
| 22 const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 25); |
| 23 |
| 24 /** |
| 15 * Launch and interact with the analysis server. | 25 * Launch and interact with the analysis server. |
| 16 */ | 26 */ |
| 17 main(List<String> rawArgs) { | 27 main(List<String> rawArgs) { |
| 18 Logger logger = new Logger('Performance Measurement Client'); | 28 Logger logger = new Logger('Performance Measurement Client'); |
| 19 logger.onRecord.listen((LogRecord rec) { | 29 logger.onRecord.listen((LogRecord rec) { |
| 20 print(rec.message); | 30 print(rec.message); |
| 21 }); | 31 }); |
| 32 ArgResults args = parseArgs(rawArgs); |
| 33 |
| 22 Driver driver = new Driver(logger); | 34 Driver driver = new Driver(logger); |
| 23 | |
| 24 ArgResults args = parseArgs(rawArgs); | |
| 25 Stream<Operation> stream = openInput(args); | 35 Stream<Operation> stream = openInput(args); |
| 26 StreamSubscription<Operation> subscription; | 36 StreamSubscription<Operation> subscription; |
| 27 subscription = stream.listen((Operation op) { | 37 subscription = stream.listen((Operation op) { |
| 28 Future future = driver.perform(op); | 38 Future future = driver.perform(op); |
| 29 if (future != null) { | 39 if (future != null) { |
| 30 logger.log(Level.FINE, 'pausing operations for ${op.runtimeType}'); | 40 logger.log(Level.FINE, 'pausing operations for ${op.runtimeType}'); |
| 31 subscription.pause(future.then((_) { | 41 subscription.pause(future.then((_) { |
| 32 logger.log(Level.FINE, 'resuming operations'); | 42 logger.log(Level.FINE, 'resuming operations'); |
| 33 })); | 43 })); |
| 34 } | 44 } |
| 35 }, onDone: () { | 45 }, onDone: () { |
| 36 subscription.cancel(); | 46 subscription.cancel(); |
| 37 driver.stopServer(); | 47 driver.stopServer(SHUTDOWN_TIMEOUT); |
| 38 }, onError: (e, s) { | 48 }, onError: (e, s) { |
| 39 subscription.cancel(); | 49 subscription.cancel(); |
| 40 logger.log(Level.WARNING, '$e\n$s'); | 50 logger.log(Level.SEVERE, '$e\n$s'); |
| 41 driver.stopServer(); | 51 driver.stopServer(SHUTDOWN_TIMEOUT); |
| 42 throw e; | |
| 43 }); | 52 }); |
| 44 driver.runComplete.then((Results results) { | 53 driver.runComplete.then((Results results) { |
| 45 results.printResults(); | 54 results.printResults(); |
| 46 }).whenComplete(() { | 55 }).whenComplete(() { |
| 47 return subscription.cancel(); | 56 return subscription.cancel(); |
| 48 }); | 57 }); |
| 49 } | 58 } |
| 50 | 59 |
| 51 const HELP_CMDLINE_OPTION = 'help'; | 60 const HELP_CMDLINE_OPTION = 'help'; |
| 52 const INPUT_CMDLINE_OPTION = 'input'; | 61 const INPUT_CMDLINE_OPTION = 'input'; |
| 62 const MAP_FROM_OPTION = 'mapFrom'; |
| 63 const MAP_TO_OPTION = 'mapTo'; |
| 53 const VERBOSE_CMDLINE_OPTION = 'verbose'; | 64 const VERBOSE_CMDLINE_OPTION = 'verbose'; |
| 54 const VERY_VERBOSE_CMDLINE_OPTION = 'vv'; | 65 const VERY_VERBOSE_CMDLINE_OPTION = 'vv'; |
| 55 | 66 |
| 56 /** | 67 /** |
| 57 * Open and return the input stream specifying how this client | 68 * Open and return the input stream specifying how this client |
| 58 * should interact with the analysis server. | 69 * should interact with the analysis server. |
| 59 */ | 70 */ |
| 60 Stream<Operation> openInput(ArgResults args) { | 71 Stream<Operation> openInput(ArgResults args) { |
| 61 Stream<List<int>> inputRaw; | 72 Stream<List<int>> inputRaw; |
| 62 String inputPath = args[INPUT_CMDLINE_OPTION]; | 73 String inputPath = args[INPUT_CMDLINE_OPTION]; |
| 63 if (inputPath == null) { | 74 if (inputPath == null) { |
| 64 return null; | 75 return null; |
| 65 } | 76 } |
| 66 if (inputPath == 'stdin') { | 77 if (inputPath == 'stdin') { |
| 67 inputRaw = stdin; | 78 inputRaw = stdin; |
| 68 } else { | 79 } else { |
| 69 inputRaw = new File(inputPath).openRead(); | 80 inputRaw = new File(inputPath).openRead(); |
| 70 } | 81 } |
| 82 Map<String, String> srcPathMap = new Map<String, String>(); |
| 83 String mapFrom = args[MAP_FROM_OPTION]; |
| 84 if (mapFrom != null && mapFrom.isNotEmpty) { |
| 85 String mapTo = args[MAP_TO_OPTION]; |
| 86 srcPathMap[mapFrom] = mapTo; |
| 87 new Logger('openInput').log( |
| 88 Level.INFO, 'mapping source paths\n from $mapFrom\n to $mapTo'); |
| 89 } |
| 71 return inputRaw | 90 return inputRaw |
| 72 .transform(SYSTEM_ENCODING.decoder) | 91 .transform(SYSTEM_ENCODING.decoder) |
| 73 .transform(new LineSplitter()) | 92 .transform(new LineSplitter()) |
| 74 .transform(new InputConverter()); | 93 .transform(new InputConverter(srcPathMap)); |
| 75 } | 94 } |
| 76 | 95 |
| 77 /** | 96 /** |
| 78 * Parse the command line arguments. | 97 * Parse the command line arguments. |
| 79 */ | 98 */ |
| 80 ArgResults parseArgs(List<String> rawArgs) { | 99 ArgResults parseArgs(List<String> rawArgs) { |
| 81 ArgParser parser = new ArgParser(); | 100 ArgParser parser = new ArgParser(); |
| 82 | 101 |
| 83 parser.addOption(INPUT_CMDLINE_OPTION, | 102 parser.addOption(INPUT_CMDLINE_OPTION, |
| 84 abbr: 'i', | 103 abbr: 'i', |
| 85 help: 'The input file specifying how this client should interact ' | 104 help: 'The input file specifying how this client should interact ' |
| 86 'with the server. If the input file name is "stdin", ' | 105 'with the server. If the input file name is "stdin", ' |
| 87 'then the instructions are read from standard input.'); | 106 'then the instructions are read from standard input.'); |
| 107 parser.addOption(MAP_FROM_OPTION, |
| 108 help: 'The original source directory when the instrumentation ' |
| 109 'or log file was generated.'); |
| 110 parser.addOption(MAP_TO_OPTION, |
| 111 help: 'The target source directory used during performance testing. ' |
| 112 'WARNING: The contents of this directory will be modified'); |
| 88 parser.addFlag(VERBOSE_CMDLINE_OPTION, | 113 parser.addFlag(VERBOSE_CMDLINE_OPTION, |
| 89 abbr: 'v', help: 'Verbose logging', negatable: false); | 114 abbr: 'v', help: 'Verbose logging', negatable: false); |
| 90 parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION, | 115 parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION, |
| 91 help: 'Extra verbose logging', negatable: false); | 116 help: 'Extra verbose logging', negatable: false); |
| 92 parser.addFlag(HELP_CMDLINE_OPTION, | 117 parser.addFlag(HELP_CMDLINE_OPTION, |
| 93 abbr: 'h', help: 'Print this help information', negatable: false); | 118 abbr: 'h', help: 'Print this help information', negatable: false); |
| 94 | 119 |
| 95 ArgResults args = parser.parse(rawArgs); | 120 ArgResults args; |
| 121 try { |
| 122 args = parser.parse(rawArgs); |
| 123 } on Exception catch (e) { |
| 124 print(e); |
| 125 printHelp(parser); |
| 126 exit(1); |
| 127 } |
| 128 |
| 96 bool showHelp = args[HELP_CMDLINE_OPTION] || args.rest.isNotEmpty; | 129 bool showHelp = args[HELP_CMDLINE_OPTION] || args.rest.isNotEmpty; |
| 97 | 130 |
| 98 if (args[INPUT_CMDLINE_OPTION] == null || | 131 bool isMissing(key) => args[key] == null || args[key].isEmpty; |
| 99 args[INPUT_CMDLINE_OPTION].isEmpty) { | 132 |
| 133 if (isMissing(INPUT_CMDLINE_OPTION)) { |
| 100 print('missing "input" argument'); | 134 print('missing "input" argument'); |
| 101 showHelp = true; | 135 showHelp = true; |
| 102 } | 136 } |
| 103 | 137 |
| 138 if (isMissing(MAP_FROM_OPTION) != isMissing(MAP_TO_OPTION)) { |
| 139 print('must specifiy both $MAP_FROM_OPTION and $MAP_TO_OPTION'); |
| 140 showHelp = true; |
| 141 } |
| 142 |
| 104 if (args[VERY_VERBOSE_CMDLINE_OPTION] || rawArgs.contains('-vv')) { | 143 if (args[VERY_VERBOSE_CMDLINE_OPTION] || rawArgs.contains('-vv')) { |
| 105 Logger.root.level = Level.FINE; | 144 Logger.root.level = Level.FINE; |
| 106 } else if (args[VERBOSE_CMDLINE_OPTION]) { | 145 } else if (args[VERBOSE_CMDLINE_OPTION]) { |
| 107 Logger.root.level = Level.INFO; | 146 Logger.root.level = Level.INFO; |
| 108 } else { | 147 } else { |
| 109 Logger.root.level = Level.WARNING; | 148 Logger.root.level = Level.WARNING; |
| 110 } | 149 } |
| 111 | 150 |
| 112 if (showHelp) { | 151 if (showHelp) { |
| 113 print(''); | 152 printHelp(parser); |
| 114 print('Launch and interact with the AnalysisServer'); | |
| 115 print(parser.usage); | |
| 116 exit(1); | 153 exit(1); |
| 117 } | 154 } |
| 118 | 155 |
| 119 return args; | 156 return args; |
| 120 } | 157 } |
| 158 |
| 159 void printHelp(ArgParser parser) { |
| 160 print(''); |
| 161 print('Launch and interact with the AnalysisServer'); |
| 162 print(parser.usage); |
| 163 } |
| OLD | NEW |