| // 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('=================================='); |
| } |
| } |