ruby/benchmark/array_join_regression.yml
Yaroslav Markin 35b7652058 Speed up Array#join with a memcpy fast path
When every element is a String sharing one ASCII-compatible fast-path
encoding (UTF-8/US-ASCII/ASCII-8BIT) and the separator is compatible, build
the result with a single memcpy pass instead of appending element by element
through rb_str_buf_append. Other cases fall back to the existing path.
2026-06-11 20:59:01 +02:00

45 lines
2.2 KiB
YAML

prelude: |
# --- must NOT take any fast path: prove added precompute-loop checks don't regress ---
# all multibyte UTF-8 (VALID coderange). 7-bit gate bails at elem 0; same-encoding gate TAKES it.
mb_utf8 = Array.new(1000) { "café" }
# ASCII except a trailing multibyte elem: WORST CASE for 7-bit gate (scans all, then falls back).
tail_mb = Array.new(1000) { "a" * 8 }; tail_mb[-1] = "café"
# non-String elements -> ary_join_1 (to_s). Gate bails at type check before coderange.
nonstr_int = Array.new(1000) { |i| i }
# ASCII strings except a trailing Integer: precompute scans strings, then mixed fallback.
mixed_tail = (Array.new(999) { "a" * 8 } << 42)
# UTF-16LE: not ASCII-compatible. Both gates bail immediately.
utf16 = Array.new(1000) { "ab".encode("UTF-16LE") }
# nested arrays -> recursive fallback.
nested = Array.new(500) { [1, 2] }
# 7-bit ASCII elements but a multibyte separator (3-byte em dash). Both gates bail at sep check.
ascii_elems = Array.new(1000) { "a" * 8 }
sep_mb = "—"
# --- fast-path ELIGIBLE variants: confirm benefit generalizes beyond single chars / find crossover ---
# frozen ASCII elements (read-only path).
frozen_elems = Array.new(1000) { ("a" * 8).freeze }
# large elements: where memcpy should dominate and the win decays toward 1x.
big_e256 = Array.new(1000) { "a" * 256 }
big_e1k = Array.new(1000) { "a" * 1024 }
big_e4k = Array.new(1000) { "a" * 4096 }
benchmark:
# regression (fallback / gate worst-case) — all use a 1-byte ASCII separator unless noted
reg_multibyte_utf8: mb_utf8.join(" ")
reg_tail_multibyte: tail_mb.join(" ")
reg_nonstring_int: nonstr_int.join(" ")
reg_mixed_tail_int: mixed_tail.join(" ")
reg_utf16: utf16.join(" ".encode("UTF-16LE"))
reg_nested: nested.join(" ")
reg_multibyte_sep: ascii_elems.join(sep_mb)
# fast-path eligible variants
fp_frozen: frozen_elems.join(" ")
fp_nosep: ascii_elems.join
fp_multichar_sep: ascii_elems.join(", ")
fp_big_e256: big_e256.join(" ")
fp_big_e1k: big_e1k.join(" ")
fp_big_e4k: big_e4k.join(" ")