v0.25.0 4492065

README.md RawHistoryFolder

Load tests

loadtest replays a traffic scenario against an ermite server. It reports throughput and latency per request while holding open the live updates streams (/-/events) that real visitors keep.

Quick start

scripts/loadtest/serve.sh                 # seeded server on :7418, pinned to 1 core
go run ./scripts/loadtest -scenario home  # closed-loop, 32 clients, 10 s
scripts/loadtest/serve.sh stop

serve.sh builds ermite from the current checkout and seeds five repositories (busy, bursty, steady, private, empty). It pins the server to the last CPUS cores (default 1) with GOMAXPROCS and taskset. A fast workstation would otherwise measure itself, not a small host. Keep the load generator off those cores: taskset -c 0-15 go run ./scripts/loadtest ….

Modes

Mode Flags Answers
Closed-loop -c 32 Maximum throughput: clients send back to back.
Open-loop -rate 1000 -c 64 Latency at a target load. Latency counts from when the request was due, so a slow server cannot hide its queue. Requests that find no free client are reported as missed.

Other flags: -d duration, -warmup, -streams (multiplier of the scenario stream counts, 0 for none), -token (signed-in pages), -var name=value, -json out.json (to compare runs), -url.

The run fails (exit 1) on any request error, refused or dropped stream, or missed request.

Against a loopback server, each stream dials from its own 127.1.x.y address. The server caps watches per client address (usecase.MaxWatchersPerClient) and in total (usecase.MaxWatchers).

Scenarios

Built-in scenarios live in scenarios/*.json. A file path also works: -scenario ./my.json.

{
  "name": "repo",
  "requests": [
    { "name": "summary", "path": "/{{repo}}", "weight": 4 },
    { "name": "commits", "path": "/{{repo}}/commits", "weight": 1 }
  ],
  "streams": [
    { "name": "events", "path": "/-/events?topic=repo:{{repo}}", "count": 50 }
  ]
}
  • weight is the share of the requests.
  • status is the expected status code (default 200).
  • {{name}} is replaced by -var name=value.
  • Every request is fetched once before the run; a wrong status stops it early.

Reading the figures

The figures depend on the host. Compare runs made on the same machine with the same CPUS, and note the CPU in the report. The report header shows the load generator; the server is whatever serve.sh pinned.

source
1# Load tests
2
3`loadtest` replays a traffic scenario against an ermite server. It reports throughput and latency per request while holding open the live updates streams (`/-/events`) that real visitors keep.
4
5## Quick start
6
7```sh
8scripts/loadtest/serve.sh                 # seeded server on :7418, pinned to 1 core
9go run ./scripts/loadtest -scenario home  # closed-loop, 32 clients, 10 s
10scripts/loadtest/serve.sh stop
11```
12
13`serve.sh` builds ermite from the current checkout and seeds five repositories (busy, bursty, steady, private, empty). It pins the server to the last `CPUS` cores (default 1) with `GOMAXPROCS` and `taskset`. A fast workstation would otherwise measure itself, not a small host. Keep the load generator off those cores: `taskset -c 0-15 go run ./scripts/loadtest …`.
14
15## Modes
16
17| Mode | Flags | Answers |
18|---|---|---|
19| Closed-loop | `-c 32` | Maximum throughput: clients send back to back. |
20| Open-loop | `-rate 1000 -c 64` | Latency at a target load. Latency counts from when the request was due, so a slow server cannot hide its queue. Requests that find no free client are reported as **missed**. |
21
22Other flags: `-d` duration, `-warmup`, `-streams` (multiplier of the scenario stream counts, `0` for none), `-token` (signed-in pages), `-var name=value`, `-json out.json` (to compare runs), `-url`.
23
24The run fails (exit 1) on any request error, refused or dropped stream, or missed request.
25
26Against a loopback server, each stream dials from its own `127.1.x.y` address. The server caps watches per client address (`usecase.MaxWatchersPerClient`) and in total (`usecase.MaxWatchers`).
27
28## Scenarios
29
30Built-in scenarios live in `scenarios/*.json`. A file path also works: `-scenario ./my.json`.
31
32```json
33{
34  "name": "repo",
35  "requests": [
36    { "name": "summary", "path": "/{{repo}}", "weight": 4 },
37    { "name": "commits", "path": "/{{repo}}/commits", "weight": 1 }
38  ],
39  "streams": [
40    { "name": "events", "path": "/-/events?topic=repo:{{repo}}", "count": 50 }
41  ]
42}
43```
44
45- `weight` is the share of the requests.
46- `status` is the expected status code (default 200).
47- `{{name}}` is replaced by `-var name=value`.
48- Every request is fetched once before the run; a wrong status stops it early.
49
50## Reading the figures
51
52The figures depend on the host. Compare runs made on the same machine with the same `CPUS`, and note the CPU in the report. The report header shows the load generator; the server is whatever `serve.sh` pinned.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 43

↑↓ moveenter openesc close