| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:io'; |
| |
| import 'package:analysis_server/src/protocol_server.dart'; |
| import 'package:path/path.dart' as path; |
| |
| import '../../test/integration/support/integration_tests.dart'; |
| import '../benchmarks.dart'; |
| import 'memory_tests.dart'; |
| |
| /// benchmarks: |
| /// - analysis-server-cold-analysis |
| /// - analysis-server-cold-memory |
| class ColdAnalysisBenchmark extends Benchmark { |
| ColdAnalysisBenchmark() |
| : super( |
| 'analysis-server-cold', |
| 'Analysis server benchmarks of a large project on start-up, no ' |
| 'existing driver cache.', |
| kind: 'group'); |
| |
| int get maxIterations => 3; |
| |
| @override |
| Future<BenchMarkResult> run({ |
| bool quick: false, |
| bool previewDart2: false, |
| bool verbose: false, |
| }) async { |
| if (!quick) { |
| deleteServerCache(); |
| } |
| |
| Stopwatch stopwatch = new Stopwatch()..start(); |
| |
| AnalysisServerMemoryUsageTest test = new AnalysisServerMemoryUsageTest(); |
| await test.setUp(previewDart2: previewDart2); |
| await test.subscribeToStatusNotifications(); |
| await test.sendAnalysisSetAnalysisRoots(getProjectRoots(quick: quick), []); |
| await test.analysisFinished; |
| |
| stopwatch.stop(); |
| int usedBytes = test.getMemoryUsage(); |
| |
| CompoundBenchMarkResult result = new CompoundBenchMarkResult(id); |
| result.add('analysis', |
| new BenchMarkResult('micros', stopwatch.elapsedMicroseconds)); |
| result.add('memory', new BenchMarkResult('bytes', usedBytes)); |
| |
| await test.shutdown(); |
| |
| return result; |
| } |
| } |
| |
| /// benchmarks: |
| /// - analysis-server-warm-analysis |
| /// - analysis-server-warm-memory |
| /// - analysis-server-edit |
| /// - analysis-server-completion |
| class AnalysisBenchmark extends Benchmark { |
| AnalysisBenchmark() |
| : super( |
| 'analysis-server', |
| 'Analysis server benchmarks of a large project, with an existing ' |
| 'driver cache.', |
| kind: 'group'); |
| |
| @override |
| Future<BenchMarkResult> run({ |
| bool quick: false, |
| bool previewDart2: false, |
| bool verbose: false, |
| }) async { |
| Stopwatch stopwatch = new Stopwatch()..start(); |
| |
| AnalysisServerMemoryUsageTest test = new AnalysisServerMemoryUsageTest(); |
| if (verbose) { |
| test.debugStdio(); |
| } |
| await test.setUp(previewDart2: previewDart2); |
| await test.subscribeToStatusNotifications(); |
| await test.sendAnalysisSetAnalysisRoots(getProjectRoots(quick: quick), []); |
| await test.analysisFinished; |
| |
| stopwatch.stop(); |
| int usedBytes = test.getMemoryUsage(); |
| |
| CompoundBenchMarkResult result = new CompoundBenchMarkResult(id); |
| result.add('warm-analysis', |
| new BenchMarkResult('micros', stopwatch.elapsedMicroseconds)); |
| result.add('warm-memory', new BenchMarkResult('bytes', usedBytes)); |
| |
| if (!quick) { |
| // change timing |
| final int editMicros = await _calcEditTiming(test); |
| result.add('edit', new BenchMarkResult('micros', editMicros)); |
| |
| // code completion |
| final int completionMicros = await _calcCompletionTiming(test); |
| result.add('completion', new BenchMarkResult('micros', completionMicros)); |
| } |
| |
| await test.shutdown(); |
| |
| return result; |
| } |
| |
| Future<int> _calcEditTiming( |
| AbstractAnalysisServerIntegrationTest test) async { |
| const int kGroupCount = 5; |
| |
| final String filePath = |
| path.join(analysisServerSrcPath, 'lib/src/analysis_server.dart'); |
| String contents = new File(filePath).readAsStringSync(); |
| |
| await test |
| .sendAnalysisUpdateContent({filePath: new AddContentOverlay(contents)}); |
| |
| final Stopwatch stopwatch = new Stopwatch()..start(); |
| |
| for (int i = 0; i < kGroupCount; i++) { |
| int startIndex = i * (contents.length ~/ (kGroupCount + 2)); |
| int index = contents.indexOf(';', startIndex); |
| contents = contents.substring(0, index + 1) + |
| ' ' + |
| contents.substring(index + 1); |
| test.sendAnalysisUpdateContent( |
| {filePath: new AddContentOverlay(contents)}); |
| await test.analysisFinished; |
| } |
| |
| stopwatch.stop(); |
| |
| return stopwatch.elapsedMicroseconds ~/ kGroupCount; |
| } |
| |
| Future<int> _calcCompletionTiming( |
| AbstractAnalysisServerIntegrationTest test) async { |
| const int kGroupCount = 10; |
| |
| final String filePath = |
| path.join(analysisServerSrcPath, 'lib/src/analysis_server.dart'); |
| String contents = new File(filePath).readAsStringSync(); |
| |
| await test |
| .sendAnalysisUpdateContent({filePath: new AddContentOverlay(contents)}); |
| |
| int completionCount = 0; |
| final Stopwatch stopwatch = new Stopwatch()..start(); |
| |
| Future _complete(int offset) async { |
| CompletionGetSuggestionsResult result = |
| await test.sendCompletionGetSuggestions(filePath, offset); |
| |
| Future<CompletionResultsParams> future = test.onCompletionResults |
| .where((CompletionResultsParams params) => |
| params.id == result.id && params.isLast) |
| .first; |
| await future; |
| |
| completionCount++; |
| } |
| |
| for (int i = 0; i < kGroupCount; i++) { |
| int startIndex = i * (contents.length ~/ (kGroupCount + 2)); |
| // Look for a line with a period in it that ends with a semi-colon. |
| int index = |
| contents.indexOf(new RegExp(r'\..*;$', multiLine: true), startIndex); |
| |
| await _complete(index - 10); |
| await _complete(index - 1); |
| await _complete(index); |
| await _complete(index + 1); |
| await _complete(index + 10); |
| |
| if (i + 1 < kGroupCount) { |
| // mutate |
| index = contents.indexOf(';', index); |
| contents = contents.substring(0, index + 1) + |
| ' ' + |
| contents.substring(index + 1); |
| await test.sendAnalysisUpdateContent( |
| {filePath: new AddContentOverlay(contents)}); |
| } |
| } |
| |
| stopwatch.stop(); |
| |
| return stopwatch.elapsedMicroseconds ~/ completionCount; |
| } |
| } |