diff --git a/CLAUDE.md b/CLAUDE.md index 01885c7..bc67585 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,7 +39,7 @@ cargo test --features test-panic --release `ffi.load("qjson")` uses `dlopen`, which respects `LD_LIBRARY_PATH` — **not** LuaJIT's `package.cpath`. The Makefile sets `LD_LIBRARY_PATH=target/release` for `test`/`bench`; if you invoke `busted` or `luajit` directly, set it yourself. -`make lint` runs clippy only (with `-D warnings`); `cargo fmt --check` is intentionally **not** part of the lint gate because the codebase uses manual column alignment in struct definitions and compact single-line literals that default rustfmt would reflow. See the README "Roadmap / Deferred" entry on fmt for context. +`make lint` runs clippy only (with `-D warnings`); `cargo fmt --check` is intentionally **not** part of the lint gate because the codebase uses manual column alignment in struct definitions and compact single-line literals that default rustfmt would reflow. ## Architecture @@ -97,4 +97,4 @@ If you add a scanner code path, run gate 2 locally; the cross-check test (`tests ## Conventions -- Deferred / "we'll do this later" decisions go in `README.md` under **Roadmap / Deferred**, one bullet per item, so each can be picked up individually. Don't park them in code comments or scratch files. +- Deferred / "we'll do this later" decisions should be tracked as GitHub Issues so each can be picked up individually. Don't park them in code comments or scratch files. diff --git a/README.md b/README.md index 0c410c8..702cdd3 100644 --- a/README.md +++ b/README.md @@ -114,21 +114,21 @@ AMD EPYC Rome, Zen 2, 4 vCPUs; 5 rounds, deterministic payload). ### Encode (unmodified) + modify-then-re-encode -| Size | encode (unmodified) | modify top (cjson / qjson) | modify nested (cjson / qjson) | speedup vs. cjson | -|---:|---:|---:|---:|---:| -| 2 KB | 219,925 | 59,761 / 56,909 | 61,685 / 49,798 | 1.0× / 0.8× | -| 60 KB | 143,843 | 4,590 / **44,370** | 4,616 / **196,386** | 9.7× / 42.5× | -| 100 KB | 119,617 | 2,645 / **32,712** | 5,263 / **59,809** | 12.4× / 11.4× | -| 1 MB | 16,269 | 241 / **3,108** | 516 / **14,134** | 12.9× / 27.4× | +Numbers from the same run as [`docs/benchmarks.md`](docs/benchmarks.md). + +| Size | encode (unmodified) | modify top + encode | modify nested + encode | +|---:|---:|---:|---:| +| 2 KB | 260,322 | 58,242 | 43,003 | +| 60 KB | 141,563 | 37,498 | 134,590 | +| 100 KB | 105,374 | 28,114 | 71,942 | +| 1 MB | 16,269 | 3,125 | 13,649 | > **qjson.encode(unmodified)** re-emits the original byte range via `memcpy` — > no fields touched means zero serializer work. > **qjson modify+encode** materializes only the mutated subtree; unmodified -> siblings stay on the fast path. cjson always does a full materialize + -> re-serialize on every encode. At 60 KB+, qjson modify+encode is **10–43×** -> faster than the cjson equivalent. -> See [`docs/benchmarks.md`](docs/benchmarks.md) for the full size ladder, -> memory numbers, and environment. +> siblings stay on the fast path. See [`docs/benchmarks.md`](docs/benchmarks.md) +> for the full size ladder, cjson comparisons, speedup ratios, memory +> numbers, and environment. ```sh make bench # qjson vs cjson and lua-resty-simdjson