GioJSdocs
On this page

gio bench

Load-test a running server: keep-alive connections for a fixed time, then throughput, latency percentiles and the X-Gio-Cache of the last response.

npx gio bench /posts/1
bash
gio bench <url-or-path> [--connections 32] [--duration 10] [--warmup 2]
gio bench --suite /,/posts/1 [--base <url>]

Reference

OptionTypeDefaultDescription
<url-or-path>string-The target: an absolute http or https URL, or a path starting with / requested from --base (default: the local server). Anything else (localhost:3000) is a usage error. Give either this or --suite.
--connections <n>number32Concurrent keep-alive connections, each sending one request after another. A whole number above 0.
--duration <s>number10Seconds to measure (per target with --suite). Must be above 0.
--warmup <s>number2Seconds of load before measuring; warmup requests count in no statistic. 0 skips it.
--suite <paths>string-Run several paths one after another and print a table. Paths are joined to --base.
--base <url>stringlocal serverWhere paths go: an http or https URL. Without it, gio passes the local server's address, resolved like gio dev resolves it (GIO_PORT / PORT, .env files, gio.toml).
-h, --helpboolean-Print the help and exit with 0.

Behavior

  • Every connection loops for warmup plus duration, sending GET requests and reading each body to the end. Requests per second is the measured request count divided by the duration.
  • non-200 counts measured responses with another status; they still count as requests. errors counts failed requests (refused, reset). A connection gives up after three errors in a row.
  • Latency is per request, from sending to the last byte: p50, p90, p99 and max.
  • x-gio-cache is the header of the last response, so a run against a cached page says hit and an uncached one bypass: the numbers label themselves.

Examples

One target

text
$ npx gio bench /blog --duration 5
gio bench http://127.0.0.1:3000/blog
  connections   32   duration 5s   warmup 2s

  requests/s    2077.80
  requests      10389
  non-200       0
  errors        0
  latency p50   14.81 ms
  latency p90   24.27 ms
  latency p99   37.07 ms
  latency max   72.57 ms
  bytes/s       5.35 MB/s
  x-gio-cache   hit; ttl=54   (last response)

A suite

text
$ npx gio bench --suite /,/blog,/giojs-logo.svg --duration 5
gio bench suite against http://127.0.0.1:3000  (32 connections, 5s per target, 2s warmup)

target             req/s         p50         p90         p99         max  non-200  errors      bytes/s  x-gio-cache (last)
/                  19.00  1314.36 ms  1527.28 ms  2395.88 ms  2395.88 ms        0       0   73.23 kB/s              bypass
/blog            1679.20    16.73 ms    33.08 ms    60.03 ms    96.61 ms        0       0    4.33 MB/s         hit; ttl=39
/giojs-logo.svg   832.40    47.62 ms    56.73 ms    75.28 ms    95.05 ms        0       0  525.24 kB/s              static

These runs used an unoptimized (debug) build of the server in a small container, against the starter app with a /blog page exporting revalidate = 60: they show the shape of the output and the gap between a cached page (hit) and a page rendered per request (bypass), not GioJS's speed. Measure with gio start and the published binary on hardware like production, and run the load generator on another machine for numbers you publish.

A remote server

bash
npx gio bench https://staging.example.com/ --connections 64 --duration 30

Good to know

  • Flags take their value as the next argument or after =: --duration 5 and --duration=5 are the same.
  • A usage error - a bad flag or value, no target, a target that is neither a path nor an http(s) URL, both a target and --suite - exits with code 2 before any request is sent, as every gio usage error does. A single-target run with no successful request exits with 1 (no successful requests to ... - is the server running?). A suite run exits 0 even when a target fails; read its errors column.
  • Every request is a plain anonymous GET: no cookies, no request body. To load-test a form post or an authenticated page, use a dedicated tool.
  • It has no dependencies: plain node:http / node:https.

Version history

VersionChanges
v0.1.0-beta.8Paths and --suite go to the address the server listens on instead of http://localhost:3000. Usage errors exit with 2 instead of 1; flags also take --flag=value; a target that is not a path or an http(s) URL, and a fractional --connections, are usage errors.
v0.1.0-beta.6Introduced.