Skip to content

Commit

Permalink
Reland "[vm] More efficient 'await' of not Future and completed _Future"
Browse files Browse the repository at this point in the history
This is a reland of commit 6b3d175

Fixes b/235734143
TEST=runtime/tests/vm/dart/await_in_custom_zone_test.dart

Original change's description:
> [vm] More efficient 'await' of not Future and completed _Future
>
> When awaiting a value which is not a Future or a completed
> built-in _Future, 'await' implementation can bypass heavyweight
> _Future/_FutureListener machinery and schedule micro-tasks directly.
>
> Benchmarks:
> JIT, x64:
> AsyncLiveVars.* +46-54% (bigger is better)
> Calls.AwaitAsyncCall -46% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -46%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -45%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -45%
> Calls.AwaitFutureOrCall -60%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -60%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -59%
>
> JIT, ia32:
> AsyncLiveVars.* +43-52% (bigger is better)
> Calls.AwaitAsyncCall -42% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -42%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -41%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -39%
> Calls.AwaitFutureOrCall -55%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -54%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -53%
>
> JIT, arm:
> AsyncLiveVars.* +64-71% (bigger is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -51% (less is better)
> Calls.AwaitAsyncCallClosureTargetPolymorphic -47%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -48%
> Calls.AwaitFutureOrCall -64%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -64%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -59%
>
> JIT, arm64:
> AsyncLiveVars.* +65-78% (bigger is better)
> Calls.AwaitAsyncCall -51% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -51%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -50%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -49%
> Calls.AwaitFutureOrCall -69%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -68%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -67%
>
> AOT, x64:
> AsyncLiveVars.* +55-61% (bigger is better)
> Calls.AwaitAsyncCall -47% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -46%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -47%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -46%
> Calls.AwaitFutureOrCall -59%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -59%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -58%
>
> AOT, arm:
> AsyncLiveVars.* 54-66% (bigger is better)
> Calls.AwaitAsyncCall -46-51% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -46-50%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -46-52%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -45-50%
> Calls.AwaitFutureOrCall -63-68%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -63-66%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -63-67%
>
> AOT, arm64:
> AsyncLiveVars.* +53-66% (bigger is better)
> Calls.AwaitAsyncCall -50-51% (less is better)
> Calls.AwaitAsyncCallInstanceTargetPolymorphic -50%
> Calls.AwaitAsyncCallClosureTargetPolymorphic -50-51%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphicManyAwaits -49-50%
> Calls.AwaitFutureOrCall -66-68%
> Calls.AwaitFutureOrCallInstanceTargetPolymorphic -66-68%
> Calls.AwaitFutureOrCallClosureTargetPolymorphic -63-67%
>
> TEST=ci
> Issue: #48378
>
> Change-Id: I65e3702fcd816ee3fee876ff442b9887c035b1ec
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243102
> Reviewed-by: Lasse Nielsen <lrn@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>

Change-Id: I245984ace1c768fdcba58dfdd6aa46e52126be4e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/248442
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
  • Loading branch information
alexmarkov authored and Commit Bot committed Jun 15, 2022
1 parent 07f7e45 commit 058265f
Show file tree
Hide file tree
Showing 7 changed files with 472 additions and 20 deletions.
6 changes: 1 addition & 5 deletions pkg/vm_service/test/get_stack_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final result = await service.getStack(isolateRef.id!);

expect(result.frames, hasLength(10));
expect(result.frames, hasLength(6));
expect(result.asyncCausalFrames, hasLength(26));
expect(result.awaiterFrames, hasLength(13));

Expand All @@ -105,10 +105,6 @@ final tests = <IsolateTest>[
[equals('Regular'), anything], // Internal mech. ..
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), anything],
[equals('Regular'), endsWith(' _RawReceivePortImpl._handleMessage')],
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var tests = <IsolateTest>[
var frames = stack['frames'];
var asyncFrames = stack['asyncCausalFrames'];
var awaiterFrames = stack['awaiterFrames'];
expect(frames.length, greaterThanOrEqualTo(20));
expect(frames.length, greaterThanOrEqualTo(12));
expect(asyncFrames.length, greaterThan(frames.length));
expect(awaiterFrames.length, greaterThan(frames.length));
expect(stack['truncated'], false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var tests = <IsolateTest>[
var frames = stack['frames'];
var asyncFrames = stack['asyncCausalFrames'];
var awaiterFrames = stack['awaiterFrames'];
expect(frames.length, greaterThanOrEqualTo(20));
expect(frames.length, greaterThanOrEqualTo(12));
expect(asyncFrames.length, greaterThan(frames.length));
expect(awaiterFrames.length, greaterThan(frames.length));
expect(stack['truncated'], false);
Expand Down
197 changes: 197 additions & 0 deletions runtime/tests/vm/dart/await_in_custom_zone_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// 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.

// This test verifies that 'await' implementation calls Zone callbacks from
// correct Zones.

import 'dart:async';

import 'package:expect/expect.dart';

List<String> log = [];

class TestZone {
final String name;
TestZone(this.name);

static T run<T>(String name, T Function() callback) {
final tz = TestZone(name);
final zone = Zone.current.fork(
specification: ZoneSpecification(
runUnary: tz.runUnary,
runBinary: tz.runBinary,
registerUnaryCallback: tz.registerUnaryCallback,
registerBinaryCallback: tz.registerBinaryCallback,
scheduleMicrotask: tz.scheduleMicrotask));
return zone.run(callback);
}

R runUnary<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f, T arg) {
log.add('$name.runUnary');
return parent.runUnary(zone, f, arg);
}

R runBinary<R, T1, T2>(Zone self, ZoneDelegate parent, Zone zone,
R Function(T1 arg1, T2 arg2) f, T1 arg1, T2 arg2) {
log.add('$name.runBinary');
return parent.runBinary(zone, f, arg1, arg2);
}

ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R Function(T arg) f) {
log.add('$name.registerUnaryCallback');
return parent.registerUnaryCallback(zone, (T arg) {
log.add('$name.unaryCallback');
return f(arg);
});
}

ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(Zone self,
ZoneDelegate parent, Zone zone, R Function(T1 arg1, T2 arg2) f) {
log.add('$name.registerBinaryCallback');
return parent.registerBinaryCallback(zone, (T1 arg1, T2 arg2) {
log.add('$name.binaryCallback');
return f(arg1, arg2);
});
}

void scheduleMicrotask(Zone self, ZoneDelegate parent, Zone zone, void f()) {
log.add('$name.scheduleMicrotask');
parent.scheduleMicrotask(zone, f);
}
}

Future<void> foo() async {
log.add('--- step 3');
}

Future<void> baz() async {
log.add('--- step 8');
}

Future<void> bar() async {
log.add('--- step 6');

Future f = TestZone.run('Z3', () {
log.add('--- step 7');
return baz();
});

log.add('--- step 9');
await TestZone.run('Z4', () async {
log.add('--- step 10');
await f;
log.add('--- step 13');
});
log.add('--- step 14');
}

main() async {
log.add('--- start');
await TestZone.run('Z1', () async {
log.add('--- step 1');
await null;
log.add('--- step 2');
await foo();

log.add('--- step 4');
await TestZone.run('Z2', () async {
log.add('--- step 5');
Future f = bar();

log.add('--- step 11');
await TestZone.run('Z4', () async {
log.add('--- step 12');
await f;
log.add('--- step 15');
});
log.add('--- step 16');
});
log.add('--- step 17');
});
log.add('--- end');

print('Actual log = [');
for (int i = 0; i < log.length; ++i) {
print(" /* $i */ '${log[i]}',");
}
print('];');

List<String> expectedLog = [
/* 0 */ '--- start',
/* 1 */ '--- step 1',
/* 2 */ 'Z1.registerUnaryCallback',
/* 3 */ 'Z1.registerBinaryCallback',
/* 4 */ 'Z1.scheduleMicrotask',
/* 5 */ 'Z1.runUnary',
/* 6 */ 'Z1.unaryCallback',
/* 7 */ '--- step 2',
/* 8 */ '--- step 3',
/* 9 */ 'Z1.scheduleMicrotask',
/* 10 */ 'Z1.runUnary',
/* 11 */ 'Z1.unaryCallback',
/* 12 */ '--- step 4',
/* 13 */ '--- step 5',
/* 14 */ '--- step 6',
/* 15 */ '--- step 7',
/* 16 */ '--- step 8',
/* 17 */ '--- step 9',
/* 18 */ '--- step 10',
/* 19 */ 'Z4.registerUnaryCallback',
/* 20 */ 'Z2.registerUnaryCallback',
/* 21 */ 'Z1.registerUnaryCallback',
/* 22 */ 'Z4.registerBinaryCallback',
/* 23 */ 'Z2.registerBinaryCallback',
/* 24 */ 'Z1.registerBinaryCallback',
/* 25 */ 'Z3.scheduleMicrotask',
/* 26 */ 'Z2.scheduleMicrotask',
/* 27 */ 'Z1.scheduleMicrotask',
/* 28 */ 'Z2.registerUnaryCallback',
/* 29 */ 'Z1.registerUnaryCallback',
/* 30 */ 'Z2.registerBinaryCallback',
/* 31 */ 'Z1.registerBinaryCallback',
/* 32 */ '--- step 11',
/* 33 */ '--- step 12',
/* 34 */ 'Z4.registerUnaryCallback',
/* 35 */ 'Z2.registerUnaryCallback',
/* 36 */ 'Z1.registerUnaryCallback',
/* 37 */ 'Z4.registerBinaryCallback',
/* 38 */ 'Z2.registerBinaryCallback',
/* 39 */ 'Z1.registerBinaryCallback',
/* 40 */ 'Z2.registerUnaryCallback',
/* 41 */ 'Z1.registerUnaryCallback',
/* 42 */ 'Z2.registerBinaryCallback',
/* 43 */ 'Z1.registerBinaryCallback',
/* 44 */ 'Z4.runUnary',
/* 45 */ 'Z2.runUnary',
/* 46 */ 'Z1.runUnary',
/* 47 */ 'Z1.unaryCallback',
/* 48 */ 'Z2.unaryCallback',
/* 49 */ 'Z4.unaryCallback',
/* 50 */ '--- step 13',
/* 51 */ 'Z2.runUnary',
/* 52 */ 'Z1.runUnary',
/* 53 */ 'Z1.unaryCallback',
/* 54 */ 'Z2.unaryCallback',
/* 55 */ '--- step 14',
/* 56 */ 'Z4.runUnary',
/* 57 */ 'Z2.runUnary',
/* 58 */ 'Z1.runUnary',
/* 59 */ 'Z1.unaryCallback',
/* 60 */ 'Z2.unaryCallback',
/* 61 */ 'Z4.unaryCallback',
/* 62 */ '--- step 15',
/* 63 */ 'Z2.runUnary',
/* 64 */ 'Z1.runUnary',
/* 65 */ 'Z1.unaryCallback',
/* 66 */ 'Z2.unaryCallback',
/* 67 */ '--- step 16',
/* 68 */ 'Z1.runUnary',
/* 69 */ 'Z1.unaryCallback',
/* 70 */ '--- step 17',
/* 71 */ '--- end',
];
Expect.listEquals(expectedLog, log);
}
Loading

0 comments on commit 058265f

Please sign in to comment.