Skip to content
Draft
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
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Added

- Add a FYRE OpenShift comparison profile that provisions 40 GB nodes and runs
the built-in and external dataplane lanes concurrently on separate target,
Locust, and Fast Time workers. Package the pinned `oc` runtime, collect
gateway-side memory, and produce a self-contained Markdown report alongside
the existing CSV, JSON, and Slack-ready PNG artifacts.
- Add a quota-sized 2 vCPU / 2 GiB OpenShift profile that runs all eight
built-in/external and 125/250/500/1,000-user measurements concurrently with
exact pod limits on three dedicated-role workers. Reserve 1.75 vCPU / 1.75
GiB per 2 vCPU / 2 GiB target so all eight targets schedule with host
headroom, set 40 GB master and worker root disks, disable FYRE's automatic
worker data disks, and preserve structured FYRE API validation errors.

### Changed

- Generalize `load fyre run|status|destroy` ownership and cleanup to support
run-owned OpenShift clusters as well as standalone Terraform VMs.
- Resume an interrupted OpenShift campaign when `load fyre run` is invoked
again with the same run ID and saved configuration.

## [0.5.0] - 2026-09-16

### Added
Expand Down
100 changes: 100 additions & 0 deletions benchmarks/fyre/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ disk and expose no create-time root-disk setting. The default three-VM run
therefore needs 750 GB of FYRE disk quota. The CLI checks CPU, memory, disk, and
public-IP quota before it creates any benchmark VM.

The OpenShift profile requires `FYRE_PRODUCT_GROUP_ID`, Docker on the
orchestration host, and access to the FYRE OpenShift API and cluster DNS. The
CLI runs a digest-pinned OpenShift client container, so a host `oc` installation
is not required.

## Run the complete comparison

The bare command is the CI entrypoint for the complete eight-run comparison:
Expand Down Expand Up @@ -137,3 +142,98 @@ cf-integration load fyre run \

Comparison reports derive the target allocation from the selected profile; both
lanes always run sequentially on that same VM.

## Parallel OpenShift profile with 40 GB disks

`openshift.yaml` runs the same eight comparison measurements on a FYRE
OpenShift cluster while reducing every master and worker root disk to 40 GB
and explicitly disabling FYRE's default worker data disks.
The built-in and external lanes run concurrently and remain isolated on six
dedicated workers:

| Lane role | Workers | Pod allocation on each worker |
| --- | ---: | ---: |
| Built-in and external Locust | 2 | 4 vCPU / 16 GiB each |
| Built-in and external target | 2 | 4 vCPU / 4 GiB each |
| Built-in and external Fast Time | 2 | 8 vCPU / 32 GiB each |

Each Locust pod contains one master and three workers. Each target allocation
includes its supporting PostgreSQL/Redis or Redis/JWKS containers. Each lane
has a separate zero-delay Fast Time service. No measured target, load generator,
or backend shares a worker node with the other lane.

Run the complete parallel comparison with:

```bash
cf-integration load fyre run \
--file benchmarks/fyre/openshift.yaml \
--run-id openshift-builtin-external
```

The short form is:

```bash
cf-integration l f r -f benchmarks/fyre/openshift.yaml -i openshift-builtin-external
```

The command creates the cluster through the FYRE OpenShift API, authenticates
with the generated kubeadmin credential, assigns the six workers by their
configured CPU and memory, runs both lanes in parallel at 125, 250, 500, and
1,000 users, downloads every phase before deleting its pods, writes the final
report, deletes the benchmark namespace, and deletes only the run-owned
cluster. A failed or interrupted campaign retains its local run state and
retries cluster cleanup three times. Run the same command with the same run ID
to resume an interrupted OpenShift campaign from its saved manifest.

OpenShift artifacts use the same
`$CF_INTEGRATION_DIR/fyre/<run-id>/results/` layout and add `report.md`, a
self-contained report with the result table, memory averages and peaks,
request mix, pinned images, and Mermaid architecture. The cluster record and
manifest recursively omit passwords, tokens, pull secrets, API keys, and
kubeconfig data.

The built-in lane remains pinned to the MCP SDK v2 fixture image until that SDK
change is available in the main gateway image. The profile must not be changed
back to the main image before that merge because both lanes use the same modern
`2026-07-28` client.

