Skip to content

chore(samples): add message-list benchmark page - #2779

Merged
xsahil03x merged 2 commits into
masterfrom
chore/sample-app-benchmark-page
Jun 22, 2026
Merged

xsahil03x merged 2 commits into
masterfrom
chore/sample-app-benchmark-page

Conversation

@xsahil03x

@xsahil03x xsahil03x commented Jun 22, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds an internal profiling screen to sample_app for measuring StreamMessageListView under load. Lives at sample_app/benchmark/ (sibling to lib/, not packaged with the regular app) with its own entrypoint so it stays out of normal sample-app navigation.

Run with:

cd sample_app
flutter run --profile -t benchmark/main_benchmark.dart

The page injects synthetic message.new events through client.handleEvent (same path the WebSocket pipeline uses) at a configurable rate. Chips control:

  • LIMIT — in-memory message cap (via StreamMessageListViewConfiguration.maximumMessageLimit)
  • FLOOD — number of events to inject per recording
  • SPEED — injection rate (msg/s)

Dashboard updates are routed through a ValueNotifier so HUD repaints don't bubble up into StreamMessageListView's rebuild path — keeps the measured frame timings clean.

This was originally drafted on the v10 branch and recovered from a dangling commit; APIs were ported to current master (StreamMessageItemBuilder 3-arg signature, StreamMessageListViewConfiguration, StreamMessageComposer).

Test plan

  • flutter run --profile -t benchmark/main_benchmark.dart from sample_app/ launches the benchmark page
  • Tapping "Start flood" injects synthetic messages at the chosen rate
  • LIMIT chip caps in-memory messages; FLOOD chip stops auto after N events; SPEED chip controls injection rate
  • Toggling lightweight items swaps in the minimal builder (1-line text rows)
  • HUD (avg frame ms, RSS, message count) updates at ~2 Hz without re-rendering the list

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a new Flutter benchmark page to stress-test message list rendering with configurable “flood” event injection and automatic stop at a target message count.
    • Live performance reporting now includes frame-time metrics (average/worst/p95), jank percentage, and render timing breakdown, plus an on-screen HUD for run controls (limits, speed, lite items, pruning, reset).
    • Introduced a dedicated benchmark app entrypoint that initializes a minimal chat UI and launches the benchmark page for a watched channel.

A scratch screen in sample_app for profiling StreamMessageListView under
synthetic message floods. Has its own entrypoint so it stays out of the
main sample app's UI; run with:

  flutter run --profile -t benchmark/main_benchmark.dart

The page injects synthetic `message.new` events through `client.handleEvent`
at a configurable rate, with chips for LIMIT (in-memory cap), FLOOD
(events per recording), and SPEED (msg/s) so a single recording is
comparable across builds. Dashboard updates are routed through a separate
ValueNotifier so HUD repaints don't taint the list's frame timings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef89069f-a86e-43ce-8084-e6ff557434f1

📥 Commits

Reviewing files that changed from the base of the PR and between 6f305d0 and c57f4d7.

📒 Files selected for processing (1)
  • sample_app/benchmark/benchmark_page.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • sample_app/benchmark/benchmark_page.dart

📝 Walkthrough

Walkthrough

Two new files add a standalone Flutter benchmark tool for StreamMessageListView. main_benchmark.dart provides the app entrypoint with hardcoded credentials, channel setup, and a FutureBuilder launcher. benchmark_page.dart implements the full stress-test page: a frame-timing engine that collects render metrics via SchedulerBinding, publishes live snapshots to a ValueNotifier, injects synthetic message floods via handleEvent, and renders a floating HUD overlay with live performance metrics and configurable controls.

Changes

StreamMessageListView Benchmark Tool

