Skip to content

[devicelab] Fix memory benchmark tap synchronization and swipe flakes - #194457

Merged
auto-submit[bot] merged 2 commits into
flutter:masterfrom
bkonyi:fix-memory-benchmark-flakes
Nov 11, 2026
Merged

auto-submit[bot] merged 2 commits into
flutter:masterfrom
bkonyi:fix-memory-benchmark-flakes

Conversation

@bkonyi

@bkonyi bkonyi commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Fixes synchronization and timeout flakes in Devicelab memory benchmarks:

  • Replaces the Future.any race in MemoryTest.tapNotification() (which fired adb shell input tap 100 100 every 100ms and could leave an unawaited tap in flight after TAPPED was received, causing stray taps or duplicate Completer.complete() throws in flutter_gallery__memory_nav and complex_layout_scroll_perf__memory) with a sequential retry loop (up to 10 attempts, 1s timeout per tap).
  • Guards Completer.complete() in MemoryTest.handleLogcatLine(), ReportedDurationTest.run(), memory_nav.dart, and scroll_perf.dart against duplicate benchmark markers.
  • Updates fast_scroll_heavy_gridview__memory and fast_scroll_large_images__memory to drive scrolling deterministically in-process with LiveWidgetController(WidgetsBinding.instance).fling(...) + endOfAnimation() and ==== MEMORY BENCHMARK ==== DONE ==== via the standard MemoryTest.useMemory() flow instead of blind adb shell input swipe coordinates and fixed delays.
  • Adds bounded 60-second timeouts (MemoryTest.nextMessageTimeout and ReportedDurationTest.durationTimeout) to READY, DONE, AppLifecycleState.paused, and durationCompleter.future logcat waits so missed log lines fail fast instead of hanging the LUCI builder for 30 minutes.

Fixes #149901

Pre-launch Checklist

Replaces the unawaited `Future.any` tap loop in `MemoryTest.tapNotification()` with sequential tap-and-wait retries so in-flight `adb shell input tap` commands do not leak into the benchmark after `TAPPED` is received, and guards `Completer.complete()` against duplicate `TAPPED` logcat markers.

Updates `fast_scroll_heavy_gridview__memory` and `fast_scroll_large_images__memory` to drive scrolling deterministically in-process with `LiveWidgetController.fling` and `endOfAnimation()` instead of blind `adb shell input swipe` commands and fixed sleeps, and adds bounded 60-second timeouts to `MemoryTest` and `ReportedDurationTest` logcat waits.

Fixes flutter#149901
@bkonyi bkonyi added the CICD Run CI/CD label Oct 15, 2026
@github-actions github-actions Bot added the f: scrolling Viewports, list views, slivers, etc. label Oct 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors memory benchmark tests to perform automated flinging internally within the test apps rather than using external ADB swipe commands, and improves tap synchronization with sequential retries and timeouts. Feedback on these changes suggests simplifying the widget tree in the benchmark apps by removing redundant GestureDetector and IgnorePointer wrappers, and replacing null-aware operators (?.) with null-assertions (!) on receivedNextMessage to prevent silent test bypasses and ensure fast failures.

Comment on lines +50 to +57
runApp(
GestureDetector(
child: const IgnorePointer(
ignoring: false,
child: MacrobenchmarksApp(initialRoute: kHeavyGridViewRouteName),
),
),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since runApp completely replaces the widget tree, wrapping the app in a redundant GestureDetector (with no callbacks) and IgnorePointer(ignoring: false) is unnecessary. We can simplify this by directly calling runApp with the MacrobenchmarksApp widget.

Suggested change
runApp(
GestureDetector(
child: const IgnorePointer(
ignoring: false,
child: MacrobenchmarksApp(initialRoute: kHeavyGridViewRouteName),
),
),
);
runApp(const MacrobenchmarksApp(initialRoute: kHeavyGridViewRouteName));
References
  1. Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)