### Fully parallel 2 vCPU / 2 GiB comparison

`openshift-2v2-parallel.yaml` runs all eight measurements at the same time:
built-in and external dataplane lanes at 125, 250, 500, and 1,000 users. Each
measurement gets its own target, Locust, and Fast Time pods with identical
requests and limits. Pods share only with pods serving the same role.

| Dedicated worker role | Worker size | Pods | Reserved per measurement |
| --- | ---: | ---: | ---: |
| Target | 16 vCPU / 16 GiB | 8 | 2 vCPU / 2 GiB limits; 1.75 vCPU / 1.75 GiB requests |
| Locust | 14 vCPU / 12 GiB | 8 | 1.5 vCPU / 1.25 GiB |
| Fast Time | 14 vCPU / 12 GiB | 8 | 1.5 vCPU / 1.375 GiB |

Each target reservation includes its supporting PostgreSQL and Redis
containers for the built-in dataplane, or Redis and loopback JWKS containers
for the external dataplane. Each Locust pod has one master and three workers.
The helper pressure gate rejects the campaign if the shared helper workers or
individual helper pods become the bottleneck.

Run the full comparison with one command:

```bash
cf-integration load fyre run \
--file benchmarks/fyre/openshift-2v2-parallel.yaml \
--run-id openshift-2v2-parallel
```

The short form is:

```bash
cf-integration l f r -f benchmarks/fyre/openshift-2v2-parallel.yaml -i openshift-2v2-parallel
```

