b59ea8efc7 |
1.000 |
450.9 |
ZJIT: Reserve a label reference's bytes by writing them (ruby#18519) (base) |
fbccb8ac4f |
0.999 |
451.5 |
ZJIT: Expose bucket counts on DistributionSummary |
93970417c8 |
1.003 |
449.4 |
ZJIT: Guard the profiled receiver types of megamorphic call sites |
72b5ea6116 |
1.010 |
446.4 |
ZJIT: Guard receiver types for sends with a literal block |
e3e36fd91b |
1.002 |
449.8 |
ZJIT: Dispatch megamorphic-by-class call sites on one ancestor guard |
41ea490868 |
1.002 |
450.2 |
ZJIT: Look megamorphic send targets up in a class table |
f182afce8c |
0.999 |
451.4 |
ZJIT: Fix invokeblock block-handler profiling and gate its ISEQ chain |
8706bad1f8 |
1.004 |
448.9 |
ZJIT: Dispatch to blocks that only return with a direct JIT-to-JIT call |
99006aca80 |
1.002 |
450.1 |
ZJIT: Inline a block whose non-local return escapes to the frame we compile |
607937d7ab |
1.000 |
450.8 |
ZJIT: Destructure a lone yielded Array for the direct block dispatch |
088b42a163 |
1.002 |
450.2 |
ZJIT: Destructure a lone yielded Array at polymorphic yield sites too |
cae94dab8f |
1.006 |
448.3 |
ZJIT: Specialize yield whose arity does not match the block |
dbe5aa7e8f |
1.002 |
449.9 |
ZJIT: Let a yield-unlocking iterator past the caller's inline budget |
ab56cf176f |
1.007 |
448.0 |
ZJIT: Lay the inlined block frame out on the reshaped yield arguments |
6ac1117571 |
1.002 |
450.2 |
ZJIT: Drop the now-unreachable invokeblock arity-mismatch fallback reason |
8d9005fe9d |
1.005 |
448.6 |
ZJIT: Read the throwing frame's ISEQ through CFP_ISEQ() in vm_throw_start |
5e8fa8b101 |
1.005 |
448.7 |
ZJIT: Dispatch a yield to a block that can break directly |
2a286ff97e |
1.003 |
449.8 |
ZJIT: Call megamorphic ISEQ targets without leaving JIT code |
7d77398b9b |
0.997 |
452.4 |
ZJIT: Size megamorphic send tables to the shapes that need them |
52c435946c |
1.001 |
450.5 |
ZJIT: Compile direct sends to def foo(...) callees |
921e5ce21c |
1.005 |
448.8 |
ZJIT: Compile direct sends to callees with a **rest parameter |
73f2c20acf |
1.001 |
450.3 |
ZJIT: Compile direct sends to callees with an anonymous ** |
7fe4ce55a4 |
1.005 |
448.6 |
ZJIT: Narrow test reg, imm to the immediate's width |
57a28d54ab |
1.015 |
444.2 |
ZJIT: Allocate JITFrames below INT32_MAX |
2de98f9bf0 |
1.009 |
446.7 |
ZJIT: Compile send/send with a profiled method name |
f32800b920 |
1.012 |
445.7 |
ZJIT: Compile splat calls instead of dispatching them dynamically |
8bc85404bc |
1.012 |
445.5 |
ZJIT: Bump VM_INSTRUCTION_SIZE for the new profiled splatarray |
3d0a8c2fb5 |
1.011 |
445.9 |
ZJIT: Read nil for an out-of-bounds Array#[] instead of side-exiting |
c0fed27163 |
1.013 |
445.2 |
ZJIT: Forward a splat straight to the callee's rest parameter |
09ebf123c2 |
1.021 |
441.5 |
ZJIT: Pass a &blk argument through to a direct send |
b0ae5b4177 |
1.020 |
442.1 |
ZJIT: Only branch on the block param proxy for an ISEQ callee |
2c8127083b |
1.019 |
442.6 |
ZJIT: Pass a &blk argument through to a direct C call |
37cabd0c65 |
1.018 |
442.9 |
ZJIT: Pin the forwardable callee's fallback on a &blk call site |
720e77f911 |
1.022 |
441.1 |
ZJIT: Inline callees that a &blk call site passes a block handler to |
da07755ead |
1.022 |
441.3 |
ZJIT: Stop side-exiting forever at unstable super sites |
f200ed58b3 |
1.020 |
442.1 |
ZJIT: Dispatch polymorphic super on the frame's method entry |
013722e299 |
1.027 |
439.2 |
ZJIT: Compile protected calls behind a check on the caller's self |
0b1ed96a03 |
1.025 |
440.0 |
ZJIT: Compile a yield to a Symbol block as the send it stands for |
e913ce9375 |
1.029 |
438.3 |
ZJIT: Drop the now-unreachable invokeblock may-throw fallback reason |
f7a0a83372 |
1.013 |
444.9 |
ZJIT: Let a frozen ivar dispatch earn back the shape it is missing |
ffd1019e36 |
1.025 |
440.0 |
ZJIT: Fall back to a generic ivar access when a shape chain misses |
2c3db83855 |
1.024 |
440.2 |
ZJIT: Back ivar shape-chain misses with a per-name shape table |
d34ae52b40 |
1.022 |
441.3 |
ZJIT: Weigh an ivar respecialization by the traffic it would take off the fallback |
e372630f06 |
1.027 |
439.1 |
ZJIT: Test the ivar reprofile budget inline |
55d4065554 |
1.024 |
440.4 |
ZJIT: Let a getivar site's profile forget boot-time shapes |
00ef8c1683 |
1.023 |
440.6 |
ZJIT: Cache the ivar location of class and module shapes |
be07f449b2 |
1.027 |
438.9 |
ZJIT: Test profile eviction and cached class ivars |
f6ff443528 |
1.022 |
441.3 |
ZJIT: Size ivar shape tables to the names that need them |
e5e533c148 |
1.026 |
439.3 |
ZJIT: Hand the SP register back when returning past inlined frames |
b2af99f1da |
1.027 |
439.0 |
ZJIT: Dispatch yield to a run-time block ISEQ without leaving JIT code |
a97775546b |
1.023 |
441.0 |
ZJIT: Dispatch a Symbol block's send through the megamorphic class table |
5aae4cfcf5 |
1.021 |
441.8 |
ZJIT: Insert the missing zjit_splatarray in the checked-in bindings |
887ae5a22e |
1.024 |
440.5 |
ZJIT: Inline def foo(...) callees and compile the bar(...) inside them |
6c9e6a68ee |
1.041 |
433.3 |
ZJIT: Specialize bar(...) in standalone forwardable ISEQs |
cd8025014a |
1.043 |
432.3 |
ZJIT: Fuse Test and fixnum compares into CondBranch |
3b2d0a7e8b |
1.052 |
428.8 |
ZJIT: Fuse type tests into the branch that consumes them |
bd9f496b4f |
1.061 |
425.0 |
ZJIT: Split cold code into an outlined code region |
f5bafc5aea |
1.065 |
423.3 |
ZJIT: Assert with_write_ptr patches the half it is on |
3e2c13a5ab |
1.058 |
426.2 |
ZJIT: Stop each half of the code region at its own end |
4b910e0aa9 |
1.062 |
424.8 |
ZJIT: Allocate callee-saved registers to call-crossing VRegs |
5dd4a434ed |
1.067 |
422.7 |
ZJIT: Remove CheckInterrupts in empty inline frames |
f8e5349cdb |
1.061 |
424.9 |
ZJIT: Remove the trivial inliner |
c749360d5f |
1.064 |
423.9 |
ZJIT: Remove NoTracePoint patch points in empty inline frames |
61974e367f |
1.061 |
425.0 |
ZJIT: Elide inline frames around leaf builtin calls |
b1ab8d9cd1 |
1.063 |
424.2 |
ZJIT: Retry inlining annotated builtins after type inference |
504d291dfd |
1.061 |
424.9 |
ZJIT: Update opt_tests snapshots for the empty-inline-frame elimination |
2f22d768e9 |
1.063 |
424.0 |
ZJIT: cut the cost of the GC mark hooks |
63d34ffe94 |
1.067 |
422.7 |
ZJIT: Coalesce block params with the arguments feeding them |
41e90501eb |
1.064 |
423.7 |
ZJIT: Rematerialize block params that can only hold one value |
d064b6c3ac |
1.071 |
421.1 |
ZJIT: Make the block-param coalescing analysis linear |
a4d8070e04 |
1.068 |
422.2 |
ZJIT: Shrink side-exit stubs with a shared metadata table |
d1ce2014fc |
1.069 |
421.7 |
ZJIT: Skip the bounds check on the side-exit metadata lookup |
ff371cafae |
1.063 |
424.1 |
ZJIT: Profile ISEQs before function stub compilation |
1297d69808 |
1.062 |
424.5 |
ZJIT: Compile the once instruction |
e848a42abb |
1.059 |
425.9 |
ZJIT: Grow the array instead of side-exiting on out-of-range Array#[]= |
37a00b6c38 |
1.063 |
424.3 |
ZJIT: Compute the coderange instead of side-exiting when it is unknown |
e3ccdd7fad |
1.067 |
422.7 |
ZJIT: Profile expandarray and compile one shape per site |
c124fa60d5 |
1.068 |
422.3 |
ZJIT: Renumber YJIT's instruction bindings for zjit_expandarray |
4dc9d55c82 |
1.065 |
423.5 |
ZJIT: Inline a fast path for Array#push and Array#<< |
2174f109b8 |
1.068 |
422.0 |
ZJIT: Skip redundant cfp->sp stores |
2dc25a0444 |
1.067 |
422.8 |
ZJIT: Skip redundant local spill stores |
b9596c23b1 |
1.067 |
422.6 |
ZJIT: Test that spill elision keeps frame locals observable |
3303693b7e |
1.068 |
422.1 |
ZJIT: Don't break spilled parallel-copy cycles through SCRATCH_REG |
0f2743ee57 |
1.069 |
421.8 |
ZJIT: Break down zjit_alloc_bytes by subsystem |
bcadbeadfb |
1.067 |
422.8 |
ZJIT: Release an ISEQ's profile and GC offsets when the ISEQ is freed |
ab396b7bd0 |
1.070 |
421.3 |
ZJIT: Size operand type profiles exactly |
f0638f31ae |
1.066 |
423.1 |
ZJIT: Box the polymorphic tail of a type distribution |
c9e6722195 |
1.067 |
422.4 |
ZJIT: Box the rarely-used profile side tables |
5ba271156d |
1.066 |
423.0 |
ZJIT: Stop over-reserving in long-lived metadata vectors |
6129f47787 |
1.064 |
423.9 |
ZJIT: Pin the profiling metadata layout the memdiet merge depends on |
4a162a7816 |
1.071 |
421.1 |
ZJIT: Free the payload of a GC-freed ISEQ and account dead-version bytes |
cfea460e2f |
1.077 |
418.7 |
ZJIT: Let invalidated ISEQs recompile instead of exiting forever |
4455e638ef |
1.087 |
415.0 |
ZJIT: Compile past polymorphic splatkw instead of side-exiting |
b6072e749d |
1.103 |
409.0 |
ZJIT: Recognize an unpassed block at unspecialized block-param sites |
4f0c06814f |
1.102 |
409.1 |
ZJIT: Initialize the block param local when a function stub exits |
4c1e741e67 |
1.104 |
408.4 |
ZJIT: Compile exception handler entries (jit_exception) |
480d6a3ba3 |
1.102 |
409.1 |
ZJIT: Materialize frames before pushing a caught break value |
60e78ec08b |
1.110 |
406.2 |
ZJIT: Re-enter JIT code for frames unwound back into after a throw |
6821f4f286 |
1.102 |
409.0 |
ZJIT: Dispatch exception handler entries over several continuations |
302657336c |
1.100 |
410.1 |
ZJIT: Keep the profiled shape reachable through guards and dispatch arms |
e001eb49c6 |
1.099 |
410.2 |
ZJIT: Branch on the ivar shape for attr_accessor sends in polymorphic arms |
b59ea8efc7 |
1.083 |
416.4 |
YJIT row — base commit run with --yjit (vs base ZJIT) |
I'm focusing on lobsters again, so I filed a separate issue from #1030. Take 3 of the effort after #833 and #713.
I have a branch where ZJIT is faster than YJIT on lobsters. The goal of this issue is to upstream the most reasonable ideas out of it in cleaner patches, not necessarily porting everything.
Branch
This is a branch that originally had more patches, which got reduced to fewer patches and then rebased.
List of patches
I have previously benchmarked each revision so we can know the impact of each change. Note: The latency was measured on a different CPU from the above.
b59ea8efc7fbccb8ac4f93970417c872b5ea6116e3e36fd91b41ea490868f182afce8c8706bad1f899006aca80607937d7ab088b42a163cae94dab8fyieldwhose arity does not match the blockdbe5aa7e8fyield-unlocking iterator past the caller's inline budgetab56cf176fyieldarguments6ac11175718d9005fe9d5e8fa8b101yieldto a block that canbreakdirectly2a286ff97e7d77398b9b52c435946cdef foo(...)callees921e5ce21c**restparameter73f2c20acf**7fe4ce55a4test reg, immto the immediate's width57a28d54ab2de98f9bf0f32800b9208bc85404bc3d0a8c2fb5c0fed2716309ebf123c2&blkargument through to a direct sendb0ae5b41772c8127083b&blkargument through to a direct C call37cabd0c65&blkcall site720e77f911&blkcall site passes a block handler toda07755eadf200ed58b3superon the frame's method entry013722e2990b1ed96a03yieldto a Symbol block as the send it stands fore913ce9375f7a0a83372ffd1019e362c3db83855d34ae52b40e372630f0655d406555400ef8c1683be07f449b2f6ff443528e5e533c148b2af99f1dayieldto a run-time block ISEQ without leaving JIT codea97775546b5aae4cfcf5887ae5a22edef foo(...)callees and compile thebar(...)inside them6c9e6a68eebar(...)in standalone forwardable ISEQscd8025014a3b2d0a7e8bbd9f496b4ff5bafc5aea3e2c13a5ab4b910e0aa95dd4a434edf8e5349cdbc749360d5f61974e367fb1ab8d9cd1504d291dfd2f22d768e963d34ffe9441e90501ebd064b6c3aca4d8070e04d1ce2014fcff371cafae1297d69808e848a42abb37a00b6c38e3ccdd7fadc124fa60d54dc9d55c822174f109b82dc25a0444b9596c23b13303693b7e0f2743ee57bcadbeadfbab396b7bd0f0638f31aec9e67221955ba271156d6129f477874a162a7816cfea460e2f4455e638efb6072e749d4f0c06814f4c1e741e67480d6a3ba360e78ec08b6821f4f286302657336ce001eb49c6b59ea8efc7--yjit(vs base ZJIT)Details
6c9e6a68ee+1.7% — specializes thebar(...)inside adef foo(...)forwarder that was not itself inlined, which is the shape Rails delegation generates everywhereb6072e749d+1.5% — a site whose block param is never passed a block no longer pays the generic block-param dispatchffd1019e36+1.1% — the last arm of an ivar shape chain was a guard whose only miss target was a side exit, and the recompile it asked for was gated on a reprofile that on rubocop never happened57a28d54ab+1.0% — lets every JIT-to-JIT call site store its JITFrame pointer with the narrow form instead of the wide one4455e638ef+0.9% — a genericInsn::ToHashforsplatkw, plus an InvalidationCause split so an invalidation grant is not spent on a respecialization requestbd9f496b4f+0.9% — moves side-exit stubs and other cold code out of the hot half, so a hot function's instructions sit closer together09ebf123c2+0.9% —foo(&blk)no longer forces the dynamic send path3b2d0a7e8b+0.8% — aHasTypefeeding aCondBranchbuilt an 89-byte diamond that materialized 0/1 into a block parameter and then re-tested itf7a0a83372−1.5% — lets an ivar dispatch compiled underno_side_exitsearn back a shape its pre-invalidation profile never saw; sets up the +1.1% two commits latere3e36fd91b−0.8% — one ancestor guard in place of a chain; the compile-time no-override walk it needs costs a pass over every class in the process3e2c13a5ab−0.7% — bounds the hot half atoutlined_start— a correctness fix for the cold split, and the check is on the emit path6821f4f286−0.7% — splits handler entry into continuations; more entry points to compile7d77398b9b−0.6% — shrinks the per-call-shape send tables, trading hit rate for memory2de98f9bf0−0.6% — guards the profiled method name atsend/__send__sitesf182afce8c— invokeblock profiled block handlers by object identity, so every IFUNC/Proc yield site looked megamorphic; also gated the ISEQ dispatch chain on profile coverage8d9005fe9d— vm_throw_start read a ZJIT-pushed frame's ISEQ via rawcfp->_iseq57a28d54ab— JITFrame pointers on the Rust heap need the wide store form; allocate them belowINT32_MAX(also the largest single win here)8bc85404bc— checked-in ZJIT bindings still saidVM_INSTRUCTION_SIZE = 259after the profiledsplatarraymade it 2605aae4cfcf5—YARVINSN_zjit_splatarrayitself was never added, leaving everyYARVINSN_zjit_*from 229 up one lower than the built VMc124fa60d5— the same staleness in YJIT's copy of the instruction table — asking YJIT for stats panicked37cabd0c65— a&blkcall site stored a callinfo describing an already-popped argument, so a latersendforwardreplayed the call wronge5e533c148—gen_return()left the SP register stale when returning past inlined framesf5bafc5aea— a half switch insidewith_write_ptrwould hand back an empty written range toremove_gc_offsets3e2c13a5ab— bounds were checked per region rather than per half, so a body that filled the inlined half overwrote exit stubs in the outlined half63d34ffe94— three soundness defects in the portedcoalesce_block_params()— this commit is the port with its follow-up fix folded in (see below)3303693b7e—resolve_ssa()broke spilled parallel-copy cycles through SCRATCH_REG, whichscratch_splitalso stages memory-to-memory moves inbcadbeadfb— an IseqPayload was never freed — 86 MB of dead profiles on an RDoc-over-stdlib run4a162a7816—rb_zjit_iseq_freeused the creating getter, allocating and leaking a fresh payload for every GC-freed ISEQ4f0c06814f—prepare_for_exitskipped the block-param local, leaving it uninitialized when a function stub exits to the interpreter480d6a3ba3—vm_exec_handle_exceptionpushed the caught break value before materializing the frame, so the stack map overwrote it