blob: 17bf40f269ad691872fa31bce903166b7b6881f0 [file] [log] [blame]
// Copyright (c) 2023, 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.
// This script runs the benchmarks in this directory and uploads the
// results to cloud storage. These results are then ingested by our
// performance measurement system.
//
// The script only works when run on a LUCI builder in the dart-ci project,
// and uploads results to paths within gs://dart-test-results/benchmark-results.
//
// This script is needed to run benchmarks on platforms that we only have
// in our LUCI CI system, not in our performance lab, such as Windows.
// The script is currently only used and tested on Windows.
import 'dart:convert';
import 'dart:io';
void main(List<String> args) async {
try {
var results = <Map<String, dynamic>>[];
for (int i = 0; i < countRuns; ++i) {
results.addAll(await runBenchmarks(warm: true));
results.addAll(await runBenchmarks(warm: false));
}
if (!Platform.isWindows) {
print('Analyzer benchmark uploads only run on Windows');
exit(1);
}
var targetResults = [
for (final result in results)
{
'cpu': 'Windows VM',
'machineType': 'windows-x64',
'target': 'dart-analysis-server-external',
...result,
}
];
await uploadResults(targetResults);
} catch (e, st) {
print('$e\n$st');
}
}
const countRuns = 2;
Future<List<Map<String, dynamic>>> runBenchmarks({required bool warm}) async {
var temperature = warm ? 'warm' : 'cold';
var benchmarkResults = await Process.run(Platform.resolvedExecutable, [
'pkg/analysis_server/benchmark/benchmarks.dart',
'run',
if (warm) 'analysis-server' else 'analysis-server-cold',
]);
print(benchmarkResults.stdout);
print(benchmarkResults.stderr);
if (benchmarkResults.exitCode != 0) {
throw 'Failed to run $temperature benchmarks';
}
var result = jsonDecode(LineSplitter()
.convert(benchmarkResults.stdout as String)
.where((line) => line.startsWith('{"benchmark":'))
.single);
return <Map<String, dynamic>>[
{
'benchmark': 'analysis-server-$temperature-memory',
'metric': 'MemoryUse',
'score': result['result']['analysis-server-$temperature-memory']['bytes'],
},
{
'benchmark': 'analysis-server-$temperature-analysis',
'metric': 'RunTimeRaw',
'score': result['result']['analysis-server-$temperature-analysis']
['micros'],
},
if (warm)
{
'benchmark': 'analysis-server-edit',
'metric': 'RunTimeRaw',
'score': result['result']['analysis-server-edit']['micros'],
},
if (warm)
{
'benchmark': 'analysis-server-completion',
'metric': 'RunTimeRaw',
'score': result['result']['analysis-server-completion']['micros'],
}
];
}
Future<void> uploadResults(List<Map<String, dynamic>> results) async {
// Create JSON results in the desired format
// Write results file to cloud storage.
var tempDir =
await Directory.systemTemp.createTemp('analysis-server-benchmarks');
try {
var resultsJson = jsonEncode(results);
var resultsFile = File.fromUri(tempDir.uri.resolve('results.json'));
resultsFile.writeAsStringSync(resultsJson, flush: true);
var taskId = Platform.environment['SWARMING_TASK_ID'] ?? 'test_task_id';
if (taskId == 'test_task_id') {
print('Benchmark_uploader requires SWARMING_TASK_ID in the environment.');
}
var cloudStoragePath =
'gs://dart-test-results/benchmarks/$taskId/results.json';
var args = [
'third_party/gsutil/gsutil',
'cp',
resultsFile.path,
cloudStoragePath
];
var python = 'python3.exe';
print('Running $python ${args.join(' ')}');
var commandResult = await Process.run(python, args);
var exitCode = commandResult.exitCode;
print(commandResult.stdout);
print(commandResult.stderr);
print('exit code: $exitCode');
if (exitCode != 0) {
throw 'Gsutil upload failed. Exit code $exitCode';
}
} finally {
await tempDir.delete(recursive: true);
}
}