The three OpenShift masters and all three workers use 40 GB root disks, the
FYRE API VM uses its fixed 500 GB root disk, and workers have no additional
data disks. The cluster therefore requests 740 GB of disk in total. The
orchestration command may run on a persistent VM or CI worker; the benchmark
continues if the developer laptop sleeps. Artifacts are downloaded to
`$CF_INTEGRATION_DIR/fyre/<run-id>/results/` before the run-owned cluster is
deleted.
54 changes: 54 additions & 0 deletions benchmarks/fyre/openshift-2v2-parallel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
schema_version: 1
benchmark_kind: comparison
infrastructure:
kind: openshift
os: Red Hat CoreOS
expiry_hours: 24
openshift:
version: "4.21.27"
base_disk_gb: 40
oc_image: quay.io/openshift/origin-cli@sha256:f3fc63fc3d2fd1c3a2c3311bf517b776f6596244e697dad32d62ca9fd6482fe5
master: { cpu: 4, memory_gb: 16 }
api: { cpu: 4, memory_gb: 8 }
target_pod: { cpu_millicores: 1750, memory_mib: 1792 }
load_pod: { cpu_millicores: 1500, memory_mib: 1280 }
backend_pod: { cpu_millicores: 1500, memory_mib: 1408 }
worker_pools:
- { role: target, cpu: 16, memory_gb: 16, count: 1 }
- { role: locust, cpu: 14, memory_gb: 12, count: 1 }
- { role: fast-time, cpu: 14, memory_gb: 12, count: 1 }
images:
dataplane: ghcr.io/contextforge-org/contextforge-data-plane@sha256:0b3026b21659ce6c494142aee2c5866b44122232e73fcf21102da1f210692a96
controlplane: ghcr.io/contextforge-org/cf-integration-fixture@sha256:5b206e6f863cea9f8cabea6451392428fbe67b16bdf10fefd1f7ac8032d95b52
fast_time: ghcr.io/ibm/cfex-mcp-fast-time-server@sha256:110e1826f5d763e5afadba770b731dac93e0819c1bbadb68671b0124260603cf
helpers: ghcr.io/contextforge-org/cf-integration-helpers@sha256:f7e557e263737328225d827e73b519d0b40facb2698c55ee3d2de0ed82f00fa3
locust: mirror.gcr.io/locustio/locust@sha256:fd39232c31971fe7509582717a95592f0fbf9a917b705f355bd7471e03bdd649
postgres: postgres@sha256:4ef4dbc939d61acea57712655ddb4b4ab27419c913f94cca0cd57cb3ea3c2280
redis: mirror.gcr.io/library/redis@sha256:a7859ed111db3c1f5404a973a4747505d559fb5ca32d37e447afc0ef845a2103
workload:
protocol_version: 2026-07-28
user_levels: [125, 250, 500, 1000]
first_users: 125
maximum_users: 1000
ramp_seconds: 30
warmup_seconds: 30
measure_seconds: 3600
repetitions: 1
maximum_campaign_seconds: 7200
plateau_improvement_percent: 5.0
boundary_percent: 12.5
config_cache_seconds: 60
helper_cpu_percent: 70.0
helper_memory_percent: 80.0
worker_core_percent: 85.0
parallel_lanes: true
parallel_user_levels: true
tools:
- convert_time
- echo
- get_stats
- get_system_time
- schema_success
- verify-protocol
scenarios:
- { id: comparison, label: Built-in dataplane vs external dataplane, replicas: 1, cpu: 2, memory_gb: 2, multiplier: 1 }
57 changes: 57 additions & 0 deletions benchmarks/fyre/openshift.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
schema_version: 1
benchmark_kind: comparison
infrastructure:
kind: openshift
os: Red Hat CoreOS
expiry_hours: 12
openshift:
version: "4.21.27"
base_disk_gb: 40
oc_image: quay.io/openshift/origin-cli@sha256:f3fc63fc3d2fd1c3a2c3311bf517b776f6596244e697dad32d62ca9fd6482fe5
master: { cpu: 4, memory_gb: 16 }
api: { cpu: 4, memory_gb: 8 }
target_pod: { cpu_millicores: 3500, memory_mib: 3584 }
load_pod: { cpu_millicores: 4000, memory_mib: 16384 }
backend_pod: { cpu_millicores: 8000, memory_mib: 32768 }
worker_pools:
- { role: target-builtin, cpu: 6, memory_gb: 12, count: 1 }
- { role: target-external, cpu: 6, memory_gb: 12, count: 1 }
- { role: locust-builtin, cpu: 6, memory_gb: 20, count: 1 }
- { role: locust-external, cpu: 6, memory_gb: 20, count: 1 }
- { role: fast-time-builtin, cpu: 10, memory_gb: 40, count: 1 }
- { role: fast-time-external, cpu: 10, memory_gb: 40, count: 1 }
images:
dataplane: ghcr.io/contextforge-org/contextforge-data-plane@sha256:0b3026b21659ce6c494142aee2c5866b44122232e73fcf21102da1f210692a96
controlplane: ghcr.io/contextforge-org/cf-integration-fixture@sha256:5b206e6f863cea9f8cabea6451392428fbe67b16bdf10fefd1f7ac8032d95b52
fast_time: ghcr.io/ibm/cfex-mcp-fast-time-server@sha256:110e1826f5d763e5afadba770b731dac93e0819c1bbadb68671b0124260603cf
helpers: ghcr.io/contextforge-org/cf-integration-helpers@sha256:f7e557e263737328225d827e73b519d0b40facb2698c55ee3d2de0ed82f00fa3
locust: mirror.gcr.io/locustio/locust@sha256:fd39232c31971fe7509582717a95592f0fbf9a917b705f355bd7471e03bdd649
postgres: postgres@sha256:4ef4dbc939d61acea57712655ddb4b4ab27419c913f94cca0cd57cb3ea3c2280
redis: mirror.gcr.io/library/redis@sha256:a7859ed111db3c1f5404a973a4747505d559fb5ca32d37e447afc0ef845a2103
workload:
protocol_version: 2026-07-28
user_levels: [125, 250, 500, 1000]
first_users: 125
maximum_users: 1000
ramp_seconds: 30
warmup_seconds: 30
measure_seconds: 3600
repetitions: 1
maximum_campaign_seconds: 18000
plateau_improvement_percent: 5.0
boundary_percent: 12.5
config_cache_seconds: 60
helper_cpu_percent: 70.0
helper_memory_percent: 80.0
worker_core_percent: 85.0
parallel_lanes: true
parallel_user_levels: false
tools:
- convert_time
- echo
- get_stats
- get_system_time
- schema_success
- verify-protocol
scenarios:
- { id: comparison, label: Built-in dataplane vs external dataplane, replicas: 1, cpu: 4, memory_gb: 4, multiplier: 1 }
Loading
Loading