~bigbes/tarantool

tarantool-protobuf

4b91822d7ef3b46c24364ccafbe67db596d6047e — Eugene Blikh 3 months ago b1a1147
bench/jit_trace: harden mcode arena + jit.off the listener

Two infra fixes for the trace-stability gate, both reproduced on
Tarantool 3.8.0-entrypoint / LuaJIT 2.1.0-beta3 / macOS arm64.

1. Default JIT mcode arena (sizemcode=32K, maxmcode=512K) is too
   small for our hot-path codegen footprint. Roughly 1 in 10 runs
   the gate reports every check as 'stops=0' with no diagnostic —
   indistinguishable from a real JIT topology regression. jit.v
   shows 'failed to allocate mcode memory at hello_pb.lua:890'
   (the packed lucky_numbers varint loop). Calling
   jit.opt.start('sizemcode=64','maxmcode=4096') at the top of
   the gate gives the arena enough headroom to hold both encoder
   and decoder bodies for the proto3 + proto2 fixtures.

2. The trace listener callback itself can become hot enough to
   be JIT-compiled, which then races with the function being
   recorded (recording-while-recording). Reproduced with a fat
   cb that appends event tuples to a table: starts go up but
   stops drop to ~0. Calling jit.off(cb) on the listener
   prevents this. The current cb body happens to dodge this
   because its branches keep call sites polymorphic — but it's
   fragile; any future extension (per-event timing, pc context)
   would re-trigger the bug. Adds the jit.off as defense.

Verified 20/20 consecutive runs now report 37/37 passing (was
intermittently 0/37 before). Also drops a now-stale "(PLAN.M6)"
reference from the header comment.

beads-tarantool-protobuf-3o2
1 files changed, 20 insertions(+), 1 deletions(-)

M bench/jit_trace.lua
M bench/jit_trace.lua => bench/jit_trace.lua +20 -1
@@ 1,5 1,5 @@
#!/usr/bin/env tarantool
-- Trace-stability gate (PLAN.md M6).
-- Trace-stability gate for protobuf encode/decode hot paths.
--
-- For each hot encode/decode path, run a few thousand iterations with
-- a `trace` listener attached and assert that no trace aborts in


@@ 30,6 30,15 @@ package.path = './runtime/?.lua;./runtime/?/init.lua;'
    .. package.path

jit.on()
-- macOS arm64 mcode arena hardening: the default sizemcode/maxmcode are too
-- small for our combined hot-path codegen footprint, and the allocator
-- intermittently fails to find an executable page within the signed-32-bit
-- offset window. When that happens the gate reports every check as
-- 'stops=0' with no diagnostic — indistinguishable from a real JIT
-- topology regression. Raising the arena past our peak need eliminates
-- the failure mode and keeps the gate's pass/fail signal load-bearing.
jit.opt.start('sizemcode=64', 'maxmcode=4096')

local vmdef = require('jit.vmdef')

-- Codes from jit.vmdef.traceerr (1-indexed). We treat these as fatal —


@@ 94,6 103,16 @@ local function record(fn, warmup_iters, measured_iters)
            end
        end
    end
    -- Defensive: keep the listener out of the JIT. If the callback ever
    -- becomes hot enough to be traced, recording the cb while recording
    -- the function-under-test races and stop events are dropped (starts
    -- still fire, but most traces never finish recording). The current
    -- cb body branches enough to dodge this organically, but any future
    -- extension (per-event timing, pc context capture, etc.) would
    -- re-trigger it silently. Reproducible in a few lines: a fat cb
    -- that appends event tuples to a table drops Person_encode's stop
    -- count from ~9 to 0 on this codebase.
    jit.off(cb)
    jit.attach(cb, 'trace')
    for _ = 1, measured_iters do fn() end
    jit.attach(cb)