benchmark

GitHub

对 Dragonfly 及 Redis/Valkey 进行基准测试,收集吞吐量、延迟和内存指标,生成包含图表和数据附录的性能报告。适用于性能评估与对比场景。

.claude/skills/benchmark/SKILL.md dragonflydb/dragonfly

Trigger Scenarios

用户运行 /benchmark 命令 请求负载测试或测量 QPS/延迟 比较不同数据库性能 描述性能测试目标

Install

npx skills add dragonflydb/dragonfly --skill benchmark -g -y
More Options

Non-standard path

npx skills add https://github.com/dragonflydb/dragonfly/tree/main/.claude/skills/benchmark -g -y

Use without installing

npx skills use dragonflydb/dragonfly@benchmark

指定 Agent (Claude Code)

npx skills add dragonflydb/dragonfly --skill benchmark -a claude-code -g -y

安装 repo 全部 skill

npx skills add dragonflydb/dragonfly --all -g -y

预览 repo 内 skill

npx skills add dragonflydb/dragonfly --list

SKILL.md

Frontmatter
{
    "name": "benchmark",
    "description": "Benchmark Dragonfly (and compare against Valkey\/Redis) on local or remote cloud instances, then produce a performance + memory report with charts and a raw-data appendix. Use this whenever the user runs \/benchmark, or asks to benchmark \/ load-test \/ measure throughput, QPS, latency, or memory efficiency of Dragonfly or another Redis-compatible server, to compare Dragonfly vs Valkey or Redis, or to generate a benchmark report. Trigger it even when the user just describes the goal (\"see how fast Dragonfly is on this box\", \"compare memory per key vs Valkey\") without saying the word \"benchmark\".\n",
    "allowed-tools": "Bash, Read, Write, Edit, AskUserQuestion",
    "argument-hint": "(optional) free-form spec, e.g. \"server=10.0.0.1 client=10.0.0.2 strings vs-valkey\""
}

Benchmark Dragonfly

Drive a benchmark of Dragonfly (optionally side-by-side with Valkey or Redis) on local or remote instances, collect throughput / latency / memory numbers, and assemble a report that mirrors the team's published format: a narrative TLDR, per-instance metric tables, charts, and an appendix with the exact commands and raw output so anyone can reproduce it.

The whole point of the report is trust: a reader should be able to see the headline numbers, understand the conditions they were measured under, and re-run the exact commands themselves. Everything below serves that goal.

When you start

If the user passed a free-form spec in $ARGUMENTS, parse what you can from it (IPs, use-cases, comparison targets) and only ask about what's missing. The work splits into clear phases — walk through them in order, but stay flexible: the user may already have servers running, or may only want the report half (handed raw output to format). Read what they're actually asking for.

Phases: (1) gather spec → (2) prepare instances → (3) network tuning → (4) start monitoring → (5) run workloads → (6) extract metrics, charts, report.

The two reference files carry the operational detail — read them before acting, not from memory:

  • references/running-benchmarks.md — how to prep instances, start servers, drive dfly_bench and memtier_benchmark, run Valkey/Redis for comparison, apply network tuning, and measure memory. Read this before Phase 2.
  • references/report-template.md — the exact report structure, with an example. Read this before Phase 5.

Bundled scripts/ (reuse these instead of re-improvising the same loops — they encode the safety discipline learned the hard way):

  • bench_server.sh start|stop|status <ssh> <binary> [maxmem] [port] — launch a server tracking its PID; stop kills by PID and verifies the process is gone + port free (tmux kill-session does not reap it).
  • monitor_fill.sh <server_ssh> <client_ssh> [session] [abort_pct] — the live RSS guard: polls used_memory_rss, prints a line per sample, aborts the write if RSS crosses the threshold (default 92%). Its output is also the input to plot_fill.py.
  • capture_result.sh <server_ssh> <client_ssh> <log> <outdir> [label] — saves the run summary + INFO memory + OS-level free snapshot (host_memory.txt) and exits non-zero if there were any eviction errors (enforces the zero-error rule). The OS snapshot matters: used_memory_rss and host free can diverge significantly — e.g. with MIMALLOC_ALLOW_LARGE_OS_PAGES=1 (default), mimalloc holds large-page arenas that the OS counts as used but INFO doesn't fully reflect, making the machine appear near-OOM while RSS looks fine.
  • collect_metrics.py / make_charts.py — metrics + charts from dfly_bench JSON (GET/SET workloads).
  • plot_fill.py — memory-fill chart from monitor_fill.sh output, for --command workloads (e.g. SETEX) that produce no JSON time series.