Layer / File(s) Summary
Benchmark entrypoint and app shell
sample_app/benchmark/main_benchmark.dart
main() initializes Flutter bindings, creates a StreamChatClient, connects the user, and runs _BenchmarkApp. _BenchmarkApp wraps the tree in StreamChat and MaterialApp; _BenchmarkLauncherState calls channel.watch(limit: 25) and uses a FutureBuilder to route between error, loading, and BenchmarkPage states.
Frame metrics data model
sample_app/benchmark/benchmark_page.dart (lines 1083–1179)
Defines _FrameSample (per-frame timing: build, raster, vsync-hit) and _DashboardSnapshot (derived metrics: avg/worst/p95 frame time, jank%, refresh-hit%, RSS, message counts). _formatCompact helper converts large integers to K/M/G display format.
Page layout and frame-timing engine
sample_app/benchmark/benchmark_page.dart (lines 1–545)
_BenchmarkPageState registers SchedulerBinding timings callbacks, collects frame samples with warmup-frame gating, prunes a rolling time-windowed queue, samples process RSS (non-web), and publishes computed snapshots at 2 Hz via ValueNotifier. Flood lifecycle starts/stops a periodic timer injecting synthetic message.new events; auto-stops at the FLOOD target. StreamMessageListView renders with optional lightweight Text row builder.
HUD overlay container, pill, and body
sample_app/benchmark/benchmark_page.dart (lines 546–1081)
_BenchHud positions an animated expand/collapse floating container with RepaintBoundary isolation. _BenchHudPill renders FPS/msg/mem metrics and flood controls via ValueListenableBuilder. _BenchHudBody applies a dark ColorScheme remap. Supporting pieces include _HudMetric, _StatusDot, _achievedFps, _DebugBanner, and _FloodButton.
Dashboard panels and metric widgets
sample_app/benchmark/benchmark_page.dart (lines 1180–1495)
_DashboardPanel renders Messages, Performance, and Memory cards with color-threshold helpers for frame-time, jank, refresh-hit, RSS, and message growth. _MetricCard and _MetricLine provide reusable layout with primary/secondary lines and optional value color.
Controls, formatting helpers, and synthetic corpus
sample_app/benchmark/benchmark_page.dart (lines 1497–1857)
_ControlsPanel and _ChipRow expose LIMIT/FLOOD/SPEED chips, action buttons, and Lite items toggle. Formatting helpers convert ints to thousands-separated display, bytes to MB/GB, and signed RSS delta. _floodAuthors and _floodCorpus provide a pre-cacheable user list and mixed message text strings for synthetic event generation.

Sequence Diagram(s)

sequenceDiagram
  participant main
  participant StreamChatClient
  participant _BenchmarkLauncherState
  participant _BenchmarkPageState
  participant SchedulerBinding
  participant ValueNotifier

  main->>StreamChatClient: connectUser(credentials)
  main->>_BenchmarkLauncherState: runApp
  _BenchmarkLauncherState->>StreamChatClient: channel.watch(limit: 25)
  StreamChatClient-->>_BenchmarkLauncherState: Channel
  _BenchmarkLauncherState->>_BenchmarkPageState: BenchmarkPage(channel)

  rect rgba(70, 130, 180, 0.5)
    Note over _BenchmarkPageState,SchedulerBinding: Flood active
    _BenchmarkPageState->>StreamChatClient: handleEvent(message.new) [periodic]
    SchedulerBinding->>_BenchmarkPageState: timingsCallback(frames)
    _BenchmarkPageState->>_BenchmarkPageState: collect _FrameSample, prune window
    _BenchmarkPageState->>ValueNotifier: publish _DashboardSnapshot at 2Hz
    ValueNotifier-->>_BenchHudPill: rebuild FPS/msg/mem metrics
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hippity-hop, the frames fly by,
A flood of messages fills the sky!
The HUD gleams bright with jank and FPS,
Synthetic authors put lists to the test.
P95 ticks, the corpus is set—
The fastest rabbit benchmark yet! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a benchmark page for measuring message list performance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/sample-app-benchmark-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@xsahil03x xsahil03x changed the title chore(sample): add message-list benchmark page chore(samples): add message-list benchmark page Jun 22, 2026
@xsahil03x
xsahil03x enabled auto-merge (squash) June 22, 2026 18:32

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
sample_app/benchmark/main_benchmark.dart (1)

