~bigbes/tarantool

tarantool-protobuf

a33dbecb99a102622400c46b461f679c9ad30662 — Eugene Blikh 3 months ago 46045da
wire: encode_varint 1-byte fast path (up to 3.8× encode throughput)

For non-negative Lua numbers under 0x80, return string.char(n) directly
— no `to_uint64` cdata allocation, no `out` table, no table.concat.
Covers the dominant case for typical payloads: length prefixes for
strings <128 bytes, small int field values, enum ordinals, and most
tag bytes when codegen-precomputation isn't available.

Symmetric to the decode_varint 1-byte fast path in 9f3bfb8 but the
payoff is much bigger because the encode path was paying for both
a cdata allocation and a list-builder per call, not just a varint
loop.

Effect (bench/bench.lua, hello.Person):
  full/10B   encode:  13 →  30 MB/s (2.3×)
  full/100B  encode: 125 → 278 MB/s (2.2×)
  full/1KB   encode:  69 → 210 MB/s (3.0×)
  full/10KB  encode:  98 → 352 MB/s (3.6×)
  full/100KB encode: 108 → 398 MB/s (3.7×)
  runtime/10B   encode:  9 →  16 MB/s (1.8×)
  runtime/100B  encode: 78 → 151 MB/s (1.9×)
  runtime/1KB   encode: 68 → 183 MB/s (2.7×)
  runtime/10KB  encode: 99 → 352 MB/s (3.5×)
  runtime/100KB encode: 109 → 411 MB/s (3.8×)
  decode: unchanged
  alloc/op: unchanged (bench-compare clean)
1 files changed, 8 insertions(+), 0 deletions(-)

M runtime/pb/wire.lua
M runtime/pb/wire.lua => runtime/pb/wire.lua +8 -0
@@ 45,7 45,15 @@ M.to_int64 = to_int64

-- encode_varint(n) -> string
-- Accepts uint64_t/int64_t cdata, Lua number, or boolean.
--
-- Fast path: small non-negative Lua numbers (0..127) become a single
-- string.char(n) call with no cdata allocation, no `out` table, no
-- table.concat. Covers most length prefixes for short strings, many
-- enum ordinals, and most small int values in typical RPC payloads.
local function encode_varint(n)
    if type(n) == 'number' and n >= 0 and n < 0x80 then
        return string.char(n)
    end
    n = to_uint64(n)
    local out = {}
    local i = 1