Comment on lines +49 to +56
runApp(
GestureDetector(
child: const IgnorePointer(
ignoring: false,
child: MacrobenchmarksApp(initialRoute: kLargeImagesRouteName),
),
),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since runApp completely replaces the widget tree, wrapping the app in a redundant GestureDetector (with no callbacks) and IgnorePointer(ignoring: false) is unnecessary. We can simplify this by directly calling runApp with the MacrobenchmarksApp widget.

Suggested change
runApp(
GestureDetector(
child: const IgnorePointer(
ignoring: false,
child: MacrobenchmarksApp(initialRoute: kLargeImagesRouteName),
),
),
);
runApp(const MacrobenchmarksApp(initialRoute: kLargeImagesRouteName));
References
  1. Suggest simplification and refactoring: Assess whether the code can be made simpler or refactored to enhance readability and maintainability. (link)

prepareForNextMessage('AppLifecycleState.paused');
await device!.shellExec('input', <String>['keyevent', 'KEYCODE_BACK']);
await receivedNextMessage;
await receivedNextMessage?.timeout(MemoryTest.nextMessageTimeout);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null-aware operator ?. on receivedNextMessage means that if receivedNextMessage is null (e.g., due to a developer error where prepareForNextMessage was not called), the expression will silently evaluate to null and await null will complete immediately without waiting. Using the null-assertion operator ! instead ensures that the test fails fast with a clear error if receivedNextMessage is null, preventing silent test bypasses.

Suggested change
await receivedNextMessage?.timeout(MemoryTest.nextMessageTimeout);
await receivedNextMessage!.timeout(MemoryTest.nextMessageTimeout);

fail('unable to launch activity');
}
await receivedNextMessage;
await receivedNextMessage?.timeout(MemoryTest.nextMessageTimeout);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null-aware operator ?. on receivedNextMessage means that if receivedNextMessage is null (e.g., due to a developer error where prepareForNextMessage was not called), the expression will silently evaluate to null and await null will complete immediately without waiting. Using the null-assertion operator ! instead ensures that the test fails fast with a clear error if receivedNextMessage is null, preventing silent test bypasses.

Suggested change
await receivedNextMessage?.timeout(MemoryTest.nextMessageTimeout);
await receivedNextMessage!.timeout(MemoryTest.nextMessageTimeout);

print('awaiting "ready" message...');
await receivedNextMessage;
print('awaiting "ready" message... (timeout: $nextMessageTimeout)');
await receivedNextMessage?.timeout(nextMessageTimeout);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null-aware operator ?. on receivedNextMessage means that if receivedNextMessage is null (e.g., due to a developer error where prepareForNextMessage was not called), the expression will silently evaluate to null and await null will complete immediately without waiting. Using the null-assertion operator ! instead ensures that the test fails fast with a clear error if receivedNextMessage is null, preventing silent test bypasses.

Suggested change
await receivedNextMessage?.timeout(nextMessageTimeout);
await receivedNextMessage!.timeout(nextMessageTimeout);

