Add benchmarker app - #16
Merged
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a complete Flutter benchmarking application for the
http_cache_streampackage. 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.dart) that manages benchmark runs, coordinates worker isolates, and aggregates resultsworker_pool.dart,worker_protocol.dart,benchmark_worker.dart) for parallel HTTP request execution with configurable client buildersbenchmark_config.dart) supporting three run types: pre-cached, non-cached, and directbenchmark_stats.dart,benchmark_report.dart)benchmark_page.dart)benchmark_form.dart) with source URL probingThe app benchmarks the package by path dependency, ensuring it always tests the working copy of the repository.