Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ scripts/utm/images/

# Build artifacts
/api
.bench/
46 changes: 46 additions & 0 deletions benchmarks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
SHELL := /bin/bash

.PHONY: bench-activity-ramp

REPO_ROOT := $(abspath $(CURDIR)/..)

K6 ?= k6
K6_OUT_DIR ?= $(REPO_ROOT)/.bench/k6
HYPEMAN_BASE_URL ?= http://127.0.0.1:8080
HYPEMAN_IMAGE ?= docker.io/library/nginx:alpine
HYPEMAN_BENCH_MAX_VUS ?= 16
HYPEMAN_BENCH_VU_STEP ?= 1
HYPEMAN_BENCH_STAGE_DURATION ?= 2m
HYPEMAN_BENCH_DASHBOARD_PERIOD ?= 120s
HYPEMAN_HYPERVISOR ?= cloud-hypervisor
HYPEMAN_INGRESS_HOST_PORT ?= 80
HYPEMAN_CREATE_REJECTED_BACKOFF_SECONDS ?= 1

bench-activity-ramp:
@if ! command -v $(K6) >/dev/null 2>&1; then \
echo "k6 not found; install k6 or run with K6=/path/to/k6"; \
exit 1; \
fi
@if [ -z "$$HYPEMAN_API_KEY" ]; then \
echo "HYPEMAN_API_KEY is required"; \
exit 1; \
fi
@mkdir -p $(K6_OUT_DIR)
K6_WEB_DASHBOARD=true \
K6_WEB_DASHBOARD_PORT=-1 \
K6_WEB_DASHBOARD_PERIOD=$(HYPEMAN_BENCH_DASHBOARD_PERIOD) \
K6_WEB_DASHBOARD_EXPORT=$(K6_OUT_DIR)/activity-ramp.html \
$(K6) run \
--summary-mode=full \
--summary-trend-stats="avg,med,p(90),p(95),p(99),min,max" \
--summary-export=$(K6_OUT_DIR)/activity-ramp-summary.json \
-e HYPEMAN_BASE_URL="$(HYPEMAN_BASE_URL)" \
-e HYPEMAN_API_KEY="$$HYPEMAN_API_KEY" \
-e HYPEMAN_IMAGE="$(HYPEMAN_IMAGE)" \
-e HYPEMAN_HYPERVISOR="$(HYPEMAN_HYPERVISOR)" \
-e HYPEMAN_BENCH_MAX_VUS="$(HYPEMAN_BENCH_MAX_VUS)" \
-e HYPEMAN_BENCH_VU_STEP="$(HYPEMAN_BENCH_VU_STEP)" \
-e HYPEMAN_BENCH_STAGE_DURATION="$(HYPEMAN_BENCH_STAGE_DURATION)" \
-e HYPEMAN_INGRESS_HOST_PORT="$(HYPEMAN_INGRESS_HOST_PORT)" \
-e HYPEMAN_CREATE_REJECTED_BACKOFF_SECONDS="$(HYPEMAN_CREATE_REJECTED_BACKOFF_SECONDS)" \
k6/activity-ramp.ts
44 changes: 44 additions & 0 deletions benchmarks/k6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# k6 benchmarks

This directory contains TypeScript k6 benchmarks for a running Hypeman API.

## Activity ramp

`activity-ramp.ts` runs a closed workload where each virtual user repeatedly:

1. creates an instance from a ready image,
2. waits for it to reach `Running`,
3. sends an HTTP probe through a shared pattern ingress,
4. deletes the instance.

The default ramp increases concurrency by one virtual user every two minutes up to 16 virtual users. Tune the run with environment variables:

```sh
export HYPEMAN_API_KEY=...
make -C benchmarks bench-activity-ramp \
HYPEMAN_BASE_URL=http://127.0.0.1:8080 \
HYPEMAN_IMAGE=docker.io/library/nginx:alpine \
HYPEMAN_HYPERVISOR=cloud-hypervisor \
HYPEMAN_BENCH_MAX_VUS=16
```

The Make target writes:

- `.bench/k6/activity-ramp.html`
- `.bench/k6/activity-ramp-summary.json`

The Make target uses 120-second dashboard buckets by default so each HTML report point lines up with one default ramp window. Override that with `HYPEMAN_BENCH_DASHBOARD_PERIOD`.

The benchmark creates a shared ingress named `bench-activity-ramp` if one does not already exist. By default it listens on host port `80`, matches `{instance}.hypeman-bench.local`, and targets port `80` on each instance. Override the probe path with:

```sh
HYPEMAN_PROBE_URL=http://host/
HYPEMAN_PROBE_HOST_SUFFIX=.hypeman-bench.local
HYPEMAN_INGRESS_HOST_PORT=80
HYPEMAN_INGRESS_TARGET_PORT=80
```

Capacity rejections from `POST /instances` are recorded as `hypeman_create_rejected` and `hypeman_create_rejections`. They are not treated as unexpected script errors because they identify the concurrency level where the server starts refusing new activity.
Rejected creates back off for one second by default so a saturated server does not produce a tight 409 loop. Override that with `HYPEMAN_CREATE_REJECTED_BACKOFF_SECONDS`.

Set `HYPEMAN_HYPERVISOR` to `cloud-hypervisor`, `firecracker`, or `qemu` to run the same activity loop against a specific hypervisor. The value is sent on instance creation and added as a metric tag.
Loading
Loading