| // 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. |
| |
| /// Micro-benchmark for the [IOSink] returned by [File.openWrite]. |
| |
| import 'dart:io'; |
| import 'dart:typed_data'; |
| |
| import 'package:benchmark_harness/benchmark_harness.dart'; |
| |
| const numBytesToWrite = 200000; // Write 200KiB in all benchmarks runs. |
| |
| /// Benchmark building a [numBytesToWrite] byte file a single byte at a time. |
| /// |
| /// Based on https://github.com/dart-lang/sdk/issues/32874#issue-314022259 |
| class BenchmarkManySmallAdds extends AsyncBenchmarkBase { |
| late Directory _tempDir; |
| late IOSink _ioSink; |
| final _singleByte = Uint8List(1); |
| |
| BenchmarkManySmallAdds() : super('FileIOSink.Add.ManySmall'); |
| |
| @override |
| Future<void> setup() async { |
| _tempDir = Directory.systemTemp.createTempSync(); |
| _ioSink = File(_tempDir.uri.resolve('many-small').toFilePath()).openWrite(); |
| } |
| |
| @override |
| Future<void> teardown() async { |
| await _ioSink.close(); |
| _tempDir.deleteSync(recursive: true); |
| } |
| |
| @override |
| Future<void> run() async { |
| for (var i = 0; i < numBytesToWrite; ++i) { |
| _ioSink.add(_singleByte); |
| } |
| await _ioSink.flush(); |
| } |
| } |
| |
| /// Benchmark building a [numBytesToWrite] byte file with a single call to |
| /// [IOSink.add]. |
| class BenchmarkOneLargeAdd extends AsyncBenchmarkBase { |
| late final Directory _tempDir; |
| late final IOSink _ioSink; |
| final _largeData = Uint8List(numBytesToWrite); |
| |
| BenchmarkOneLargeAdd() : super('FileIOSink.Add.OneLarge'); |
| |
| @override |
| Future<void> setup() async { |
| _tempDir = Directory.systemTemp.createTempSync(); |
| _ioSink = File(_tempDir.uri.resolve('one-large').toFilePath()).openWrite(); |
| } |
| |
| @override |
| Future<void> teardown() async { |
| await _ioSink.close(); |
| _tempDir.deleteSync(recursive: true); |
| } |
| |
| @override |
| Future<void> run() async { |
| _ioSink.add(_largeData); |
| await _ioSink.flush(); |
| } |
| } |
| |
| /// Benchmark building a file by alternating calls to [IOSink.add] with large |
| /// and small amounts of data. |
| class BenchmarkAlternatingSizedAdd extends AsyncBenchmarkBase { |
| late final Directory _tempDir; |
| late final IOSink _ioSink; |
| final _largeData = Uint8List(numBytesToWrite - 1); |
| final _smallData = Uint8List(1); |
| |
| BenchmarkAlternatingSizedAdd() : super('FileIOSink.Add.AlternatingAddSize'); |
| |
| @override |
| Future<void> setup() async { |
| _tempDir = Directory.systemTemp.createTempSync(); |
| _ioSink = File(_tempDir.uri.resolve('alternative-add-size').toFilePath()) |
| .openWrite(); |
| } |
| |
| @override |
| Future<void> teardown() async { |
| await _ioSink.close(); |
| _tempDir.deleteSync(recursive: true); |
| } |
| |
| @override |
| Future<void> run() async { |
| _ioSink.add(_largeData); |
| _ioSink.add(_smallData); |
| await _ioSink.flush(); |
| } |
| } |
| |
| void main() async { |
| final benchmarks = [ |
| BenchmarkManySmallAdds(), |
| BenchmarkOneLargeAdd(), |
| BenchmarkAlternatingSizedAdd(), |
| ]; |
| |
| for (final benchmark in benchmarks) { |
| await benchmark.report(); |
| } |
| } |