| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library server.performance; | 5 library server.performance; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 25); | 22 const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 25); |
| 23 | 23 |
| 24 /** | 24 /** |
| 25 * Launch and interact with the analysis server. | 25 * Launch and interact with the analysis server. |
| 26 */ | 26 */ |
| 27 main(List<String> rawArgs) { | 27 main(List<String> rawArgs) { |
| 28 Logger logger = new Logger('Performance Measurement Client'); | 28 Logger logger = new Logger('Performance Measurement Client'); |
| 29 logger.onRecord.listen((LogRecord rec) { | 29 logger.onRecord.listen((LogRecord rec) { |
| 30 print(rec.message); | 30 print(rec.message); |
| 31 }); | 31 }); |
| 32 ArgResults args = parseArgs(rawArgs); | 32 PerfArgs args = parseArgs(rawArgs); |
| 33 | 33 |
| 34 Driver driver = new Driver(logger); | 34 Driver driver = new Driver(logger); |
| 35 Stream<Operation> stream = openInput(args); | 35 Stream<Operation> stream = openInput(args); |
| 36 StreamSubscription<Operation> subscription; | 36 StreamSubscription<Operation> subscription; |
| 37 subscription = stream.listen((Operation op) { | 37 subscription = stream.listen((Operation op) { |
| 38 Future future = driver.perform(op); | 38 Future future = driver.perform(op); |
| 39 if (future != null) { | 39 if (future != null) { |
| 40 logger.log(Level.FINE, 'pausing operations for ${op.runtimeType}'); | 40 logger.log(Level.FINE, 'pausing operations for ${op.runtimeType}'); |
| 41 subscription.pause(future.then((_) { | 41 subscription.pause(future.then((_) { |
| 42 logger.log(Level.FINE, 'resuming operations'); | 42 logger.log(Level.FINE, 'resuming operations'); |
| 43 })); | 43 })); |
| 44 } | 44 } |
| 45 }, onDone: () { | 45 }, onDone: () { |
| 46 subscription.cancel(); | 46 subscription.cancel(); |
| 47 driver.stopServer(SHUTDOWN_TIMEOUT); | 47 driver.stopServer(SHUTDOWN_TIMEOUT); |
| 48 }, onError: (e, s) { | 48 }, onError: (e, s) { |
| 49 subscription.cancel(); | 49 subscription.cancel(); |
| 50 logger.log(Level.SEVERE, '$e\n$s'); | 50 logger.log(Level.SEVERE, '$e\n$s'); |
| 51 driver.stopServer(SHUTDOWN_TIMEOUT); | 51 driver.stopServer(SHUTDOWN_TIMEOUT); |
| 52 }); | 52 }); |
| 53 driver.runComplete.then((Results results) { | 53 driver.runComplete.then((Results results) { |
| 54 results.printResults(); | 54 results.printResults(); |
| 55 }).whenComplete(() { | 55 }).whenComplete(() { |
| 56 return subscription.cancel(); | 56 return subscription.cancel(); |
| 57 }); | 57 }); |
| 58 } | 58 } |
| 59 | 59 |
| 60 const HELP_CMDLINE_OPTION = 'help'; | 60 const HELP_CMDLINE_OPTION = 'help'; |
| 61 const INPUT_CMDLINE_OPTION = 'input'; | 61 const INPUT_CMDLINE_OPTION = 'input'; |
| 62 const MAP_FROM_OPTION = 'mapFrom'; | 62 const MAP_OPTION = 'map'; |
| 63 const MAP_TO_OPTION = 'mapTo'; | |
| 64 const TMP_SRC_DIR_OPTION = 'tmpSrcDir'; | 63 const TMP_SRC_DIR_OPTION = 'tmpSrcDir'; |
| 65 const VERBOSE_CMDLINE_OPTION = 'verbose'; | 64 const VERBOSE_CMDLINE_OPTION = 'verbose'; |
| 66 const VERY_VERBOSE_CMDLINE_OPTION = 'vv'; | 65 const VERY_VERBOSE_CMDLINE_OPTION = 'vv'; |
| 67 | 66 |
| 68 /** | 67 /** |
| 69 * Open and return the input stream specifying how this client | 68 * Open and return the input stream specifying how this client |
| 70 * should interact with the analysis server. | 69 * should interact with the analysis server. |
| 71 */ | 70 */ |
| 72 Stream<Operation> openInput(ArgResults args) { | 71 Stream<Operation> openInput(PerfArgs args) { |
| 73 var logger = new Logger('openInput'); | 72 var logger = new Logger('openInput'); |
| 74 Stream<List<int>> inputRaw; | 73 Stream<List<int>> inputRaw; |
| 75 String inputPath = args[INPUT_CMDLINE_OPTION]; | 74 if (args.inputPath == 'stdin') { |
| 76 if (inputPath == null) { | |
| 77 return null; | |
| 78 } | |
| 79 if (inputPath == 'stdin') { | |
| 80 inputRaw = stdin; | 75 inputRaw = stdin; |
| 81 } else { | 76 } else { |
| 82 inputRaw = new File(inputPath).openRead(); | 77 inputRaw = new File(args.inputPath).openRead(); |
| 83 } | 78 } |
| 84 Map<String, String> srcPathMap = new Map<String, String>(); | 79 args.srcPathMap.forEach((oldPath, newPath) { |
| 85 String mapFrom = args[MAP_FROM_OPTION]; | |
| 86 if (mapFrom != null && mapFrom.isNotEmpty) { | |
| 87 String mapTo = args[MAP_TO_OPTION]; | |
| 88 srcPathMap[mapFrom] = mapTo; | |
| 89 logger.log( | 80 logger.log( |
| 90 Level.INFO, 'mapping source paths\n from $mapFrom\n to $mapTo'); | 81 Level.INFO, 'mapping source path\n from $oldPath\n to $newPath'); |
| 91 } | 82 }); |
| 92 String tmpSrcDirPath = args[TMP_SRC_DIR_OPTION]; | 83 logger.log(Level.INFO, 'tmpSrcDir: ${args.tmpSrcDirPath}'); |
| 93 logger.log(Level.INFO, 'tmpSrcDir: $tmpSrcDirPath'); | |
| 94 return inputRaw | 84 return inputRaw |
| 95 .transform(SYSTEM_ENCODING.decoder) | 85 .transform(SYSTEM_ENCODING.decoder) |
| 96 .transform(new LineSplitter()) | 86 .transform(new LineSplitter()) |
| 97 .transform(new InputConverter(tmpSrcDirPath, srcPathMap)); | 87 .transform(new InputConverter(args.tmpSrcDirPath, args.srcPathMap)); |
| 98 } | 88 } |
| 99 | 89 |
| 100 /** | 90 /** |
| 101 * Parse the command line arguments. | 91 * Parse the command line arguments. |
| 102 */ | 92 */ |
| 103 ArgResults parseArgs(List<String> rawArgs) { | 93 PerfArgs parseArgs(List<String> rawArgs) { |
| 104 ArgParser parser = new ArgParser(); | 94 ArgParser parser = new ArgParser(); |
| 105 | 95 |
| 106 parser.addOption(INPUT_CMDLINE_OPTION, abbr: 'i', help: '<filePath>\n' | 96 parser.addOption(INPUT_CMDLINE_OPTION, abbr: 'i', help: '<filePath>\n' |
| 107 'The input file specifying how this client should interact with the server
.\n' | 97 'The input file specifying how this client should interact with the server
.\n' |
| 108 'If the input file name is "stdin", then the instructions are read from st
andard input.'); | 98 'If the input file name is "stdin", then the instructions are read from st
andard input.'); |
| 109 parser.addOption(MAP_FROM_OPTION, | 99 parser.addOption(MAP_OPTION, |
| 110 help: 'The original source directory when the instrumentation ' | 100 abbr: 'm', |
| 111 'or log file was generated.'); | 101 allowMultiple: true, |
| 112 parser.addOption(MAP_TO_OPTION, | 102 splitCommas: false, |
| 113 help: 'The target source directory used during performance testing. ' | 103 help: '<oldSrcPath>,<newSrcPath>\n' |
| 114 'WARNING: The contents of this directory will be modified'); | 104 'This option defines a mapping from the original source directory <oldSrcP
ath>\n' |
| 105 'when the instrumentation or log file was generated\n' |
| 106 'to the target source directory <newSrcPath> used during performance testi
ng.\n' |
| 107 'Multiple mappings can be specified.\n' |
| 108 'WARNING: The contents of the target directory will be modified'); |
| 115 parser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n' | 109 parser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n' |
| 116 'The temporary directory containing source used during performance measure
ment.\n' | 110 'The temporary directory containing source used during performance measure
ment.\n' |
| 117 'WARNING: The contents of the target directory will be modified'); | 111 'WARNING: The contents of the target directory will be modified'); |
| 118 parser.addFlag(VERBOSE_CMDLINE_OPTION, | 112 parser.addFlag(VERBOSE_CMDLINE_OPTION, |
| 119 abbr: 'v', help: 'Verbose logging', negatable: false); | 113 abbr: 'v', help: 'Verbose logging', negatable: false); |
| 120 parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION, | 114 parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION, |
| 121 help: 'Extra verbose logging', negatable: false); | 115 help: 'Extra verbose logging', negatable: false); |
| 122 parser.addFlag(HELP_CMDLINE_OPTION, | 116 parser.addFlag(HELP_CMDLINE_OPTION, |
| 123 abbr: 'h', help: 'Print this help information', negatable: false); | 117 abbr: 'h', help: 'Print this help information', negatable: false); |
| 124 | 118 |
| 125 ArgResults args; | 119 ArgResults args; |
| 120 PerfArgs perfArgs = new PerfArgs(); |
| 126 try { | 121 try { |
| 127 args = parser.parse(rawArgs); | 122 args = parser.parse(rawArgs); |
| 128 } on Exception catch (e) { | 123 } on Exception catch (e) { |
| 129 print(e); | 124 print(e); |
| 130 printHelp(parser); | 125 printHelp(parser); |
| 131 exit(1); | 126 exit(1); |
| 132 } | 127 } |
| 133 | 128 |
| 134 bool showHelp = args[HELP_CMDLINE_OPTION] || args.rest.isNotEmpty; | 129 bool showHelp = args[HELP_CMDLINE_OPTION] || args.rest.isNotEmpty; |
| 135 | 130 |
| 136 bool isMissing(key) => args[key] == null || args[key].isEmpty; | 131 bool isMissing(key) => args[key] == null || args[key].isEmpty; |
| 137 | 132 |
| 133 perfArgs.inputPath = args[INPUT_CMDLINE_OPTION]; |
| 138 if (isMissing(INPUT_CMDLINE_OPTION)) { | 134 if (isMissing(INPUT_CMDLINE_OPTION)) { |
| 139 print('missing $INPUT_CMDLINE_OPTION argument'); | 135 print('missing $INPUT_CMDLINE_OPTION argument'); |
| 140 showHelp = true; | 136 showHelp = true; |
| 141 } | 137 } |
| 142 | 138 |
| 143 if (isMissing(MAP_FROM_OPTION) != isMissing(MAP_TO_OPTION)) { | 139 perfArgs.srcPathMap = <String, String>{}; |
| 144 print('must specifiy both $MAP_FROM_OPTION and $MAP_TO_OPTION'); | 140 for (String pair in args[MAP_OPTION]) { |
| 141 if (pair is String) { |
| 142 int index = pair.indexOf(','); |
| 143 if (index != -1 && pair.indexOf(',', index + 1) == -1) { |
| 144 String oldSrcPath = pair.substring(0, index); |
| 145 String newSrcPath = pair.substring(index + 1); |
| 146 if (new Directory(oldSrcPath).existsSync() && |
| 147 new Directory(newSrcPath).existsSync()) { |
| 148 perfArgs.srcPathMap[oldSrcPath] = newSrcPath; |
| 149 continue; |
| 150 } |
| 151 } |
| 152 } |
| 153 print('must specifiy $MAP_OPTION <oldSrcPath>,<newSrcPath>'); |
| 145 showHelp = true; | 154 showHelp = true; |
| 146 } | 155 } |
| 147 | 156 |
| 157 perfArgs.tmpSrcDirPath = args[TMP_SRC_DIR_OPTION]; |
| 148 if (isMissing(TMP_SRC_DIR_OPTION)) { | 158 if (isMissing(TMP_SRC_DIR_OPTION)) { |
| 149 print('missing $TMP_SRC_DIR_OPTION argument'); | 159 print('missing $TMP_SRC_DIR_OPTION argument'); |
| 150 showHelp = true; | 160 showHelp = true; |
| 151 } | 161 } |
| 152 | 162 |
| 153 if (args[VERY_VERBOSE_CMDLINE_OPTION] || rawArgs.contains('-vv')) { | 163 if (args[VERY_VERBOSE_CMDLINE_OPTION] || rawArgs.contains('-vv')) { |
| 154 Logger.root.level = Level.FINE; | 164 Logger.root.level = Level.FINE; |
| 155 } else if (args[VERBOSE_CMDLINE_OPTION]) { | 165 } else if (args[VERBOSE_CMDLINE_OPTION]) { |
| 156 Logger.root.level = Level.INFO; | 166 Logger.root.level = Level.INFO; |
| 157 } else { | 167 } else { |
| 158 Logger.root.level = Level.WARNING; | 168 Logger.root.level = Level.WARNING; |
| 159 } | 169 } |
| 160 | 170 |
| 161 if (showHelp) { | 171 if (showHelp) { |
| 162 printHelp(parser); | 172 printHelp(parser); |
| 163 exit(1); | 173 exit(1); |
| 164 } | 174 } |
| 165 | 175 |
| 166 return args; | 176 return perfArgs; |
| 167 } | 177 } |
| 168 | 178 |
| 169 void printHelp(ArgParser parser) { | 179 void printHelp(ArgParser parser) { |
| 170 print(''); | 180 print(''); |
| 171 print('Launch and interact with the AnalysisServer'); | 181 print('Launch and interact with the AnalysisServer'); |
| 172 print(''); | 182 print(''); |
| 173 print(parser.usage); | 183 print(parser.usage); |
| 174 } | 184 } |
| 185 |
| 186 /** |
| 187 * The performance measurement arguments specified on the command line. |
| 188 */ |
| 189 class PerfArgs { |
| 190 |
| 191 /** |
| 192 * The file path of the instrumentation or log file |
| 193 * used to drive performance measurement, |
| 194 * or 'stdin' if this information should be read from standard input. |
| 195 */ |
| 196 String inputPath; |
| 197 |
| 198 /** |
| 199 * A mapping from the original source directory |
| 200 * when the instrumentation or log file was generated |
| 201 * to the target source directory used during performance testing. |
| 202 */ |
| 203 Map<String, String> srcPathMap; |
| 204 |
| 205 /** |
| 206 * The temporary directory containing source used during performance measureme
nt. |
| 207 */ |
| 208 String tmpSrcDirPath; |
| 209 } |
| OLD | NEW |