Files
ruby/benchmark/keyword_arguments_many.yml
Nobuyoshi Nakada 74856fbfb6 Use identity sets to track unspecified keyword arguments
Keyword tracking only needs membership, so replace identity hashes
with identity sets to avoid storing unused values.  Add `rb_set_p`
for the type assertion in `vm_check_keyword`.

Add benchmarks for 31, 32 and 128 keyword parameters with sparse and
dense dynamic defaults, using both direct keywords and keyword splats.
The 31-parameter cases provide a bitmask-only control.

Local arm64 macOS measurements show about 16-26% higher throughput
with many omitted dynamic defaults at 32 and 128 parameters.  Smaller
differences remain noisy, including in the bitmask-only controls.

The tracking container is created at call time, leaving IBF and
`ISeq#to_a` unchanged.  Verify IBF-loaded calls with the Integer
refinement and colliding keyword indices from [Bug #22335].
2026-09-23 21:36:41 +09:00

29 lines
1.1 KiB
YAML

# 31 keywords use the bitmask; 32 and 128 exercise the overflow container.
# Sparse defaults are dynamic only for the last two keywords; dense defaults
# are all dynamic. Reuse an object to avoid allocating default values.
prelude: |
DEFAULT = Object.new
kwargs = {k0: 0}
[31, 32, 128].each do |n|
[:sparse, :dense].each do |kind|
params = n.times.map do |i|
default = kind == :dense || i >= n - 2 ? "DEFAULT" : "0"
"k#{i}: #{default}"
end
eval "def many_#{n}_#{kind}(#{params.join(", ")}); end"
end
end
benchmark:
kw_31_sparse: "many_31_sparse(k0: 0)"
kwsplat_31_sparse: "many_31_sparse(**kwargs)"
kw_31_dense: "many_31_dense(k0: 0)"
kwsplat_31_dense: "many_31_dense(**kwargs)"
kw_32_sparse: "many_32_sparse(k0: 0)"
kwsplat_32_sparse: "many_32_sparse(**kwargs)"
kw_32_dense: "many_32_dense(k0: 0)"
kwsplat_32_dense: "many_32_dense(**kwargs)"
kw_128_sparse: "many_128_sparse(k0: 0)"
kwsplat_128_sparse: "many_128_sparse(**kwargs)"
kw_128_dense: "many_128_dense(k0: 0)"
kwsplat_128_dense: "many_128_dense(**kwargs)"