retoorandClaude Opus 5 6c830181c8
Build and Test / build-c (push) Successful in 45s
Build and Test / build-python (push) Successful in 39s
Build and Test / valgrind (push) Successful in 42s
feat: rebuild the terminal output around a single column-chart renderer
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
2026-09-08 06:43:57 +00:00

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

make          # build optimized binary
make debug    # build with debug symbols
make valgrind # run memory leak tests
make clean    # remove build artifacts

Usage

./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

make py-install

Usage

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

./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
S
Description
Clone of Apache Benchmark (ab) that supports variable content length as response from the test URL. This repository contains a python version based on aiohttp and a C version with only OpenSSL / lcrypto as depenceny. Both support keep alive, insecure mode (expired SSL), concurrency level and amount of request configurable trough parameters. It's just a modern variant of Apache Benchmark.
Readme
74 KiB
Languages
C 82.6%
Python 16.1%
Makefile 1.3%