fbf331e0dd
Change-Id: I42b4a44fd6a2197e499e8623274b3cd1a4b5556f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394003 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
227 lines
6.1 KiB
Dart
227 lines
6.1 KiB
Dart
// 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:path/path.dart' as path;
|
|
|
|
import '../benchmarks.dart';
|
|
import 'memory_tests.dart';
|
|
|
|
/// benchmarks:
|
|
/// - analysis-server-warm-analysis
|
|
/// - analysis-server-warm-memory
|
|
/// - analysis-server-edit
|
|
/// - analysis-server-completion
|
|
class AnalysisBenchmark extends Benchmark {
|
|
final AbstractBenchmarkTest Function() testConstructor;
|
|
|
|
AnalysisBenchmark(ServerBenchmark benchmarkTest)
|
|
: testConstructor = benchmarkTest.testConstructor,
|
|
super(
|
|
benchmarkTest.id,
|
|
'${benchmarkTest.name} benchmarks of a large project, with an existing '
|
|
'driver cache.',
|
|
kind: 'group',
|
|
);
|
|
|
|
@override
|
|
Future<BenchMarkResult> run({
|
|
required String dartSdkPath,
|
|
bool quick = false,
|
|
bool verbose = false,
|
|
}) async {
|
|
var stopwatch = Stopwatch()..start();
|
|
|
|
var test = testConstructor();
|
|
if (verbose) {
|
|
test.debugStdio();
|
|
}
|
|
await test.setUp(dartSdkPath, getProjectRoots(quick: quick));
|
|
await test.analysisFinished;
|
|
|
|
stopwatch.stop();
|
|
var usedBytes = await test.getMemoryUsage();
|
|
|
|
var result = CompoundBenchMarkResult(id);
|
|
result.add(
|
|
'warm-analysis',
|
|
BenchMarkResult('micros', stopwatch.elapsedMicroseconds),
|
|
);
|
|
result.add('warm-memory', BenchMarkResult('bytes', usedBytes));
|
|
|
|
if (!quick) {
|
|
// change timing
|
|
var editMicros = await _calcEditTiming(test);
|
|
result.add('edit', BenchMarkResult('micros', editMicros));
|
|
|
|
// code completion
|
|
var completionMicros = await _calcCompletionTiming(test);
|
|
result.add('completion', BenchMarkResult('micros', completionMicros));
|
|
}
|
|
|
|
await test.shutdown();
|
|
|
|
return result;
|
|
}
|
|
|
|
Future<int> _calcCompletionTiming(AbstractBenchmarkTest test) async {
|
|
const kGroupCount = 10;
|
|
|
|
var filePath = path.join(
|
|
analysisServerSrcPath,
|
|
'lib',
|
|
'src',
|
|
'analysis_server.dart',
|
|
);
|
|
var contents = File(filePath).readAsStringSync();
|
|
|
|
await test.openFile(filePath, contents);
|
|
|
|
var completionCount = 0;
|
|
var stopwatch = Stopwatch()..start();
|
|
|
|
Future<void> complete(int offset) async {
|
|
await test.complete(filePath, offset, isWarmUp: false);
|
|
completionCount++;
|
|
}
|
|
|
|
for (var i = 0; i < kGroupCount; i++) {
|
|
var startIndex = i * (contents.length ~/ (kGroupCount + 2));
|
|
// Look for a line with a period in it that ends with a semi-colon.
|
|
var index = contents.indexOf(
|
|
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.updateFile(filePath, contents);
|
|
}
|
|
}
|
|
|
|
stopwatch.stop();
|
|
|
|
await test.closeFile(filePath);
|
|
|
|
return stopwatch.elapsedMicroseconds ~/ completionCount;
|
|
}
|
|
|
|
Future<int> _calcEditTiming(AbstractBenchmarkTest test) async {
|
|
const kGroupCount = 5;
|
|
|
|
var filePath = path.join(
|
|
analysisServerSrcPath,
|
|
'lib',
|
|
'src',
|
|
'analysis_server.dart',
|
|
);
|
|
var contents = File(filePath).readAsStringSync();
|
|
|
|
// Get the future for `analysisFinished` *before* the call to [openFile]
|
|
// as the analysis triggered by opening is sometimes so fast that it
|
|
// finishes before starting to listen if only starting *after* the call to
|
|
// [openFile].
|
|
Future<void> analysisFinished = test.analysisFinished;
|
|
await test.openFile(filePath, contents);
|
|
await analysisFinished;
|
|
|
|
var stopwatch = Stopwatch()..start();
|
|
|
|
for (var i = 0; i < kGroupCount; i++) {
|
|
var startIndex = i * (contents.length ~/ (kGroupCount + 2));
|
|
var index = contents.indexOf(';', startIndex);
|
|
contents =
|
|
'${contents.substring(0, index + 1)} ${contents.substring(index + 1)}';
|
|
await test.updateFile(filePath, contents);
|
|
await test.analysisFinished;
|
|
}
|
|
|
|
stopwatch.stop();
|
|
|
|
await test.closeFile(filePath);
|
|
|
|
return stopwatch.elapsedMicroseconds ~/ kGroupCount;
|
|
}
|
|
}
|
|
|
|
/// benchmarks:
|
|
/// - analysis-server-cold-analysis
|
|
/// - analysis-server-cold-memory
|
|
class ColdAnalysisBenchmark extends Benchmark {
|
|
final AbstractBenchmarkTest Function() testConstructor;
|
|
|
|
ColdAnalysisBenchmark(ServerBenchmark benchmarkTest)
|
|
: testConstructor = benchmarkTest.testConstructor,
|
|
super(
|
|
'${benchmarkTest.id}-cold',
|
|
'${benchmarkTest.name} benchmarks of a large project on start-up, no '
|
|
'existing driver cache.',
|
|
kind: 'group',
|
|
);
|
|
|
|
@override
|
|
int get maxIterations => 3;
|
|
|
|
@override
|
|
Future<BenchMarkResult> run({
|
|
required String dartSdkPath,
|
|
bool quick = false,
|
|
bool verbose = false,
|
|
}) async {
|
|
if (!quick) {
|
|
deleteServerCache();
|
|
}
|
|
|
|
var stopwatch = Stopwatch()..start();
|
|
|
|
var test = testConstructor();
|
|
await test.setUp(dartSdkPath, getProjectRoots(quick: quick));
|
|
await test.analysisFinished;
|
|
|
|
stopwatch.stop();
|
|
var usedBytes = await test.getMemoryUsage();
|
|
|
|
var result = CompoundBenchMarkResult(id);
|
|
result.add(
|
|
'analysis',
|
|
BenchMarkResult('micros', stopwatch.elapsedMicroseconds),
|
|
);
|
|
result.add('memory', BenchMarkResult('bytes', usedBytes));
|
|
|
|
await test.shutdown();
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class ServerBenchmark {
|
|
static final das = ServerBenchmark(
|
|
'analysis-server',
|
|
'Analysis Server',
|
|
AnalysisServerBenchmarkTest.new,
|
|
);
|
|
static final lsp = ServerBenchmark(
|
|
'lsp-analysis-server',
|
|
'LSP Analysis Server',
|
|
LspAnalysisServerBenchmarkTest.new,
|
|
);
|
|
final String id;
|
|
|
|
final String name;
|
|
final AbstractBenchmarkTest Function() testConstructor;
|
|
|
|
ServerBenchmark(this.id, this.name, this.testConstructor);
|
|
}
|