Every benchmark output directory must include a commands_audit.log artifact with the exact command lines used for setup, server launch, writes, reads, captures, diagnostics, and chart/report generation. Raw data without the commands that produced it is not reproducible.

Run-control scripts are mandatory for benchmark phases. For Phase 5 runs, use the bundled scripts as the default API:

  • start/stop/status servers with scripts/bench_server.sh;
  • monitor long write fills with scripts/monitor_fill.sh;
  • capture write results and enforce the zero-error rule with scripts/capture_result.sh;
  • generate metrics/charts with scripts/collect_metrics.py, scripts/make_charts.py, and scripts/plot_fill.py.

Inline SSH is fine for inspection, package setup, one-off diagnostics, and bounded foreground probes, but not as a replacement for the run-control scripts in the main benchmark path. If a script is not usable for a run, document the reason in commands_audit.log and in the report appendix before using a manual equivalent.

Phase 1 — Gather the benchmark spec (interactive)

Use AskUserQuestion to pin down anything not already given. You need:

  1. Where it runs. Local, or remote instances? For remote, get the server host/IP and the client host/IP (the load generator should run on a separate machine from the server — co-locating them steals CPU and corrupts the numbers). Get the SSH user / key if not obvious. On cloud instances, always use the private/internal IP (VPC-internal) for both SSH and as the load generator's -h target — the public IP routes through the internet gateway, adding latency and egress cost, and the result measures the gateway rather than the server.
  2. Use-cases. Default menu: simple strings (SETEX writes + GET reads), pipelined / peak-throughput, memory efficiency. Always also ask whether there is a specific focus (a particular command, data type, key distribution, value size, or scenario) — the canned use-cases are a starting point, not a cage.
  3. Comparison targets. Dragonfly only, or also Valkey / Redis? Which versions?
  4. Instance specs (for the report's conditions section): instance type, CPU count, OS/kernel. Read these directly from the box at the start of Phase 2 rather than asking the user.
  5. Load parameters if the user has opinions: value size (-d), key space (--key_maximum), connections (-c), pipeline depth, test duration. Pick sensible defaults (see the reference) and tell the user what you chose. Sizing the key count is the consequential decision — see the reference's "Sizing the load" section. The dataset must fill a large fraction of instance RAM (benchmarking a near-empty instance is wrong) but stay clear of OOM (~60–75% of RAM, headroom to spare). --key_maximum bounds the footprint, so compute it from instance RAM ÷ estimated bytes-per-entry, calibrating with a short pilot write if unsure.

Summarize the resolved spec back to the user in a short block before running anything, so a wrong assumption gets caught before machines spin.

Phase 2 — Prepare the instances

  • Record instance specs (nproc, uname -r, cloud metadata) — these go in the report's conditions section. Use the private IP when connecting between instances (see Phase 1).
  • A remote instance usually already has ~/projects/dragonfly. If not, clone it there. Build a release binary (build-opt/dragonfly, build-opt/dfly_bench) unless the user wants a published release downloaded instead — follow their instruction on build-vs-download.
  • For comparison targets, pull the Valkey/Redis docker image on the server box.
  • Verify everything launches and is reachable from the client box (a quick redis-cli -h <server-private-ip> ping) before committing to a long run.

Run each step individually over SSH — do not chain launch, polling, capture, and the next phase into one command. If a tool call is interrupted, remote work keeps running but goes uncaptured. Start the server; start the write; monitor it; capture; start reads — one bounded step at a time.

Phase 3 — Network tuning (optional, remote only)

High-throughput numbers on cloud hardware depend heavily on IRQ/SMP affinity tuning. If the user wants maximal numbers, apply the tuning described in the reference and record exactly what you did — it belongs in the appendix and materially affects the results. If skipped, say so in the report; untuned and tuned numbers are not comparable.

Phase 4 — Start the monitoring stack (server machine)

Start the local Prometheus + Grafana stack on the server machine so you get continuous, fine-grained time-series (server CPU, memory, command rates, host metrics) spanning the whole benchmark — richer than the load generator's own output and the source of the most convincing report charts.

ssh <server> 'cd ~/projects/dragonfly/tools/local/monitoring && docker compose up -d'
# when benchmarking Valkey/Redis, also bring up the redis exporter:
ssh <server> 'cd ~/projects/dragonfly/tools/local/monitoring && docker compose --profile redis up -d'

Prometheus scrapes at 1s. Always run servers on port 6380 (Dragonfly, Valkey, and Redis alike). The bundled prometheus.yml ships pointing at 6379, so before bringing the stack up, fix the scrape targets:

sed -i 's/:6379/:6380/g' tools/local/monitoring/prometheus/prometheus.yml

(This is a workaround for a misconfigured default — if you have repo write access, commit the corrected file once so future runs start clean.)

Restart Prometheus if it was already running, then verify targets are UP at http://<server>:9090/targets before starting the load — a silently-down scrape job means no data for that window.

Start monitoring before the workloads and leave it running across all runs, so a single continuous window covers everything. See the reference's monitoring section for what to read from Grafana (dashboards are pre-provisioned) and how to pull panels into the report. Record the benchmark start/end timestamps — they let you crop the Grafana window to exactly the run.

Phase 5 — Run the workloads

For each (use-case × datastore) combination, see the reference for the precise commands. The shape is always: write → memory snapshot → read. Use the private IP as the load generator's -h target.

Pass --json_out_file to dfly_bench (and --json-out-file to memtier) when the workload supports it — charts and headline numbers come from these files. dfly_bench --command workloads (e.g. SETEX __key__ 10000 __data__) do not produce JSON; save full stdout and chart the monitor_fill.sh output instead.

Drive the run with the bundled scripts: bench_server.sh start, write in a client tmux session, monitor_fill.sh alongside (live RSS guard), then capture_result.sh to save results. capture_result.sh enforces the zero-error rule — any eviction/OOM error response makes the run invalid; discard it, cut --key_maximum ~10–15%, and re-run. See the preamble and the reference's "Sizing the load" section for the full rule.

Prefill writes must use --pipeline 30. Without pipelining, the client stalls waiting for each reply and becomes the bottleneck before the server is saturated — especially at high key counts. Use --pipeline 30 for all write (fill) phases. Drop to --pipeline 1 (or omit it) only for latency-honest read benchmarks where you want honest per-request numbers.

Initialize commands_audit.log at the start and append each command as it runs (see the preamble for the requirement).

Phase 6 — Extract metrics, build charts, assemble the report

  1. Headline metrics + memory. Run the bundled extractor over the JSON files to pull QPS / P99 and compute bytes-per-entry (both used_memory- and used_memory_rss-based, per the user's choice to report both):

    python3 .claude/skills/benchmark/scripts/collect_metrics.py \
        --bench-json <run.json> [--bench-json <run2.json> ...] \
        --info <info_memory.txt> --dbsize <N> \
        --label "Dragonfly m7g.2xlarge"
    

    It prints a metrics block (and JSON) you can drop straight into the tables.

  2. Charts. Generate QPS-over-time PNGs from the time series (this is what visually shows Dragonfly's smooth throughput vs a competitor's degradation):

    python3 .claude/skills/benchmark/scripts/make_charts.py \
        --series "Dragonfly=df_write.json" --series "Valkey=valkey_write.json" \
        --metric qps --title "Write throughput, m7g.2xlarge" \
        --out charts/write_m7g2xl.png
    

    Embed the PNGs in the report with relative paths. For --command workloads (e.g. SETEX) there is no dfly_bench JSON — use plot_fill.py instead to chart memory-fill over time from the monitor_fill.sh output:

    python3 .claude/skills/benchmark/scripts/plot_fill.py \
        --series "prebuilt=prebuilt/poll.txt" --series "release=release/poll.txt" \
        --interval 10 --ram-gib 30 --out charts/memory_fill.png
    
  3. Report. Follow references/report-template.md exactly. Write a TLDR with the 3–5 genuinely important takeaways (scaling behavior, memory efficiency, any hardware surprise), then per-instance tables, then the appendix. The TLDR is interpretation, not a restatement of the tables — say what the numbers mean. Only claim what the data supports.

Save the report where the user asks (default: benchmark-<YYYY>-<MM>.md in the repo root) and tell them the path plus a one-line summary of the headline result.

Cleanup

If you started servers, the monitoring stack, or comparison containers on remote instances, offer to stop them (docker compose down in the monitoring dir). If you applied network tuning that changes machine state, tell the user what would need reverting. Don't tear anything down without asking — they may want to inspect or re-run.

Version History

  • d8d8fe3 Current 2026-08-20 19:06

Same Skill Collection

.claude/skills/reproduce-fuzz-crash/SKILL.md
.claude/skills/benchmark-report/SKILL.md

Metadata

Files
0
Version
d8d8fe3
Hash
5404c7e7
Indexed
2026-08-20 19:06

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-21 10:49
浙ICP备14020137号-1 $방문자$