blob: a2afec1281b2d265ce482acaecc6ee664c8d60ac [file] [log] [blame]
// Copyright (c) 2025, 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:convert';
import 'dart:io';
import 'language_server_benchmark.dart';
String formatDuration(Duration duration) {
int seconds = duration.inSeconds;
int ms = duration.inMicroseconds - seconds * Duration.microsecondsPerSecond;
return '$seconds.${ms.toString().padLeft(6, '0')}';
}
String formatKb(int kb) {
if (kb > 1024) {
return '${kb ~/ 1024} MB';
} else {
return '$kb KB';
}
}
Future<void> runHelper<E, F, G>(
List<String> args,
DartLanguageServerBenchmark Function(
List<String> args,
Uri rootUri,
Uri cacheFolder,
E runDetails,
)
benchmarkCreator,
E Function(
Uri packageDirUri,
Uri outerDirForAdditionalData,
int size,
F? extraIterationData,
List<String> args, {
required G? extraInformation,
})
createDataAndCreateRunDetails, {
required bool runAsLsp,
List<int> sizeOptions = const [16, 32, 64, 128, 256, 512, 1024],
required List<F?> Function(List<String> args) extraIterations,
G? extraInformation,
}) async {
int verbosity = 0;
bool jsonOutput = false;
for (String arg in args) {
if (arg.startsWith('--sizes=')) {
sizeOptions = arg
.substring('--sizes='.length)
.split(',')
.map(int.parse)
.toList();
} else if (arg.startsWith('--verbosity=')) {
verbosity = int.parse(arg.substring('--verbosity='.length));
} else if (arg == '--json') {
jsonOutput = true;
}
}
if (jsonOutput) {
verbosity = -1;
}
StringBuffer sb = StringBuffer();
Map<String, int> jsonData = {};
for (F? extraIteration in extraIterations(args)) {
for (int size in sizeOptions) {
var caption = 'size $size / $extraIteration';
if (extraIteration == null) {
caption = 'size $size';
}
try {
Directory tmpDir = Directory.systemTemp.createTempSync(
'analysisServer_benchmark',
);
try {
Directory cacheDir = Directory.fromUri(tmpDir.uri.resolve('cache/'))
..createSync(recursive: true);
Directory dartDir = Directory.fromUri(tmpDir.uri.resolve('dart/'))
..createSync(recursive: true);
var runDetails = createDataAndCreateRunDetails(
dartDir.uri,
tmpDir.uri,
size,
extraIteration,
args,
extraInformation: extraInformation,
);
var benchmark = benchmarkCreator(
args,
dartDir.uri,
cacheDir.uri,
runDetails,
);
try {
benchmark.verbosity = verbosity;
await benchmark.run();
} finally {
benchmark.exit();
}
if (jsonOutput) {
for (var durationInfo in benchmark.durationInfo) {
var key = '$caption: ${durationInfo.name} (ms)';
if (jsonData.containsKey(key)) {
throw 'Already contains data for $key';
}
jsonData[key] = durationInfo.duration.inMilliseconds;
}
for (var memoryInfo in benchmark.memoryInfo) {
jsonData['$caption: ${memoryInfo.name} (kb)'] = memoryInfo.kb;
}
} else {
if (verbosity >= 0) print('====================');
if (verbosity >= 0) print('$caption:');
sb.writeln('$caption:');
for (var durationInfo in benchmark.durationInfo) {
if (verbosity >= 0) {
print(
'${durationInfo.name}: '
'${formatDuration(durationInfo.duration)}',
);
}
sb.writeln(
'${durationInfo.name}: '
'${formatDuration(durationInfo.duration)}',
);
}
for (var memoryInfo in benchmark.memoryInfo) {
if (verbosity >= 0) {
print(
'${memoryInfo.name}: '
'${formatKb(memoryInfo.kb)}',
);
}
sb.writeln(
'${memoryInfo.name}: '
'${formatKb(memoryInfo.kb)}',
);
}
if (verbosity >= 0) print('====================');
sb.writeln();
}
} finally {
try {
tmpDir.deleteSync(recursive: true);
} catch (e) {
// Wait a little and retry.
sleep(const Duration(milliseconds: 42));
try {
tmpDir.deleteSync(recursive: true);
} catch (e) {
if (verbosity >= 0) print('Warning: $e');
}
}
}
} catch (e) {
stderr.writeln('Error while processing $caption: $e');
}
}
}
if (jsonOutput) {
print(json.encode(jsonData));
} else {
print('==================================');
print(sb.toString().trim());
print('==================================');
}
}