13-16: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider externalizing credentials.

Static analysis flagged these as hardcoded secrets. While these appear to be shared demo credentials for the sample app, externalizing them via environment variables or a gitignored config file would:

  • Keep credentials out of version control history
  • Allow different credentials per environment
  • Follow security best practices

For a benchmark-only tool this may be acceptable, but worth noting for future reference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sample_app/benchmark/main_benchmark.dart` around lines 13 - 16, The constants
_apiKey, _userId, and _userToken are hardcoded directly in the source file,
which exposes credentials in version control. Move these credential values to
environment variables or a gitignored configuration file instead. Update the
const declarations to read from environment variables using a method like
String.fromEnvironment() or by loading them from a gitignored config file at
runtime, ensuring the credentials are no longer embedded in the code.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sample_app/benchmark/benchmark_page.dart`:
- Around line 621-632: The Align widget in the build method has a key:
UniqueKey() parameter that creates a new key on every build call, forcing
Flutter to discard and recreate the element unnecessarily and introducing
measurement noise in the benchmarking tool. Remove the key parameter entirely
from the Align widget since the _BenchHud widget is stateless and does not
require a unique key for element reuse.
- Around line 192-199: The code has inconsistent null handling for
`widget.channel.state`: line 192 uses safe navigation with `state?.messages`,
but line 194 uses force unwrap with `state!.messagesStream`. Since
`channel.watch()` is awaited before this page is shown, `state` should be
guaranteed non-null, so update line 192 to use force unwrap
`widget.channel.state!.messages` instead of the safe navigation operator to make
the null handling explicit and consistent throughout the listen callback block.

In `@sample_app/benchmark/main_benchmark.dart`:
- Line 7: Replace the relative import statement for benchmark_page.dart with a
package import. Change the import from relative path syntax (import
'benchmark_page.dart') to package syntax (import 'package:sample_app/...') to
comply with the always_use_package_imports coding guideline.

---

Nitpick comments:
In `@sample_app/benchmark/main_benchmark.dart`:
- Around line 13-16: The constants _apiKey, _userId, and _userToken are
hardcoded directly in the source file, which exposes credentials in version
control. Move these credential values to environment variables or a gitignored
configuration file instead. Update the const declarations to read from
environment variables using a method like String.fromEnvironment() or by loading
them from a gitignored config file at runtime, ensuring the credentials are no
longer embedded in the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ad28b2fc-b439-4a8d-a4a0-f7633180567f

📥 Commits

Reviewing files that changed from the base of the PR and between 9605679 and 6f305d0.

📒 Files selected for processing (2)
  • sample_app/benchmark/benchmark_page.dart
  • sample_app/benchmark/main_benchmark.dart

Comment thread sample_app/benchmark/benchmark_page.dart Outdated
Comment thread sample_app/benchmark/benchmark_page.dart
Comment thread sample_app/benchmark/main_benchmark.dart
@xsahil03x
xsahil03x disabled auto-merge June 22, 2026 18:34
@codecov

codecov Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.59%. Comparing base (9605679) to head (c57f4d7).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2779   +/-   ##
=======================================
  Coverage   69.59%   69.59%           
=======================================
  Files         426      426           
  Lines       25675    25675           
=======================================
  Hits        17868    17868           
  Misses       7807     7807           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Consistent non-null `channel.state` handling: capture once into a
  local and read `messages` / `messagesStream` off it. The page is
  only shown after `channel.watch()` resolves, so the bang is the
  honest expression of that invariant.
- Drop `UniqueKey()` on the HUD's `Align` — it forced a discard +
  rebuild on every parent rebuild, which is exactly the kind of
  measurement noise this page is supposed to avoid. The HUD's outer
  `RepaintBoundary` already gives it its own compositor layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xsahil03x
xsahil03x enabled auto-merge (squash) June 22, 2026 18:42
@xsahil03x
xsahil03x merged commit 6b9e9a9 into master Jun 22, 2026
24 checks passed
@xsahil03x
xsahil03x deleted the chore/sample-app-benchmark-page branch June 22, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants