# BestPerf v0.1

> 现网实测 · 复刻 — capture the real network, replay it in the lab.

BestPerf is a cross-platform network-quality probe. Two probes actively measure
the network between them over UDP, BestPerf builds a neutral **network profile**
from the samples, and exports a **WAN-emulator replay scenario** so you can reproduce
the field network's behaviour in the lab.

- **Two probes, either side initiates** — RTT, directional loss, jitter, reorder,
  duplicate, micro-outage, burst-loss, RTT-spike.
- **No SSH, no root, no pcap, no tc/netem.** Pure UDP + a small local web console.
- **Record → profile → replay file**, plus an optional **pressure/bandwidth test**
  (ramp to find capacity + characterize under load, with a Gilbert-Elliott burst model).

See `field_to_lab_replay_v0_1_spec.md` for the data contracts and
`docs/plans/` for the design notes.

## Build

```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build        # unit + integration tests
```

Binaries land in `build/`: `fr-agent`, `fr-profile-build`, `fr-scenario-export`, `fr-load`, `fr-tcp`.

## The console (recommended)

Each probe runs a small local web console. Start it:

- macOS: double-click `BestPerf.command`
- Linux: `BestPerf.sh`
- Windows: `BestPerf.bat` (or use `Install BestPerf.*` to create desktop entries)

The launcher checks Python/CMake/compiler, builds the binaries if needed, starts the
controller on `http://127.0.0.1:8768/`, and opens the browser. Set `--port` or
`FIELDREPLAY_PORT` for a fixed port.

In the console:

1. **探针 (Probes)** — register the probes. The one tagged `本机` is the machine running
   this console. For a real two-machine test, give the peer its `IP:UDP-port` and its
   console URL `http://IP:8768`.
2. **发起测试 (Start a test)** — pick the peer and direction, set duration, press the
   glowing **开始**. No second machine? Press **本机回环自测** (loopback self-test).
   Toggle **压力/带宽测试** to run the ramp/capacity test instead.
3. **结果 (Results)** — RTT / loss / jitter per direction (or capacity + load-vs-quality
   curve + Gilbert-Elliott burst model for a load test), with a one-click **回放文件**
   (replay scenario) download.

On Windows, to let **other machines measure toward this PC** (so it can act as the
peer/responder), double-click the desktop entry **`2 开放网络权限 BestPerf`** (or
`BestPerf Fix UDP.bat` in the install folder) and click **是 / Yes** on the Windows
prompt. It self-elevates (one UAC click — no need to know about firewalls) and opens the
inbound ports as ranges: UDP 39700-39899, TCP 39800-39899, and TCP 8768 (the console).
Initiating a test *from* Windows needs none of this.

## Command line (advanced)

Light measurement, end to end:

```bash
# on probe B (the responder)
./build/fr-agent responder --listen 0.0.0.0:39700 --agent-id 2 --agent-name agent_b \
  --out ./logs/agent_b_raw.ndjson

# on probe A (the initiator)
./build/fr-agent initiator --config ./examples/session_config.example.json

# merge both raw logs into a profile
./build/fr-profile-build --agent-a-log ./logs/agent_a_raw.ndjson \
  --agent-b-log ./logs/agent_b_raw.ndjson --out ./out/network_profile.json \
  --window-ms 1000 --session-config ./examples/session_config.example.json

# export the WAN-emulator replay scenario (capability-driven)
./build/fr-scenario-export --profile ./out/network_profile.json \
  --capabilities ./examples/emulator_capabilities.example.json \
  --out ./out/wan_emulator_scenario.json
```

Pressure / bandwidth test (`fr-load`):

```bash
# self-contained loopback ramp -> writes load_report.v1 JSON
./build/fr-load loopback --out ./out/load_report.json --max-mbps 50 --duration 30

# cross-machine, simultaneous bidirectional (the console default):
./build/fr-load bidir-peer --out ./out/lr_b.json --forward-out ./out/fwd_b.json   # on the peer
./build/fr-load bidir --peer PEER_IP:39700 --out ./out/lr_a.json \
  --forward-out ./out/fwd_a.json --max-mbps 100 --duration 30                     # here

# correct each direction's loss to forward truth using the receiver's record:
./build/fr-load recompute --report ./out/lr_a.json --forward-record ./out/fwd_b.json
# turn the report(s) into a replay scenario:
./build/fr-load scenario --report ./out/lr_a.json --report-peer ./out/lr_b.json \
  --out ./out/wan_emulator_scenario.json
```

Felt throughput (`fr-tcp`, RFC 6349) — what an app actually gets, since TCP backs off:

```bash
./build/fr-tcp server --listen 0.0.0.0:39800                      # on the peer
./build/fr-tcp client --peer PEER_IP:39800 --out ./out/tcp_throughput.json \
  --duration 10                                                   # here
```

Measures upload and download goodput separately (so the directions never contend for the
bottleneck) plus application-level RTT, into `tcp_throughput.v1` JSON. The UDP `fr-load` path
gives the physical capacity; `fr-tcp` gives the application-felt rate next to it. The console's
"TCP 体感吞吐" toggle runs it against a peer that has a controller URL.

`fr-load` ramps the offered rate, finds the saturation knee (latency-leading, then
delivered-plateau = capacity, then loss), characterizes at the working point, and fits a
two-state Gilbert burst-loss model. Each working-point packet is tagged so the receiving
side keeps an authoritative record; `recompute` corrects loss from the round-trip proxy
(forward + reverse) to **forward truth** (the direction actually measured). Loss is reported
with a 95% upper bound (rule-of-three when zero) and a sample-size reliability flag, so a
"0% loss" reading is never mistaken for certainty. The console runs all of this for you and
offers the replay scenario as a one-click **回放文件** download.

## How it works

```
Agent A  <──UDP probes──>  Agent B          (both probe both directions)
        raw_samples ndjson on each side
                    │
            fr-profile-build  ──>  network_profile.v1.json   (neutral profile)
                    │
            fr-scenario-export ──> wan_emulator_scenario.v1.json  (replay file)

Load path (load==measurement, one fully-sequenced stream is itself the measurement):

  fr-load bidir <──UDP load──> fr-load bidir-peer    (both directions loaded at once)
        load_report.v1 (capacity, knee, working point, Gilbert burst, confidence)
                    │  recompute with the peer's receive record -> forward-truth loss
            fr-load scenario  ──>  wan_emulator_scenario.v1.json  (replay file)
```

- The **agent** (C++ core in `src/`) sends echo probes (RTT), one-way sequenced stream
  probes (directional loss/reorder/duplicate/jitter), and burst probes. Monotonic clocks
  only; one-way delay is not claimed (exported as `rtt_half_estimate`, confidence medium).
- The **profile builder** computes per-window metrics + events; `scheduler_lag` separates
  local scheduling jitter from network jitter.
- The **exporter** maps the profile onto whatever the target emulator supports (declared in
  an `emulator_capabilities.v1.json`), downgrading gracefully and recording warnings.
- The **console controller** (`scripts/bestperf_controller.py`) serves the GUI and runs
  measurements locally; for a two-probe test it coordinates the peer over HTTP (no SSH).

JSON schemas are in `schemas/`, examples in `examples/`.

## Status

Implemented and tested: the core engine and the four CLIs, the console, the light
two-probe measurement (loopback + cross-machine, no SSH), and the pressure/bandwidth
test — ramp/knee, working-point characterization, Gilbert burst model, simultaneous
bidirectional measurement, forward-truth loss correction, confidence reporting, and the
load → replay-scenario export. Validated end-to-end between a Mac and an x86_64 Linux peer
through both controllers. Mobile FFI bridges under `mobile/` are placeholders per the spec.
