Skip to content

IOSink and many small .adds is slow #32874

Description

@jensjoha

On current head (not that I think it has changed lately) I see the following:

Having many small .adds on an IOList is very slow, and I seem to have to buffer it myself.
E.g. the following example:

import 'dart:io';
import 'dart:convert';
import 'dart:typed_data';

Utf8Encoder utf8Encoder = const Utf8Encoder();

main() async {
  final int count = 100000;
  // Warmup
  await unbuffered(10000);

  Stopwatch stopwatch = new Stopwatch()..start();
  await buffered(count, 10 * 1024 /* 10 KB buffer */);
  print("Buffered => ${stopwatch.elapsedMilliseconds} ms");

  stopwatch.reset();
  await unbuffered(count);
  print("Unbuffered => ${stopwatch.elapsedMilliseconds} ms");
}

void unbuffered(int count) async {
  File f = new File("io_unbuffered_test");
  IOSink sink = f.openWrite();
  for (int i = 0; i < count; i++) {
    String s = "foo_$i";
    List<int> data = utf8Encoder.convert(s);
    sink.add(data);
  }
  await sink.flush();
  await sink.close();
}

void buffered(int count, int bufferSize) async {
  File f = new File("io_buffered_test");
  IOSink sink = f.openWrite();
  int size = 0;
  Uint8List buffer = new Uint8List(bufferSize);
  for (int i = 0; i < count; i++) {
    String s = "foo_$i";
    List<int> data = utf8Encoder.convert(s);
    if (size + data.length > bufferSize || data.length > bufferSize) {
      sink.add(buffer.sublist(0, size));
      size = 0;
      buffer = new Uint8List(bufferSize);
    }
    if (data.length > bufferSize) {
      sink.add(data);
    } else {
      buffer.setRange(size, size + data.length, data);
      size += data.length;
    }
  }
  sink.add(buffer.sublist(0, size));
  await sink.flush();
  await sink.close();
}

has the following output on my machine:

Buffered => 22 ms
Unbuffered => 2383 ms

So as a thanks for writing 24 lines of code instead of 11 I get a 100x+ speedup...
Is this intentional, and am I really supposed to write the buffering code myself?

/cc @lrhn
/cc @zanderso

Metadata

Metadata

Assignees

Labels

P2A bug or feature request we're likely to work onarea-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.library-iotriagedIssue has been triaged by sub teamtype-performanceIssue relates to performance or code size

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions