Skip to content

Commit 7e4e07e

Browse files
committed
docs(readme): current cross-implementation performance table
Replace the stale Performance table (no Node; Lua decode listed at the old ~4 MB/s) with measured throughput for all four CLIs (encode+decode of 10 MB random data via test/benchmark_test), and document this pass's measured decode optimizations (C 1.9x via direct LUTs, Lua 1.8-3.6x via UTF-8 length lookup) plus the leak-suite regression guard.
1 parent 2d284c9 commit 7e4e07e

1 file changed

Lines changed: 15 additions & 13 deletions

File tree

README.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,26 @@ This implementation allows you to view binary data directly in a terminal (it ev
4242

4343
## Performance
4444

45-
The Zig implementation is heavily optimized for throughput via source-level data structure improvements and optional PGO (Profile-Guided Optimization):
45+
All implementations share the same byte↔glyph map and pass the same test suite; they differ only in language/runtime. Indicative throughput — encode + decode of 10 MB of random `/dev/urandom` data via `test/benchmark_test`, release builds on Apple Silicon:
4646

47-
| Implementation | Encode (10 MB) | Decode (10 MB) | Encode Throughput | Decode Throughput |
48-
|---|---|---|---|---|
49-
| **Zig** | 51 ms | 62 ms | 121 MB/s | 108 MB/s |
50-
| **PGO (C FFI + Zig)** | 50 ms | 63 ms | 125 MB/s | 109 MB/s |
51-
| **C (standalone)** ||| comparable to Zig | comparable to Zig |
52-
| **Lua (LuaJIT)** | 233 ms | 2,510 ms | 86 MB/s | 3.9 MB/s |
47+
| Implementation | Encode | Decode |
48+
|---|---|---|
49+
| **Zig** (ReleaseFast) | ~107 MB/s | ~275 MB/s |
50+
| **C** (standalone, `-O3`) | ~61 MB/s | ~141 MB/s |
51+
| **Lua** (LuaJIT) | ~41 MB/s | ~18 MB/s |
52+
| **Node.js** | ~12 MB/s | ~15 MB/s |
53+
54+
The WebAssembly build is compiled from the same C core. Reproduce on your machine with `IMPLEMENTATION_TO_TEST=<binary> ./test/benchmark_test` (defaults to the Zig build and announces the implementation under test).
5355

5456
Key optimizations in the Zig core:
55-
- **Pre-allocated buffers**: Encode/decode output sized upfront (no growth checks in the hot loop)
56-
- **Flat character map**: Comptime-built contiguous byte buffer (~1.5 KB) replacing 256 scattered fat pointers — fits in L1 cache
57-
- **O(1) decode lookup**: Direct tables for 1-byte, 2-byte, and 3-byte UTF-8 sequences replacing O(log 256) binary search
58-
- **No inner decode loop**: Single UTF-8 length check + direct lookup per character
57+
- **Pre-allocated buffers**: encode/decode output sized upfront (no growth checks in the hot loop).
58+
- **Flat character map**: a comptime-built contiguous byte buffer (~1.5 KB) replacing 256 scattered fat pointers — fits in L1 cache.
59+
- **O(1) decode lookup**: direct tables for 1-, 2-, and 3-byte UTF-8 sequences instead of an O(log 256) binary search.
60+
- **No inner decode loop**: a single UTF-8 length check + direct lookup per character.
5961

60-
These source-level changes yielded a **16% encode speedup** and **61% decode speedup (2.6x)** over the initial ReleaseFast build. The PGO path (`make pgo-ffi`) provides an additional ~1-3% via profile-guided branch layout, using the C FFI CLI to dogfood the Zig library through its public C ABI.
62+
The C and Lua decoders were brought in line with this approach in a measured optimization pass: C now uses direct 1-/2-byte lookup tables (**1.9×** decode), and Lua resolves each glyph by its UTF-8 leading-byte length instead of brute-forcing all four lengths (**1.8–3.6×** decode, up from ~8 MB/s). Every optimization is benchmarked before and after, and a continuous memory-leak suite (`test/leak_test`) guards the FFI and C paths against regressions.
6163

62-
Benchmarks were run on Apple M4 with `hyperfine --warmup 5 --min-runs 20` against random binary data from `/dev/urandom`.
64+
The optional PGO path (`make pgo-ffi`) adds a further ~1–3% via profile-guided branch layout, dogfooding the Zig library through its public C ABI.
6365

6466
## Usage
6567

0 commit comments

Comments
 (0)