await device!.tap(_tapCoordinate, _tapCoordinate);
print('awaiting "tapped" message... (timeout: $_tapRetryTimeout)');
try {
await receivedNextMessage?.timeout(_tapRetryTimeout);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null-aware operator ?. on receivedNextMessage means that if receivedNextMessage is null (e.g., due to a developer error where prepareForNextMessage was not called), the expression will silently evaluate to null and await null will complete immediately without waiting. Using the null-assertion operator ! instead ensures that the test fails fast with a clear error if receivedNextMessage is null, preventing silent test bypasses.

Suggested change
await receivedNextMessage?.timeout(_tapRetryTimeout);
await receivedNextMessage!.timeout(_tapRetryTimeout);

print('awaiting "done" message...');
await receivedNextMessage;
print('awaiting "done" message... (timeout: $nextMessageTimeout)');
await receivedNextMessage?.timeout(nextMessageTimeout);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the null-aware operator ?. on receivedNextMessage means that if receivedNextMessage is null (e.g., due to a developer error where prepareForNextMessage was not called), the expression will silently evaluate to null and await null will complete immediately without waiting. Using the null-assertion operator ! instead ensures that the test fails fast with a clear error if receivedNextMessage is null, preventing silent test bypasses.

Suggested change
await receivedNextMessage?.timeout(nextMessageTimeout);
await receivedNextMessage!.timeout(nextMessageTimeout);

@Piinks Piinks added the team-infra Owned by Infrastructure team label Oct 19, 2026
@github-actions github-actions Bot removed the team-infra Owned by Infrastructure team label Nov 6, 2026
@bkonyi
bkonyi requested a review from chingjun November 6, 2026 17:45
@Piinks Piinks added team-infra Owned by Infrastructure team team: presubmit flakes Presubmit flakes found labels Nov 9, 2026
@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 11, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Nov 11, 2026
Merged via the queue into flutter:master with commit cf854df Nov 11, 2026
27 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Nov 11, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Nov 11, 2026
flutter/flutter@fffd8c2...b98afb5

2026-11-11 [email protected] Roll Dart SDK from 172cf8f121c0 to 8f15c4ca2d41 (1 revision) (flutter/flutter#196367)
2026-11-11 [email protected] Roll Skia from 657283e78115 to cc4c54f752ba (5 revisions) (flutter/flutter#196365)
2026-11-11 [email protected] Roll Skia from 2605c4a9761c to 657283e78115 (1 revision) (flutter/flutter#196358)
2026-11-11 [email protected] Roll Dart SDK from 890c6d15334c to 172cf8f121c0 (1 revision) (flutter/flutter#196352)
2026-11-11 [email protected] [flutter_tools] Migrate general.shard project, runner, and web tests off globals (flutter/flutter#196128)
2026-11-11 [email protected] [flutter_tools] Migrate test helpers and integration tests off globals (flutter/flutter#196124)
2026-11-11 [email protected] [web] Report skwasm WebGL context creation failure instead of hanging (flutter/flutter#193293)
2026-11-11 [email protected] [flutter_tools] Migrate commands.shard tests off globals (flutter/flutter#196139)
2026-11-11 [email protected] [devicelab] Fix memory benchmark tap synchronization and swipe flakes (flutter/flutter#194457)
2026-11-11 [email protected] Roll Skia from 06062e36d938 to 2605c4a9761c (2 revisions) (flutter/flutter#196350)
2026-11-11 [email protected] Do not wait again for a closed mock event stream in tear down (flutter/flutter#196110)
2026-11-11 [email protected] [gen_l10n] Add `use-explicit-plural-values` option (flutter/flutter#194816)
2026-11-11 [email protected] Roll Skia from 7bd33f8a3b70 to 06062e36d938 (2 revisions) (flutter/flutter#196340)
2026-11-11 [email protected] Skip redundant work in plugin_test_* (flutter/flutter#196258)
2026-11-10 [email protected] Drop test_timeout_secs from shards that no longer need it (flutter/flutter#196277)
2026-11-10 [email protected] Roll Dart SDK from 15c1699d3eeb to 890c6d15334c (1 revision) (flutter/flutter#196321)
2026-11-10 [email protected] iOS: Extract FlutterPlatformViewsController platform-thread state to Obj-C (flutter/flutter#196142)
2026-11-10 [email protected] Remove `Mac web_tool_tests` and take new subshard builders out of bringup (flutter/flutter#196276)
2026-11-10 [email protected] Roll Skia from 9c3d43d8a04b to 7bd33f8a3b70 (12 revisions) (flutter/flutter#196317)
2026-11-10 [email protected] Take customer_testing_devtools out of bringup (flutter/flutter#196239)
2026-11-10 [email protected] Roll ICU from a0ea93436c52 to b09986242cfb (1 revision) (flutter/flutter#196316)
2026-11-10 [email protected] [flutter_tools] Avoid unlinking native_assets.json and handle EXDEV (flutter/flutter#196134)
2026-11-10 [email protected] Remove old `Windows tool_integration_tests` builders and take the new shards out of bringup (flutter/flutter#196275)
2026-11-10 [email protected] [SwiftPM] Disable tests for when settings fail to compile (flutter/flutter#196310)
2026-11-10 [email protected] Roll Fuchsia Test Scripts from PXc5D7S_q6sIYpfFJ... to oEU515sDqSTvD8Spx... (flutter/flutter#196289)
2026-11-10 [email protected] Fix ime insets animation jump (flutter/flutter#191453)
2026-11-10 [email protected] Link to original PR in automatic cherry-pick PRs (flutter/flutter#196130)
2026-11-10 [email protected] Roll Packages from 565c657 to 08faf64 (9 revisions) (flutter/flutter#196296)
2026-11-10 [email protected] Roll Skia from b11315d0a096 to 9c3d43d8a04b (45 revisions) (flutter/flutter#196295)
2026-11-10 [email protected] Replace type-specific window widgets with a single Window widget (flutter/flutter#196002)
2026-11-10 [email protected] Roll Dart SDK from a2baae273bb2 to 15c1699d3eeb (2 revisions) (flutter/flutter#196294)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD f: scrolling Viewports, list views, slivers, etc. team: presubmit flakes Presubmit flakes found team-infra Owned by Infrastructure team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flutter_gallery__memory_nav is flaky on mokey

3 participants