The visualization was six unrelated widgets - a histogram, a timeline, an error-rate bar, percentile bars, a fill gauge, plus a dashboard, heatmap and "real-time monitor" charting simulated CPU/memory/disk data. Colour was decorative and inconsistent, and the result did not read as a benchmark tool. Replace all of it with one drawing primitive: a vertical column chart with a zero-based labelled y-axis, a baseline and a labelled x-axis. Four charts share that shape - throughput over time (failures stacked in red), response time over time, response time distribution, and response time percentiles. Colour now carries meaning only: cyan is data, amber is the tail (p95+), red is failure. Charts size themselves to the terminal width. The summary keeps every number it had, laid out as aligned key/value blocks under section rules, with the ApacheBench percentile table as a 3-column grid. Fixes found along the way: - "Latency over the run" plotted the sorted durations, so it was always a monotonic ramp rather than a timeline. Requests now record a start offset relative to the run, so the time-axis charts show what actually happened. - The throughput gauge was scaled against a hardcoded 1000.0 req/s, so it read a near-zero percentage regardless of the target. - The live progress line recomputed statistics over every completed request on every completion, an O(n^2) cost inside the benchmark loop. It is now throttled to ~20 Hz and skipped entirely when stdout is not a terminal. Colour and the progress bar are gated on isatty(), so redirected output is plain, greppable text with no escape codes. A heavy tail (p50 57 ms, max 1525 ms) previously collapsed the distribution into a single column. The chart now clips its axis at p95 when the maximum dwarfs it and states so beneath the chart; well-behaved runs are never clipped and the full range stays in the footer either way. Also drop 77 lines of dead simulation code from main.c, wire graphs.c into the Makefile, untrack the built binary, and add a .gitignore. Builds warning-free at -Wall -Wextra; valgrind clean on the loaded, single-request and all-failed paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GCMSMcgcwnH9a8hhaLsg6j
114 lines
2.8 KiB
Markdown
114 lines
2.8 KiB
Markdown
<!-- retoor <retoor@molodetz.nl> -->
|
|
|
|
# abr
|
|
|
|
HTTP benchmark tool inspired by ApacheBench. Available in C and Python implementations.
|
|
|
|
## C Version
|
|
|
|
Uses non-blocking sockets with poll() multiplexing and OpenSSL for TLS.
|
|
|
|
### Requirements
|
|
|
|
- GCC
|
|
- OpenSSL development libraries (libssl-dev)
|
|
- POSIX-compliant system (Linux, BSD, macOS)
|
|
- A UTF-8 capable terminal for the charts (block and box-drawing characters)
|
|
|
|
### Build
|
|
|
|
```sh
|
|
make # build optimized binary
|
|
make debug # build with debug symbols
|
|
make valgrind # run memory leak tests
|
|
make clean # remove build artifacts
|
|
```
|
|
|
|
### Usage
|
|
|
|
```sh
|
|
./abr -n <requests> -c <concurrency> [-k] [-i] <url>
|
|
```
|
|
|
|
### Output
|
|
|
|
abr prints a key/value summary (target, result, connection times, percentiles)
|
|
followed by four column charts, all drawn in the same style: a labelled y-axis
|
|
starting at zero, a baseline, and a labelled x-axis.
|
|
|
|
- **Throughput over time** — completed requests per second per time slice;
|
|
failures stack on top of each column in red
|
|
- **Response time over time** — mean response time per time slice
|
|
- **Response time distribution** — how the response times are spread
|
|
- **Response time percentiles** — p50 through p100, tail (p95+) highlighted
|
|
|
|
Charts size themselves to the terminal width. Colour and the live progress bar
|
|
are used only when stdout is a terminal, so `./abr ... > report.txt` produces
|
|
plain, greppable text with no escape codes.
|
|
|
|
## Python Version
|
|
|
|
Uses asyncio with aiohttp for concurrent HTTP requests.
|
|
|
|
### Requirements
|
|
|
|
- Python 3.7+
|
|
- aiohttp
|
|
|
|
### Install
|
|
|
|
```sh
|
|
make py-install
|
|
```
|
|
|
|
### Usage
|
|
|
|
```sh
|
|
python3 abr.py -n <requests> -c <concurrency> [-k] [-i] <url>
|
|
make py-run # quick test run
|
|
make py-test # test with more requests
|
|
```
|
|
|
|
## Options
|
|
|
|
| Option | Description |
|
|
|--------|-------------|
|
|
| `-n` | Total number of requests |
|
|
| `-c` | Concurrent connections (max 10000) |
|
|
| `-k` | Enable HTTP Keep-Alive |
|
|
| `-i` | Skip SSL certificate verification |
|
|
|
|
## Example
|
|
|
|
```sh
|
|
./abr -n 1000 -c 50 -k https://example.com/
|
|
python3 abr.py -n 1000 -c 50 -k https://example.com/
|
|
```
|
|
|
|
## Output
|
|
|
|
- Requests per second
|
|
- Transfer rate (KB/s)
|
|
- Response time percentiles (50th, 66th, 75th, 80th, 90th, 95th, 98th, 99th)
|
|
- Connection time statistics (min, mean, median, max, standard deviation)
|
|
|
|
## Technical Details
|
|
|
|
### C Version
|
|
|
|
- Event-driven architecture using poll()
|
|
- Connection pooling with keep-alive support
|
|
- Chunked transfer-encoding support
|
|
- IPv4 and IPv6 via getaddrinfo()
|
|
- 30-second per-request timeout
|
|
- Graceful shutdown on SIGINT/SIGTERM
|
|
- OpenSSL 1.0.x and 1.1+ compatibility
|
|
- Memory leak free (verified with valgrind)
|
|
|
|
### Python Version
|
|
|
|
- Async I/O with asyncio and aiohttp
|
|
- Connection pooling with keep-alive support
|
|
- 30-second per-request timeout
|
|
- Graceful shutdown on SIGINT/SIGTERM
|