diff --git a/benchmarks/FileIOSink/dart/FileIOSink.dart b/benchmarks/FileIOSink/dart/FileIOSink.dart new file mode 100644 index 00000000000..85c0cc79efc --- /dev/null +++ b/benchmarks/FileIOSink/dart/FileIOSink.dart @@ -0,0 +1,114 @@ +// 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 setup() async { + _tempDir = Directory.systemTemp.createTempSync(); + _ioSink = File(_tempDir.uri.resolve('many-small').toFilePath()).openWrite(); + } + + @override + Future teardown() async { + await _ioSink.close(); + _tempDir.deleteSync(recursive: true); + } + + @override + Future 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 setup() async { + _tempDir = Directory.systemTemp.createTempSync(); + _ioSink = File(_tempDir.uri.resolve('one-large').toFilePath()).openWrite(); + } + + @override + Future teardown() async { + await _ioSink.close(); + _tempDir.deleteSync(recursive: true); + } + + @override + Future 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 setup() async { + _tempDir = Directory.systemTemp.createTempSync(); + _ioSink = File(_tempDir.uri.resolve('alternative-add-size').toFilePath()) + .openWrite(); + } + + @override + Future teardown() async { + await _ioSink.close(); + _tempDir.deleteSync(recursive: true); + } + + @override + Future run() async { + _ioSink.add(_largeData); + _ioSink.add(_smallData); + await _ioSink.flush(); + } +} + +void main() { + final benchmarks = [ + BenchmarkManySmallAdds(), + BenchmarkOneLargeAdd(), + BenchmarkAlternatingSizedAdd(), + ]; + + for (final benchmark in benchmarks) { + benchmark.report(); + } +}