~bigbes/tarantool

tarantool-protobuf

ref: e53089ddb616b902d20c7c43a73e04ded3ac0555 tarantool-protobuf/bench/jit_trace.lua -rw-r--r-- 10.5 KiB
6fb4b04c — Eugene Blikh 3 months ago
bench: lazy decode/encode scenarios + jit-trace coverage

Adds bench/lazy_bench.lua comparing eager decode/encode against
decode_lazy:encode across three workloads (passthrough, sparse-read,
mutate-then-reencode) at 1KB/10KB/100KB on emails-heavy Person.
Output is stderr-only (varies with CPU load; not committed to
baseline.json).

Findings (LuaJIT 2.1.0-beta3, both modes):
  - Passthrough re-encode: lazy 1.0–1.5× faster. Untouched views skip
    field-walk entirely and return their original bytes verbatim.
  - Sparse :get x2: lazy 0.60–0.77× of eager. Per-segment Lua tables
    allocated during the index pass cancel the decode-skip savings on
    this flat shape (no large subtrees to skip_field over).
  - Mutate-then-reencode: lazy 0.81–1.07× of eager — roughly
    break-even. Both paths traverse the full byte range; lazy
    splices, eager re-emits per field.

Lazy is a byte-passthrough optimization, not a universal speedup. Use
it when you decode, touch few fields, and re-encode — the proxy /
router shape.

Also extends bench/jit_trace.lua with three lazy hot-path checks:
index pass, sparse :get x2, and untouched :encode. All compile with
no fatal aborts (19/19 trace-stability checks pass; one harmless
side-trace bridge per scenario at lazy.lua's index loop, same pattern
as the existing decode_varint bridge).
aff3ee42 — Eugene Blikh 3 months ago
M6: trace stability gate + two fixes

Add `make jit-trace` (`bench/jit_trace.lua`) — a standalone tarantool
script that attaches a `jit.attach('trace')` listener over each hot
encode/decode path and asserts no aborts in our source files fall into
the fatal set (NYI bytecode, blacklisting, persistent type instability).
Runs outside luatest because on macOS arm64 the test framework exhausts
JIT mcode pages before the test body runs, masking real abort reasons.

Two fixes shipped to make all 13 scenarios pass:

  - `decode_varint` grew a 1-byte fast path. Before, calling it from a
    hot decode loop pulled an inner `while true do` into the caller's
    root trace, which got blacklisted after enough retries.

  - `pb.finalize_message` now precomputes `desc.oneofs_list` (array
    form) and the runtime-mode codec iterates it with ipairs instead
    of `pairs(desc.oneofs)`. `pairs()` over a hash-keyed table compiles
    to bytecode ISNEXT, which is NYI in LuaJIT 2.1.

The gate also reports interpreter-bridge counts as a benchmark-quality
metric. Decoders show 0-4 bridges per run depending on JIT timing —
caused by side traces returning from inlined `decode_varint` calls,
which LuaJIT 2.1 can't stitch back cleanly. Small per-call overhead on
the multi-byte slow path, structural to the engine.

Scope caveat: map fields encode via `pairs()` and remain off-trace —
pinned by the gate's last scenario so we notice if upstream lifts the
restriction.