Skip to content

Add benchmarker app - #16

Merged
Colton127 merged 5 commits into
mainfrom
claude/benchmarker-flutter-app-vhpgce
Aug 3, 2026
Merged

Add benchmarker app#16
Colton127 merged 5 commits into
mainfrom
claude/benchmarker-flutter-app-vhpgce

Conversation

@Colton127

@Colton127 Colton127 commented Aug 3, 2026

Copy link
Copy Markdown
Owner

This PR adds a complete Flutter benchmarking application for the http_cache_stream package. The benchmarker is a cross-platform app (Android, iOS, macOS, Windows, Linux) that measures HTTP response performance served by the package's local cache server.

Key Changes

  • Benchmark Controller: Core orchestration logic (benchmark_controller.dart) that manages benchmark runs, coordinates worker isolates, and aggregates results
  • Worker Pool & Protocol: Isolate-based worker pool (worker_pool.dart, worker_protocol.dart, benchmark_worker.dart) for parallel HTTP request execution with configurable client builders
  • Configuration & Statistics:
    • Benchmark configuration system (benchmark_config.dart) supporting three run types: pre-cached, non-cached, and direct
    • Statistics accumulation and reporting (benchmark_stats.dart, benchmark_report.dart)
  • UI Components:
    • Main benchmark page with responsive layout (benchmark_page.dart)
    • Configuration panel for inputs (URL, concurrency, request count, run type)
    • Statistics panel displaying aggregated results with JSON/text export
    • Cache progress tracking and logging panels
    • Form state management (benchmark_form.dart) with source URL probing
  • Testing: Comprehensive test suite covering controller, config, worker pool, form, and UI components
  • Platform Support: Full build configurations for Android, iOS, macOS, Windows, and Linux with appropriate native code and build files

The app benchmarks the package by path dependency, ensuring it always tests the working copy of the repository.

claude added 5 commits August 2, 2026 20:27
Adds benchmarker/, a cross-platform (Android, iOS, Linux, macOS, Windows)
Flutter app that benchmarks HTTP responses from the http_cache_stream cache
server. It imports the package by path so it always measures the working copy.

Workers run on a pool of long-lived isolates. Each isolate builds one
http.Client from an HttpClientBuilder sent at spawn time and reuses it for
every request, so other client implementations can be benchmarked by adding an
entry to kHttpClientOptions. The pool is respawned only when the concurrency or
client implementation changes.

Inputs are the source URL, the concurrency (isolates) and the total request
count, divided evenly between workers. Three run types are supported:
pre-cached (fully download first), non-cached (wipe the cache first) and direct
(bypass http_cache_stream and hit the source URL).

Workers stream per-request measurements back to the main isolate, which
aggregates them and refreshes the UI four times a second: avg/p50/p90/p99/min/
max for time to headers, time to first byte and completion time, plus requests
per second, bytes per second, byte totals and an outcome breakdown. Every
response's byte count is verified against its Content-Length. Cache-server runs
also show live download progress and errors from cacheStateStream, alongside a
read-only log field for status and errors.

Includes unit tests for request distribution and statistics, an isolate-pool
test against a local origin server, and end-to-end tests of all three run types
through a real HttpCacheManager.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JvD7reUpdgiJeHaJz2XSE
The config inputs lived in ConfigPanel's State, which the lazily-built lists
dispose once the panel leaves the viewport's cache extent. Scrolling to the
bottom of the page and back destroyed the TextEditingControllers and the
selected run type and client, resetting them to their defaults. Switching
between the narrow and wide layouts had the same effect.

Move that state into a BenchmarkForm owned by the page, and make ConfigPanel a
stateless view over it. Adds a widget test that asserts the panel is really
disposed while scrolled away and that every input survives the round trip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JvD7reUpdgiJeHaJz2XSE
Requests can now ask for a byte range instead of the whole body. A range
slider selects the portion of the source to request; because a range has to be
expressed in bytes, a "Fetch length" probe resolves the source's size first
(HEAD, falling back to a one-byte range request, which also reports whether the
server honors Range at all). The probed length is dropped when the URL changes
so a stale size cannot be applied to another source.

The selected range travels to the workers on the job command and is sent as a
Range header; the received byte count is verified against Content-Length just
as it is for a full response. A selection covering the whole source sends no
header, keeping full-body runs identical to before, and an empty selection is
rejected before the run starts. If a range request is answered with anything
other than 206, the run logs a warning once.

Tests cover the range math, the form's probe and selection states, the panel
wiring, a worker issuing a real range request, and end-to-end partial runs both
direct and through the cache server.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JvD7reUpdgiJeHaJz2XSE
Replaces the implicit full-vs-partial distinction with an explicit "Request
range" segmented control offering three modes: full response (no Range header),
fixed range (every request asks for the slider selection), and sequential
windows (the selection is divided between the requests).

In sequential mode the window is sized from the total request count —
ceil(range / requests) — so the run walks the selected region exactly once, one
request per window, each starting where the last ended. The final window slides
back to end on the last byte, keeping every request the same size when the
division is uneven. Windows are resolved from each request's global sequence
number, so the assignment holds across workers as well as within one.

Both modes are carried to the workers as a RangePlan on the job command; the
worker resolves its window per request, so no per-request range list crosses the
port. Partial modes stay disabled until the source length has been probed, and
the panel previews exactly what will be requested — window count, window size
and the byte span — updating as the request count is edited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JvD7reUpdgiJeHaJz2XSE
Puts a copy button at the top right of the statistics panel offering the run as
plain text or as JSON. Both formats carry the run's identity alongside the
numbers — source URL, target URL, cache type, request range, http client and
concurrency — so a copied result is self-describing.

The range description is now built in one place and shared between the reports
and the run log, so the two can no longer drift.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011JvD7reUpdgiJeHaJz2XSE
@Colton127 Colton127 changed the title Add benchmarker Flutter app for http_cache_stream Add benchmarker app Aug 3, 2026
@Colton127
Colton127 merged commit 2aced6a into main Aug 3, 2026
2 checks passed
@Colton127
Colton127 deleted the claude/benchmarker-flutter-app-vhpgce branch August 3, 2026 00:22
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