Chromium Code Reviews| 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.analysis.timing; | 5 library server.performance.analysis.timing; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 10 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
| 11 import 'package:args/args.dart'; | 11 import 'package:args/args.dart'; |
| 12 import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| 13 import 'package:unittest/unittest.dart'; | 12 import 'package:unittest/unittest.dart'; |
| 14 | 13 |
| 15 import '../../test/utils.dart'; | 14 import '../../test/utils.dart'; |
| 16 import 'performance_tests.dart'; | 15 import 'performance_tests.dart'; |
| 17 | 16 |
| 18 /** | 17 /** |
| 19 * Pass in the directory of the source to be analyzed as option `--source`, | 18 * Pass in the directory of the source to be analyzed as option `--source`, |
| 20 * optionally specify a priority file with `--priority` and the specific | 19 * optionally specify a priority file with `--priority` and the specific |
| 21 * test to run with `--metric`. If no test is specified, the default is | 20 * test to run with `--metric`. If no test is specified, the default is |
| 22 * `analysis`. | 21 * `analysis`. |
| 23 */ | 22 */ |
| 24 main(List<String> arguments) { | 23 main(List<String> arguments) { |
| 25 initializeTestEnvironment(); | 24 initializeTestEnvironment(); |
| 26 ArgParser parser = _createArgParser(); | 25 ArgParser parser = _createArgParser(); |
| 27 var args = parser.parse(arguments); | 26 var args = parser.parse(arguments); |
| 28 if (args[SOURCE_OPTION] == null) { | 27 if (args[SOURCE_OPTION] == null) { |
| 29 print('path to source directory must be specified'); | 28 print('path to source directory must be specified'); |
| 30 exit(1); | 29 exit(1); |
| 31 } | 30 } |
| 32 source = args[SOURCE_OPTION]; | 31 source = args[SOURCE_OPTION]; |
| 33 priorityFile = args[PRIORITY_FILE_OPTION]; | 32 priorityFile = args[PRIORITY_FILE_OPTION]; |
| 34 metricNames.addAll(args[METRIC_NAME_OPTION]); | 33 metricNames.addAll(args[METRIC_NAME_OPTION]); |
| 35 unittestConfiguration.timeout = new Duration(minutes: 20); | 34 unittestConfiguration.timeout = new Duration(minutes: 20); |
| 36 | 35 |
| 36 var test; | |
| 37 | |
| 37 if (metricNames.isEmpty) { | 38 if (metricNames.isEmpty) { |
| 38 defineReflectiveTests(AnalysisTimingTest); | 39 test = new AnalysisTimingTest(); |
| 39 } else { | 40 } else { |
| 40 defineReflectiveTests(SubscriptionTimingTest); | 41 test = new SubscriptionTimingTest(); |
| 41 } | 42 } |
| 43 | |
| 44 Future.wait([test.test_timing()]); | |
| 42 } | 45 } |
| 43 | 46 |
| 44 const DEFAULT_METRIC = 'analysis'; | 47 const DEFAULT_METRIC = 'analysis'; |
| 45 const METRIC_NAME_OPTION = 'metric'; | 48 const METRIC_NAME_OPTION = 'metric'; |
| 46 const PRIORITY_FILE_OPTION = 'priority'; | 49 const PRIORITY_FILE_OPTION = 'priority'; |
| 47 const SOURCE_OPTION = 'source'; | 50 const SOURCE_OPTION = 'source'; |
| 48 | 51 |
| 49 final metricNames = <String>[]; | 52 final metricNames = <String>[]; |
| 50 String priorityFile; | 53 String priorityFile; |
| 51 String source; | 54 String source; |
| 52 | 55 |
| 53 ArgParser _createArgParser() => new ArgParser() | 56 ArgParser _createArgParser() => new ArgParser() |
| 54 ..addOption(METRIC_NAME_OPTION, | 57 ..addOption(METRIC_NAME_OPTION, |
| 55 help: 'metric name (defaults to `analysis`)', allowMultiple: true) | 58 help: 'metric name (defaults to `analysis`)', allowMultiple: true) |
| 56 ..addOption(SOURCE_OPTION, help: 'full path to source directory for analysis') | 59 ..addOption(SOURCE_OPTION, help: 'full path to source directory for analysis') |
| 57 ..addOption(PRIORITY_FILE_OPTION, | 60 ..addOption(PRIORITY_FILE_OPTION, |
| 58 help: '(optional) full path to a priority file'); | 61 help: '(optional) full path to a priority file'); |
| 59 | 62 |
| 60 class AbstractTimingTest extends AbstractAnalysisServerPerformanceTest { | 63 /** |
| 61 @override | 64 * AnalysisTimingTest measures the time taken by the analsyis server to fully an alyze |
| 62 Future setUp() => super.setUp().then((_) { | 65 * the given directory. Measurement is started after setting the analysis root, and |
| 63 sourceDirectory = new Directory(source); | 66 * analysis is considered complete on receiving the `"isAnalyzing": false` messa ge |
| 64 subscribeToStatusNotifications(); | 67 * from the analysis server. |
| 65 }); | 68 */ |
| 66 } | 69 class AnalysisTimingTest extends AbstractTimingTest { |
| 70 Future test_timing() async { | |
| 71 // Set root after subscribing to avoid empty notifications. | |
| 72 await init(source); | |
| 67 | 73 |
| 68 @reflectiveTest | |
| 69 class AnalysisTimingTest extends AbstractTimingTest { | |
| 70 Future test_timing() { | |
| 71 // Set root after subscribing to avoid empty notifications. | |
| 72 setAnalysisRoot(); | 74 setAnalysisRoot(); |
| 75 stopwatch.start(); | |
| 76 await analysisFinished; | |
| 77 print('analysis completed in ${stopwatch.elapsed}'); | |
| 78 stopwatch.reset(); | |
|
Brian Wilkerson
2015/10/19 22:50:32
Does 'reset' also stop the clock? If not, we shoul
keertip
2015/10/19 23:10:11
Will remove it. This is cruft from when we were tr
| |
| 73 | 79 |
| 74 stopwatch.start(); | 80 await shutdown(); |
| 75 return analysisFinished.then((_) { | |
| 76 print('analysis completed in ${stopwatch.elapsed}'); | |
| 77 stopwatch.reset(); | |
| 78 }); | |
| 79 } | 81 } |
| 80 } | 82 } |
| 81 | 83 |
| 82 class Metric { | 84 class Metric { |
| 83 List<Duration> timings = <Duration>[]; | 85 List<Duration> timings = <Duration>[]; |
| 84 Stream eventStream; | 86 Stream eventStream; |
| 85 AnalysisService service; | 87 AnalysisService service; |
| 86 String name; | 88 String name; |
| 87 Metric(this.name, this.service, this.eventStream); | 89 Metric(this.name, this.service, this.eventStream); |
| 88 String toString() => '$name: $service, ${eventStream.runtimeType}, $timings'; | 90 String toString() => '$name: $service, ${eventStream.runtimeType}, $timings'; |
| 89 } | 91 } |
| 90 | 92 |
| 91 @reflectiveTest | 93 /** |
| 94 * SubscriptionTimingTest measures the time taken by the analysis server to retu rn | |
| 95 * information for navigation, semantic highlighting, outline, get occurances, | |
| 96 * overrides, folding and implemented. These timings are wrt to the specified pr iority file | |
| 97 * - the file that is currently opened and has focus in the editor. Measure the time from | |
| 98 * when the client subscribes for the notifications till there is a response fro m the server. | |
| 99 * Does not wait for analysis to be complete before subscribing for notification s. | |
| 100 */ | |
| 92 class SubscriptionTimingTest extends AbstractTimingTest { | 101 class SubscriptionTimingTest extends AbstractTimingTest { |
| 93 List<Metric> _metrics; | 102 List<Metric> _metrics; |
| 94 | 103 |
| 95 List<Metric> get metrics => | 104 List<Metric> get metrics => |
| 96 _metrics ??= metricNames.map((name) => getMetric(name)).toList(); | 105 _metrics ??= metricNames.map((name) => getMetric(name)).toList(); |
| 97 | 106 |
| 98 Metric getMetric(String name) { | 107 Metric getMetric(String name) { |
| 99 switch (name) { | 108 switch (name) { |
| 100 case 'folding': | 109 case 'folding': |
| 101 return new Metric(name, AnalysisService.FOLDING, onAnalysisFolding); | 110 return new Metric(name, AnalysisService.FOLDING, onAnalysisFolding); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 114 return new Metric( | 123 return new Metric( |
| 115 name, AnalysisService.OCCURRENCES, onAnalysisOccurrences); | 124 name, AnalysisService.OCCURRENCES, onAnalysisOccurrences); |
| 116 case 'overrides': | 125 case 'overrides': |
| 117 return new Metric(name, AnalysisService.OVERRIDES, onAnalysisOverrides); | 126 return new Metric(name, AnalysisService.OVERRIDES, onAnalysisOverrides); |
| 118 } | 127 } |
| 119 print('no metric found for $name'); | 128 print('no metric found for $name'); |
| 120 exit(1); | 129 exit(1); |
| 121 return null; // Won't get here. | 130 return null; // Won't get here. |
| 122 } | 131 } |
| 123 | 132 |
| 124 Future test_timing() { | 133 Future test_timing() async { |
| 125 // debugStdio(); | 134 // debugStdio(); |
| 126 | 135 |
| 127 expect(metrics, isNotEmpty); | 136 expect(metrics, isNotEmpty); |
| 128 expect(priorityFile, isNotNull, | 137 expect(priorityFile, isNotNull, |
| 129 reason: 'A priority file must be specified for ' | 138 reason: 'A priority file must be specified for ' |
| 130 '${metrics.first.name} testing.'); | 139 '${metrics.first.name} testing.'); |
| 131 | 140 |
| 141 await init(source); | |
| 132 stopwatch.start(); | 142 stopwatch.start(); |
| 133 | 143 |
| 134 metrics.forEach((Metric m) => m.eventStream.listen((_) { | 144 metrics.forEach((Metric m) => m.eventStream.listen((_) { |
| 135 m.timings.add( | 145 m.timings.add( |
| 136 new Duration(milliseconds: stopwatch.elapsed.inMilliseconds)); | 146 new Duration(milliseconds: stopwatch.elapsed.inMilliseconds)); |
| 137 })); | 147 })); |
| 138 | 148 |
| 139 var subscriptions = <AnalysisService, List<String>>{}; | 149 var subscriptions = <AnalysisService, List<String>>{}; |
| 140 metrics.forEach((Metric m) => subscriptions[m.service] = [priorityFile]); | 150 metrics.forEach((Metric m) => subscriptions[m.service] = [priorityFile]); |
| 141 | 151 |
| 142 sendAnalysisSetSubscriptions(subscriptions); | 152 sendAnalysisSetSubscriptions(subscriptions); |
| 143 | 153 |
| 144 // Set root after subscribing to avoid empty notifications. | 154 // Set root after subscribing to avoid empty notifications. |
| 145 setAnalysisRoot(); | 155 setAnalysisRoot(); |
| 146 | 156 |
| 147 sendAnalysisSetPriorityFiles([priorityFile]); | 157 sendAnalysisSetPriorityFiles([priorityFile]); |
| 148 | 158 |
| 149 return analysisFinished.then((_) { | 159 await analysisFinished; |
| 150 print('analysis completed in ${stopwatch.elapsed}'); | 160 print('analysis completed in ${stopwatch.elapsed}'); |
| 151 metrics.forEach((Metric m) => print('${m.name} timings: ${m.timings}')); | 161 metrics.forEach((Metric m) => print('${m.name} timings: ${m.timings}')); |
| 152 stopwatch.reset(); | 162 stopwatch.reset(); |
| 153 }); | 163 |
| 164 await shutdown(); | |
| 154 } | 165 } |
| 155 } | 166 } |
| OLD | NEW |