You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ZJIT: Weigh an ivar respecialization by the traffic it would take off the fallback
A frozen ivar dispatch samples what its fallback path is handed and earns an extra
compiled version once a 64-sample window names a shape the dispatch has no arm for.
One missing shape is weak evidence. At a site that is genuinely polymorphic the
fallback sees a long tail of receivers, so a window nearly always contains something
new, and the arm the recompile adds covers a few percent of the traffic while the
version and the code for the whole dispatch are paid in full. On railsbench that is
what happens: the mechanism fires 119 times and dynamic_getivar_count does not move.
Weigh the vote by the share of the window the shapes a recompile would specialize
account for *together*. A per-shape threshold is the wrong shape of test -- it was
tried at 25% and cost rubyboy its win, because its windows are split across two or
three shapes that are individually small and collectively everything. The share is
read off the bucket indices: ProfileEntry now remembers how many shapes the running
dispatch was compiled from, and `Distribution::observe_stable` records a shape without
counting or reordering, so any index at or past that mark is a shape the running code
has no arm for. Shapes the distribution has no room left for, and too-complex shapes
the dispatch would filter back out, are counted as samples but not as fixable ones:
they are exactly the evidence that a recompile will not help. The first of those was
also a plain bug -- a full distribution silently dropped the shape on the floor and
granted a version for an arm the recompile could not add.
Declining a window has a cost the old code never paid, because it used to spend its
two-version budget almost immediately and the next compile dropped the sampling call.
A site that keeps declining keeps sampling, so railsbench closed 31,407 windows --
2M calls on an otherwise exit-free path. Give each compiled version four windows to
spend on evidence that does not pan out, checked with one load off the version the
call already has in hand, and leave the sampling out of anything the ISEQ compiles
after that.
railsbench: ivar_respecialize_count 119 -> 2 with dynamic_getivar_count unchanged
(3.739M), so the removed respecializations bought nothing. Against the same tree they
take compile_time from 5,394ms to 3,945ms (-27%), code_region_bytes from 13.24MB to
12.53MB (-5%), and compiled_iseq_count from 3,473 to 3,311. Declined windows
31,407 -> 222 across 50 versions that gave up. rubyboy is unchanged in every respect:
the same 10 respecializations, the same 23,281,169 dynamic_getivar_count, the same
4,567,040 code_region_bytes, and one declined window in the whole program.
0 commit comments