Repository navigation
perf: build call frames in place and inline apply_int - #438
Merged
Merged
Conversation
Profiling a zero-arg call loop on x86 showed two store-forwarding stalls on the method-call path. Vec::push takes the 192-byte Frame by value, so it was assembled on the stack with narrow stores and then copied with a libc memcpy whose wide loads could not be forwarded; that memcpy was ~14% of cycles. BinOpKind::apply_int was not inlined into BinOpLocalLocal and returned its Option<Value> through memory. push_frame_in_place writes the Frame straight into the vector's spare capacity at the five cached method-call push sites, and apply_int is now #[inline(always)]. A 30M-iteration o.n loop drops from ~11.8e9 to ~10.7e9 cycles on starship; Apple silicon gains less (o.n ~73 -> ~71 ns), consistent with its cheaper forwarding. Closes #437.
# Conflicts: # CHANGELOG.md
gapscan PR diffThis PR doesn't touch any file that affects gapscan classification — See docs/gap-reports/ for the dataset and methodology. |
# Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #437. Part of the per-call fixed cost work (#378, #385).
What
push_frame_in_place(vm.rs) writes aFramestraight intoframes' spare capacity. Five cached method-call push sites in dispatch.rs use it:serve_explicit_recv_method,try_invoke_explicit_recv_block_cached,try_invoke_class_singleton_cached,try_invoke_fixed_method_from_stack, andtry_invoke_norecv_block_cached.BinOpKind::apply_intis#[inline(always)].Why
On starship (x86),
while i < n; o.n; i += 1; endretires ~1386 instructions per iteration vs ~328 under CRuby, at a similar IPC. Almost all of the gap is instruction count, which the follow-up ADR will address. Two store-forwarding stalls were the exception, and both are cheap to remove:Vec::pushtakes the 192-byteFrameby value. The frame was assembled on the stack with narrow field stores, then copied with a libcmemcpywhose wide loads could not be store-forwarded. Thatmemcpywas ~14% of cycles.apply_int. It was not inlined intoBinOpLocalLocaland returned itsOption<Value>through memory.Numbers
starship x86.
taskset -c 5 perf stat -e cycles:u, 30M-iterationo.nloop. Master is 69845c0; both binaries were built withline-tables-only.This PR's results are bimodal: about 1 run in 5 lands at master's level. I have not confirmed why; code or stack alignment is a guess.
On the same machine, the whole
shape-bench.rbrun took 30.2 → 29.4 e9 cycles (−2.5%, 3 rounds each). Wall-clockcall0on starship stays within noise.Mac Studio (M2 Max), 5 interleaved rounds, load ~10.
o.no.r,o.n1,o.n2, loop**opts/ opt+rest)The Rails numbers are within noise; this change is too small to move Rails measurably. Apple silicon gaining less than x86 is consistent with its cheaper store-forwarding.
Verification (Mac)
STRESS_GC=1,RUBYRS_JIT_NATIVE=1, and tier 2 (THRESHOLD=1)--no-default-featurescheck-D warnings), both the rubyrseverything,jit-nativeleg and the workspace leg--test embed421/421Not in this PR
push_block_frame,invoke_block1/2, …) and the remaining method push sites. They can follow once this lands.Returnpath, and the Frame size. An ADR draft will plan these next.🤖 Generated with Claude Code