mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
[io] Avoid serializing unwritten bytes in async I/O.
TEST=ci Bug: https://github.com/dart-lang/sdk/issues/50206 Change-Id: Ibe6c326578ec4a2ca90634714e4628c02a5e5bcc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264260 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
63f957a687
commit
d2a43581a3
|
@ -2140,45 +2140,59 @@ class TypedDataViewMessageDeserializationCluster
|
|||
Dart_TypedData_Type type;
|
||||
switch (cid_) {
|
||||
case kTypedDataInt8ArrayViewCid:
|
||||
case kUnmodifiableTypedDataInt8ArrayViewCid:
|
||||
type = Dart_TypedData_kInt8;
|
||||
break;
|
||||
case kTypedDataUint8ArrayViewCid:
|
||||
case kUnmodifiableTypedDataUint8ArrayViewCid:
|
||||
type = Dart_TypedData_kUint8;
|
||||
break;
|
||||
case kTypedDataUint8ClampedArrayViewCid:
|
||||
case kUnmodifiableTypedDataUint8ClampedArrayViewCid:
|
||||
type = Dart_TypedData_kUint8Clamped;
|
||||
break;
|
||||
case kTypedDataInt16ArrayViewCid:
|
||||
case kUnmodifiableTypedDataInt16ArrayViewCid:
|
||||
type = Dart_TypedData_kInt16;
|
||||
break;
|
||||
case kTypedDataUint16ArrayViewCid:
|
||||
case kUnmodifiableTypedDataUint16ArrayViewCid:
|
||||
type = Dart_TypedData_kUint16;
|
||||
break;
|
||||
case kTypedDataInt32ArrayViewCid:
|
||||
case kUnmodifiableTypedDataInt32ArrayViewCid:
|
||||
type = Dart_TypedData_kInt32;
|
||||
break;
|
||||
case kTypedDataUint32ArrayViewCid:
|
||||
case kUnmodifiableTypedDataUint32ArrayViewCid:
|
||||
type = Dart_TypedData_kUint32;
|
||||
break;
|
||||
case kTypedDataInt64ArrayViewCid:
|
||||
case kUnmodifiableTypedDataInt64ArrayViewCid:
|
||||
type = Dart_TypedData_kInt64;
|
||||
break;
|
||||
case kTypedDataUint64ArrayViewCid:
|
||||
case kUnmodifiableTypedDataUint64ArrayViewCid:
|
||||
type = Dart_TypedData_kUint64;
|
||||
break;
|
||||
case kTypedDataFloat32ArrayViewCid:
|
||||
case kUnmodifiableTypedDataFloat32ArrayViewCid:
|
||||
type = Dart_TypedData_kFloat32;
|
||||
break;
|
||||
case kTypedDataFloat64ArrayViewCid:
|
||||
case kUnmodifiableTypedDataFloat64ArrayViewCid:
|
||||
type = Dart_TypedData_kFloat64;
|
||||
break;
|
||||
case kTypedDataInt32x4ArrayViewCid:
|
||||
case kUnmodifiableTypedDataInt32x4ArrayViewCid:
|
||||
type = Dart_TypedData_kInt32x4;
|
||||
break;
|
||||
case kTypedDataFloat32x4ArrayViewCid:
|
||||
case kUnmodifiableTypedDataFloat32x4ArrayViewCid:
|
||||
type = Dart_TypedData_kFloat32x4;
|
||||
break;
|
||||
case kTypedDataFloat64x2ArrayViewCid:
|
||||
case kUnmodifiableTypedDataFloat64x2ArrayViewCid:
|
||||
type = Dart_TypedData_kFloat64x2;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -83,12 +83,13 @@ class _BufferAndStart {
|
|||
}
|
||||
|
||||
// Ensure that the input List can be serialized through a native port.
|
||||
// Only Int8List and Uint8List Lists are serialized directly.
|
||||
// All other lists are first copied into a Uint8List. This has the added
|
||||
// benefit that it is faster to access from the C code as well.
|
||||
_BufferAndStart _ensureFastAndSerializableByteData(
|
||||
List<int> buffer, int start, int end) {
|
||||
if (buffer is Uint8List) {
|
||||
if ((buffer is Uint8List) &&
|
||||
(buffer.buffer.lengthInBytes == buffer.length)) {
|
||||
// Send typed data directly, unless it is a partial view, in which case we
|
||||
// would rather copy than drag in the potentially much large backing store.
|
||||
// See issue 50206.
|
||||
return new _BufferAndStart(buffer, start);
|
||||
}
|
||||
int length = end - start;
|
||||
|
|
91
tests/standalone/io/regress_50206_test.dart
Normal file
91
tests/standalone/io/regress_50206_test.dart
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2022, 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:async";
|
||||
import "dart:io";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "test_utils.dart" show withTempDir;
|
||||
|
||||
const chunkCount = 8192;
|
||||
const chunkSize = 8192;
|
||||
|
||||
Future<int> timeWrite(File file, chunks) async {
|
||||
final sink = file.openWrite();
|
||||
|
||||
final Stopwatch stopwatch = new Stopwatch()..start();
|
||||
for (var chunk in chunks) {
|
||||
sink.add(chunk);
|
||||
}
|
||||
await sink.close();
|
||||
stopwatch.stop();
|
||||
|
||||
Expect.equals(chunkCount * chunkSize, await file.length());
|
||||
|
||||
await file.delete();
|
||||
|
||||
return stopwatch.elapsedMilliseconds;
|
||||
}
|
||||
|
||||
main() async {
|
||||
await withTempDir("regress50206", (Directory tempDir) async {
|
||||
File file = new File("${tempDir.path}/file.tmp");
|
||||
|
||||
int arrayTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new Uint8List(chunkSize);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
arrayTime = await timeWrite(file, chunks);
|
||||
print("arrays: $arrayTime ms");
|
||||
}
|
||||
|
||||
int unmodifiableArrayTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new UnmodifiableUint8ListView(new Uint8List(chunkSize));
|
||||
chunks.add(chunk);
|
||||
}
|
||||
unmodifiableArrayTime = await timeWrite(file, chunks);
|
||||
print("unmodifiable arrays: $unmodifiableArrayTime ms");
|
||||
}
|
||||
|
||||
int viewTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
var backing = new Uint8List(chunkSize * chunkCount);
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk =
|
||||
new Uint8List.view(backing.buffer, i * chunkSize, chunkSize);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
viewTime = await timeWrite(file, chunks);
|
||||
print("views: $viewTime ms");
|
||||
}
|
||||
|
||||
int unmodifiableViewTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
var backing = new Uint8List(chunkSize * chunkCount);
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new UnmodifiableUint8ListView(
|
||||
new Uint8List.view(backing.buffer, i * chunkSize, chunkSize));
|
||||
chunks.add(chunk);
|
||||
}
|
||||
unmodifiableViewTime = await timeWrite(file, chunks);
|
||||
print("unmodifiable views: $unmodifiableViewTime ms");
|
||||
}
|
||||
|
||||
// Assert with factor a 1000 to avoid the test being flaky from I/O
|
||||
// variance. If we copy the whole backing store for each view chunk, things
|
||||
// will be quadratically slower, i.e. more than a factor of 1000.
|
||||
Expect.isTrue(unmodifiableArrayTime / arrayTime < 1000);
|
||||
Expect.isTrue(viewTime / arrayTime < 1000);
|
||||
Expect.isTrue(unmodifiableViewTime / arrayTime < 1000);
|
||||
});
|
||||
}
|
93
tests/standalone_2/io/regress_50206_test.dart
Normal file
93
tests/standalone_2/io/regress_50206_test.dart
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
// @dart = 2.9
|
||||
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "test_utils.dart" show withTempDir;
|
||||
|
||||
const chunkCount = 8192;
|
||||
const chunkSize = 8192;
|
||||
|
||||
Future<int> timeWrite(File file, chunks) async {
|
||||
final sink = file.openWrite();
|
||||
|
||||
final Stopwatch stopwatch = new Stopwatch()..start();
|
||||
for (var chunk in chunks) {
|
||||
sink.add(chunk);
|
||||
}
|
||||
await sink.close();
|
||||
stopwatch.stop();
|
||||
|
||||
Expect.equals(chunkCount * chunkSize, await file.length());
|
||||
|
||||
await file.delete();
|
||||
|
||||
return stopwatch.elapsedMilliseconds;
|
||||
}
|
||||
|
||||
main() async {
|
||||
await withTempDir("regress50206", (Directory tempDir) async {
|
||||
File file = new File("${tempDir.path}/file.tmp");
|
||||
|
||||
int arrayTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new Uint8List(chunkSize);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
arrayTime = await timeWrite(file, chunks);
|
||||
print("arrays: $arrayTime ms");
|
||||
}
|
||||
|
||||
int unmodifiableArrayTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new UnmodifiableUint8ListView(new Uint8List(chunkSize));
|
||||
chunks.add(chunk);
|
||||
}
|
||||
unmodifiableArrayTime = await timeWrite(file, chunks);
|
||||
print("unmodifiable arrays: $unmodifiableArrayTime ms");
|
||||
}
|
||||
|
||||
int viewTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
var backing = new Uint8List(chunkSize * chunkCount);
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk =
|
||||
new Uint8List.view(backing.buffer, i * chunkSize, chunkSize);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
viewTime = await timeWrite(file, chunks);
|
||||
print("views: $viewTime ms");
|
||||
}
|
||||
|
||||
int unmodifiableViewTime = 0;
|
||||
{
|
||||
var chunks = [];
|
||||
var backing = new Uint8List(chunkSize * chunkCount);
|
||||
for (var i = 0; i < chunkCount; i++) {
|
||||
var chunk = new UnmodifiableUint8ListView(
|
||||
new Uint8List.view(backing.buffer, i * chunkSize, chunkSize));
|
||||
chunks.add(chunk);
|
||||
}
|
||||
unmodifiableViewTime = await timeWrite(file, chunks);
|
||||
print("unmodifiable views: $unmodifiableViewTime ms");
|
||||
}
|
||||
|
||||
// Assert with factor a 1000 to avoid the test being flaky from I/O
|
||||
// variance. If we copy the whole backing store for each view chunk, things
|
||||
// will be quadratically slower, i.e. more than a factor of 1000.
|
||||
Expect.isTrue(unmodifiableArrayTime / arrayTime < 1000);
|
||||
Expect.isTrue(viewTime / arrayTime < 1000);
|
||||
Expect.isTrue(unmodifiableViewTime / arrayTime < 1000);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue