Skip to content

Instantly share code, notes, and snippets.

@nirvdrum
Last active February 17, 2026 19:33
Show Gist options
  • Select an option

  • Save nirvdrum/3aec0704bdf83ff6b97d5bd944ac0528 to your computer and use it in GitHub Desktop.

Select an option

Save nirvdrum/3aec0704bdf83ff6b97d5bd944ac0528 to your computer and use it in GitHub Desktop.
Parsing perf data files...
YJIT: perf-data/yjit-lobsters.data
ZJIT: perf-data/zjit-lobsters.data
==========================================================================================
PERF COMPARISON: YJIT vs ZJIT (Lobsters benchmark)
==========================================================================================
Metric YJIT ZJIT
----------------------------------------------------------------------
Total cycles (approx.) 154,765,754,535 212,917,935,753
Sample duration 34433.2 ms 47116.3 ms
Cycle ratio (ZJIT/YJIT) 1.00x 1.38x
ZJIT uses ~38% more CPU cycles than YJIT (58,152,181,218 extra cycles).
==========================================================================================
SECTION 1: DSO (Shared Object) Breakdown
==========================================================================================
This shows where cycles are spent by library/component.
Percentages are relative to each profile's total cycles.
DSO YJIT % ZJIT % Diff (pp) YJIT cycles ZJIT cycles
-----------------------------------------------------------------------------------------------
ruby 52.58% 63.42% +10.84pp 81,375,833,735 135,032,554,855 <<<
sqlite3_native.so 18.71% 13.82% -4.89pp 28,956,672,673 29,425,258,721
[JIT] 12.54% 9.83% -2.71pp 19,407,625,619 20,929,833,085
libc.so.6 10.93% 9.02% -1.91pp 16,915,896,971 19,205,197,805
sha2.so 2.71% 1.97% -0.74pp 4,194,151,948 4,194,483,334
libz.so.1.3.1 1.05% 0.78% -0.27pp 1,625,040,423 1,660,759,899
libcrypto.so.3 0.69% 0.52% -0.17pp 1,067,883,706 1,107,173,266
libyaml-0.so.2.0.9 0.24% 0.22% -0.02pp 371,437,811 468,419,459
escape.so 0.12% 0.08% -0.04pp 185,718,905 170,334,349
date_core.so 0.10% 0.07% -0.03pp 154,765,755 149,042,555
[vdso] 0.08% 0.07% -0.01pp 123,812,604 149,042,555
[unknown] 0.06% 0.05% -0.01pp 92,859,453 106,458,968
generator.so 0.04% 0.04% +0.00pp 61,906,302 85,167,174
libm.so.6 0.04% 0.02% -0.02pp 61,906,302 42,583,587
openssl.so 0.03% 0.02% -0.01pp 46,429,726 42,583,587
nokogiri.so 0.03% 0.02% -0.01pp 46,429,726 42,583,587
psych.so 0.02% 0.02% +0.00pp 30,953,151 42,583,587
digest.so 0.01% 0.01% +0.00pp 15,476,575 21,291,794
commonmarker.so 0.01% 0.01% +0.00pp 15,476,575 21,291,794
bigdecimal.so 0.01% 0.01% +0.00pp 15,476,575 21,291,794
zlib.so 0.01% 0.00% -0.01pp 15,476,575 0
stringio.so 0.00% 0.00% +0.00pp 0 0
==========================================================================================
SECTION 2: Interpreter vs JIT Code Execution
==========================================================================================
This is the most critical section. A JIT compiler's value comes from
replacing interpreter execution with compiled native code.
YJIT % ZJIT % YJIT cycles ZJIT cycles
------------------------------------------------------------------------------------------
vm_exec_core (interpreter) 1.23% 8.60% 1,903,618,781 18,310,942,475
JIT-compiled code 12.54% 9.83% 19,407,625,619 20,929,833,085
FINDING: ZJIT spends 7.0x more of its profile in the interpreter loop.
In absolute terms: 16,407,323,694 extra cycles in vm_exec_core.
That's 28.2% of the total cycle gap.
YJIT: 1.23% in interpreter, 12.54% in JIT code
ZJIT: 8.60% in interpreter, 9.83% in JIT code
This suggests ZJIT is compiling fewer methods or falling back to the
interpreter more often. The interpreter loop is the single largest
source of overhead difference.
==========================================================================================
SECTION 3: VM Send / Call Infrastructure Overhead
==========================================================================================
These functions handle method dispatch, argument setup, and frame management.
An effective JIT should inline or eliminate many of these by compiling call
sequences directly into native code.
Symbol YJIT % ZJIT % Diff (pp) Extra cycles
----------------------------------------------------------------------------------------------------
rb_vm_opt_send_without_block 1.07% 2.43% +1.36pp 3,517,912,265 ZJIT higher
rb_vm_send 0.21% 0.75% +0.54pp 1,271,876,433 ZJIT higher
rb_vm_exec 1.02% 1.24% +0.22pp 1,061,571,707
vm_call_iseq_setup 0.84% 1.43% +0.59pp 1,744,694,143 ZJIT higher
vm_call_iseq_setup_normal_0start_0params_0locals 0.59% 1.56% +0.97pp 2,408,401,846 ZJIT higher
vm_call_iseq_setup_normal_0start_1params_1locals 0.17% 0.84% +0.67pp 1,525,408,877 ZJIT higher
vm_call_iseq_setup_normal_opt_start 0.13% 0.35% +0.22pp 544,017,294
vm_call_cfunc_with_frame_ 0.31% 1.23% +0.92pp 2,139,116,771 ZJIT higher
vm_call0_body 0.88% 0.66% -0.22pp 43,319,736
vm_call_method_each_type 0.24% 0.41% +0.17pp 501,525,726
vm_call_iseq_bmethod 0.20% 0.34% +0.14pp 414,389,473
vm_call_ivar 0.14% 0.45% +0.31pp 741,458,655
vm_lookup_cc 0.59% 1.39% +0.80pp 2,046,441,355 ZJIT higher
callable_method_entry_or_negative 1.01% 0.92% -0.09pp 395,710,888
vm_callee_setup_arg 0.38% 0.51% +0.13pp 497,771,605
setup_parameters_complex 0.56% 1.02% +0.46pp 1,305,074,720 ZJIT higher
vm_yield_setup_args 0.68% 0.40% -0.28pp -200,735,388
invoke_block_from_c_bh 0.56% 0.39% -0.17pp -36,308,276
vm_invoke_iseq_block 0.10% 0.45% +0.35pp 803,364,956
vm_push_frame 0.32% 0.24% -0.08pp 15,752,631
CALLER_SETUP_ARG 0.31% 0.33% +0.02pp 222,855,349
vm_caller_setup_fwd_args 0.25% 0.09% -0.16pp -195,288,244
rb_vm_invokeblock 0.08% 0.23% +0.15pp 365,898,648
vm_search_super_method 0.37% 0.23% -0.14pp -82,922,040
vm_base_ptr 0.12% 0.57% +0.45pp 1,027,913,329
rb_call0 0.45% 0.33% -0.12pp 6,183,293
rb_funcallv_scope.constprop.0 0.81% 0.61% -0.20pp 45,196,796
rb_vm_opt_getconstant_path 0.13% 0.39% +0.26pp 629,184,468
rb_vm_getinstancevariable 0.00% 0.52% +0.52pp 1,107,173,266
rb_ec_stack_check 0.23% 0.38% +0.15pp 453,126,921
rb_block_given_p 0.34% 0.25% -0.09pp 6,091,274
----------------------------------------------------------------------------------------------------
TOTAL dispatch overhead 13.09% 20.94% +7.85pp 24,326,178,477
FINDING: ZJIT spends 24,326,178,477 more cycles on VM dispatch/call infrastructure.
That's 41.8% of the total cycle gap.
==========================================================================================
SECTION 4: Memory Allocation & GC Overhead
==========================================================================================
Symbol YJIT % ZJIT % Diff (pp) Extra cycles
-----------------------------------------------------------------------------------------------
rb_wb_protected_newobj_of 1.67% 1.48% -0.19pp 566,597,348
gc_sweep_step 0.00% 0.00% +0.00pp 0
gc_mark_check_t_none 0.16% 0.11% -0.05pp -13,415,478
gc_mark_internal.part.0 0.34% 0.23% -0.11pp -36,492,313
rb_gc_impl_writebarrier 0.58% 0.57% -0.01pp 315,990,858
rb_gc_obj_slot_size 0.21% 0.17% -0.04pp 36,952,406
__libc_malloc2 1.00% 0.96% -0.04pp 496,354,638
_int_malloc 1.50% 1.45% -0.05pp 765,823,750
_int_free_chunk 1.17% 0.99% -0.18pp 297,128,236
malloc 0.52% 0.40% -0.12pp 46,889,819
cfree@GLIBC_2.2.5 0.57% 0.42% -0.15pp 12,090,529
malloc_consolidate 0.49% 0.46% -0.03pp 221,070,307
unlink_chunk.isra.0 0.23% 0.20% -0.03pp 69,874,637
__memmove_avx512_unaligned_erms 1.70% 1.35% -0.35pp 243,374,306
-----------------------------------------------------------------------------------------------
TOTAL alloc/GC overhead 10.14% 8.79% -1.35pp 3,022,239,043
==========================================================================================
SECTION 5: Object Model & Data Structure Lookups
==========================================================================================
Symbol YJIT % ZJIT % Diff (pp) Extra cycles
-----------------------------------------------------------------------------------------------
rb_hash_aref 0.73% 0.55% -0.18pp 41,258,639
rb_hash_fetch_m 0.33% 0.23% -0.10pp -21,015,738
rb_st_lookup 0.56% 0.44% -0.12pp 70,150,692
rb_any_hash 0.46% 0.36% -0.10pp 54,582,098
ruby_sip_hash13 0.61% 0.45% -0.16pp 14,059,608
rb_str_hash 0.27% 0.22% -0.05pp 50,551,922
find_table_entry_ind 0.67% 0.51% -0.16pp 48,950,917
ar_update 0.45% 0.33% -0.12pp 6,183,293
tbl_update_modify 0.35% 0.26% -0.09pp 11,906,492
rb_obj_is_kind_of 0.52% 0.47% -0.05pp 195,932,374
rb_obj_class 0.30% 0.23% -0.07pp 25,413,988
rb_shape_get_iv_index 0.55% 0.30% -0.25pp -212,457,843
rb_shape_get_iv_index_with_hint 0.09% 1.06% +0.97pp 2,117,640,940 <<<
rb_ivar_get_at_no_ractor_check 0.40% 0.19% -0.21pp -214,518,940
rb_managed_id_table_lookup 0.94% 1.29% +0.35pp 1,291,843,278 <<<
rb_concurrent_set_find 0.28% 0.21% -0.07pp 13,783,552
==========================================================================================
SECTION 6: ZJIT Entry Trampoline Overhead
==========================================================================================
ZJIT entry trampoline: 0.69% (1,469,133,757 cycles)
This is 2.5% of the total cycle gap.
This is overhead from transitions between the interpreter and JIT-compiled code.
YJIT does not have an equivalent visible symbol because its transitions are
tightly integrated. This cost could be reduced by compiling more methods
(fewer transitions) or optimizing the trampoline itself.
==========================================================================================
SECTION 7: Top JIT-compiled Functions
==========================================================================================
Functions where the JIT spends the most time. Compare to see if ZJIT
is generating less efficient code for the same methods.
--- Top 20 ZJIT JIT-compiled functions ---
% Symbol
------------------------------------------------------------------------------------------
0.69% zjit::ZJIT entry trampoline
0.19% zjit::each@<internal:array>:222
0.14% zjit::block in redefine@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/class_attribute.rb:15
0.10% zjit::change@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/time/calculations.rb:124
0.08% zjit::block in fetch_value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb:47
0.08% zjit::[]@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/isolated_execution_state.rb:32
0.07% zjit::for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/timestamp.rb:112
0.07% zjit::build_arel@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/query_methods.rb:1751
0.07% zjit::fetch_value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb:42
0.07% zjit::safe_concat@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/buffers.rb:57
0.06% zjit::visit@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/visitors/visitor.rb:27
0.06% zjit::map@<internal:array>:240
0.05% zjit::to_sql_and_binds@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:17
0.05% zjit::block in period_for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/data_sources/transitions_data_timezone_info.rb:45
0.05% zjit::perform_query@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/sqlite3/database_statements.rb:87
0.04% zjit::hash@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/type/value.rb:130
0.04% zjit::advance@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/time/calculations.rb:195
0.04% zjit::block in tag_options@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/helpers/tag_helper.rb:240
0.04% zjit::_read_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods/read.rb:39
0.04% zjit::initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/psych-5.2.6/lib/psych/nodes/scalar.rb:58
--- Top 20 YJIT JIT-compiled functions ---
% Symbol
------------------------------------------------------------------------------------------
0.16% [JIT] block in redefine@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/class_attribute.rb:15
0.14% 0x000055554d36e001
0.06% [JIT] safe_concat@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/buffers.rb:56
0.05% [JIT] each@<internal:array>:219
0.05% [JIT] block in period_for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/data_sources/transitions_data_timezone_info.rb:45
0.04% [JIT] []@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/isolated_execution_state.rb:31
0.04% [JIT] _read_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods/read.rb:38
0.04% 0x000055554d36e000
0.04% [JIT] fetch_value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb:41
0.04% [JIT] <<@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/collectors/plain_string.rb:14
0.03% [JIT] []@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/isolated_execution_state.rb:31
0.03% [JIT] fetch_value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb:41
0.03% [JIT] connection_specification_name@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_handling.rb:319
0.02% [JIT] _read_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods/read.rb:38
0.02% [JIT] []@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb:21
0.02% 0x000055554d36e007
0.02% [JIT] association@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations.rb:53
0.02% [JIT] block in apply_inflections@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/inflector/methods.rb:382
0.02% [JIT] get_header@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/rack-2.2.19/lib/rack/request.rb:62
0.02% [JIT] query_cache@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract/query_cache.rb:203
==========================================================================================
SECTION 8: JIT Method Comparison (same methods, both JITs)
==========================================================================================
Where both JITs compile the same Ruby method, compare how much time each
spends. Larger ZJIT overhead suggests less efficient generated code.
YJIT % ZJIT % Diff (pp) Method
-----------------------------------------------------------------------------------------------
0.00% 0.10% +0.10pp change@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/time/calculations.rb
0.00% 0.07% +0.07pp for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/timestamp.rb
0.00% 0.07% +0.07pp build_arel@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/query_methods.rb
0.14% 0.19% +0.05pp each@<internal:array>
0.00% 0.05% +0.05pp to_sql_and_binds@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb
0.04% 0.08% +0.04pp block in fetch_value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb
0.00% 0.04% +0.04pp block in with_raw_connection@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract_adapter.rb
0.00% 0.04% +0.04pp initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/psych-5.2.6/lib/psych/nodes/scalar.rb
0.00% 0.04% +0.04pp advance@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/time/calculations.rb
0.01% 0.05% +0.04pp perform_query@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/sqlite3/database_statements.rb
0.02% 0.05% +0.03pp blank?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/object/blank.rb
0.00% 0.03% +0.03pp block in periods_for_local@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/data_sources/transitions_data_timezone_info.rb
0.00% 0.03% +0.03pp run_callbacks@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/callbacks.rb
0.00% 0.03% +0.03pp for_time@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/tzinfo-2.0.6/lib/tzinfo/timestamp.rb
0.00% 0.03% +0.03pp path_for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/http/url.rb
0.01% 0.04% +0.03pp hash@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/type/value.rb
0.00% 0.03% +0.03pp initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/time_with_zone.rb
0.00% 0.02% +0.02pp query_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods/query.rb
0.00% 0.02% +0.02pp column_indexes@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/result.rb
0.00% 0.02% +0.02pp call@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/callbacks.rb
0.00% 0.02% +0.02pp with_connection@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract/connection_pool.rb
0.00% 0.02% +0.02pp build_joins@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/query_methods.rb
0.00% 0.02% +0.02pp block in merge!@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-typedstore-1.6.0/lib/active_record/typed_store/typed_hash.rb
0.00% 0.02% +0.02pp type_cast@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract/quoting.rb
0.00% 0.02% +0.02pp default_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_set/builder.rb
==========================================================================================
SECTION 9: Methods Compiled by YJIT but Not ZJIT
==========================================================================================
Methods that appear in YJIT's JIT-compiled code but have no corresponding
entry in ZJIT's. These represent compilation coverage gaps in ZJIT.
(%% shown is the YJIT overhead for that method.)
YJIT compiled 1936 unique methods, ZJIT compiled 2256 unique methods.
263 methods compiled by YJIT but not ZJIT (total YJIT overhead: 0.00%):
YJIT % Method
-----------------------------------------------------------------------------------------------
0.00% distinct_value=@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/query_methods.rb
0.00% media_type@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_controller/metal.rb
0.00% _app_views_layouts_application_html_erb__4296019992001423022_14368@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/layouts/application.html.erb
0.00% action_encoding_template@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_controller/metal/parameter_encoding.rb
0.00% invoke_after@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/callbacks.rb
0.00% _app_views_stories__listdetail_html_erb__785025534689320369_14688@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/stories/_listdetail.html.erb
0.00% request_class@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/routing/route_set.rb
0.00% render_template_to_object@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/renderer/renderer.rb
0.00% clear_context@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/event_reporter.rb
0.00% block in loaders@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/preloader/branch.rb
0.00% last_chain_scope@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/association_scope.rb
0.00% block in show@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/controllers/stories_controller.rb
0.00% orders@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/select_manager.rb
0.00% current_session_id@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/rack-2.2.19/lib/rack/session/abstract/id.rb
0.00% select_named_joins@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/query_methods.rb
0.00% table_name@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/preloader/association.rb
0.00% connected?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_handling.rb
0.00% block (2 levels) in normalize_options@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/cache.rb
0.00% named_route_exists?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/routing/route_set.rb
0.00% _app_views_comments__comment_html_erb___4352811014797831820_16224@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/comments/_comment.html.erb
0.00% casted_values@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/nodes/homogeneous_in.rb
0.00% respond_to_missing?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods.rb
0.00% _app_views_stories__listdetail_html_erb__785025534689320369_15000@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/stories/_listdetail.html.erb
0.00% track_story_reads@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/controllers/stories_controller.rb
0.00% attempt@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/middleware/static.rb
0.00% block in _app_views_home_rss_erb___3488935662731373248_19224@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/home/rss.erb
0.00% set_binary_encoding@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/request/utils.rb
0.00% block in _app_views_comments_threads_html_erb___2519767291423025005_16208@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/comments/threads.html.erb
0.00% block (2 levels) in search_combinations@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/path_set.rb
0.00% per_form_csrf_tokens@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_controller/metal/request_forgery_protection.rb
0.00% negotiate_mime@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/http/mime_negotiation.rb
0.00% send_preload_links_header@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/helpers/asset_tag_helper.rb
0.00% visit@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/route_generator.rb
0.00% block in _normalize_text@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_controller/metal/rendering.rb
0.00% end_document@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/psych-5.2.6/lib/psych/handlers/document_stream.rb
0.00% extensions@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/association.rb
0.00% initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/middleware/session/cookie_store.rb
0.00% block in sending!@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/http/response.rb
0.00% registry@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/notifications.rb
0.00% !@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/4.1.0+1/delegate.rb
... and 223 more methods
==========================================================================================
SECTION 10: Methods Compiled by ZJIT but Not YJIT
==========================================================================================
Methods that appear in ZJIT's JIT-compiled code but have no corresponding
entry in YJIT's. (This is less common since YJIT typically compiles more.)
583 methods compiled by ZJIT but not YJIT (total ZJIT overhead: 0.06%):
ZJIT % Method
-----------------------------------------------------------------------------------------------
0.01% accept@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/visitors/visitor.rb
0.01% query_cast_attribute@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/attribute_methods/query.rb
0.01% to_i@<internal:numeric>
0.01% to_sym@<internal:symbol>
0.01% level_override@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/logger-1.7.0/lib/logger.rb
0.01% block in clean!@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/connection_adapters/abstract_adapter.rb
0.00% is_a?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/time_with_zone.rb
0.00% find@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/path_set.rb
0.00% render_partial@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/renderer/renderer.rb
0.00% serialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/type/value.rb
0.00% block in value@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb
0.00% merged_options@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/cache.rb
0.00% inheritable_copy@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/ordered_options.rb
0.00% _app_views_stories__listdetail_html_erb___3996640300435158413_14688@/home/nirvdrum/dev/workspaces/ruby-bench/benchmarks/lobsters/app/views/stories/_listdetail.html.erb
0.00% add_bind@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/collectors/bind.rb
0.00% initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/rack-2.2.19/lib/rack/utils.rb
0.00% populate_keys_to_load_and_already_loaded_records@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/preloader/association.rb
0.00% force_equality?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/type/value.rb
0.00% block in serve@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_dispatch/journey/router.rb
0.00% serialized?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/type/value.rb
0.00% template_keys@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/renderer/partial_renderer.rb
0.00% to_s@<internal:pathname_builtin>
0.00% verify_same_origin_request@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionpack-8.1.1/lib/action_controller/metal/request_forgery_protection.rb
0.00% camelize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/string/inflections.rb
0.00% build_children@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/preloader/branch.rb
0.00% in@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/predications.rb
0.00% coder@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/coders/yaml_column.rb
0.00% scope@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/collection_association.rb
0.00% dup@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/hash_with_indifferent_access.rb
0.00% primary_key@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/associations/belongs_to_association.rb
0.00% logger@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/actionview-8.1.1/lib/action_view/log_subscriber.rb
0.00% defaults@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-typedstore-1.6.0/lib/active_record/typed_store/type.rb
0.00% through_reflection?@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/reflection.rb
0.00% parent_comment_id@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activemodel-8.1.1/lib/active_model/attribute_methods.rb
0.00% block in <class:ToSql>@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/visitors/to_sql.rb
0.00% minus_with_coercion@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/core_ext/time/calculations.rb
0.00% extract_attributes@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/relation/where_clause.rb
0.00% scope_for@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/active_record/reflection.rb
0.00% transfer_time_values_to_utc_constructor@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activesupport-8.1.1/lib/active_support/time_with_zone.rb
0.00% initialize@/home/nirvdrum/.rbenv/versions/ruby-master/lib/ruby/gems/4.1.0+1/gems/activerecord-8.1.1/lib/arel/nodes/homogeneous_in.rb
... and 543 more methods
==========================================================================================
SECTION 11: Top Symbols by Absolute Cycle Difference (ZJIT > YJIT)
==========================================================================================
The symbols where ZJIT spends the most extra cycles compared to YJIT.
This shows where the gap actually comes from in absolute terms.
YJIT % ZJIT % Extra ZJIT cyc Symbol (DSO)
-----------------------------------------------------------------------------------------------
1.23% 8.60% 16,407,323,694 vm_exec_core (ruby)
1.07% 2.43% 3,517,912,265 rb_vm_opt_send_without_block (ruby)
0.59% 1.56% 2,408,401,846 vm_call_iseq_setup_normal_0start_0params_0locals (ruby)
0.31% 1.23% 2,139,116,771 vm_call_cfunc_with_frame_ (ruby)
0.09% 1.06% 2,117,640,940 rb_shape_get_iv_index_with_hint (ruby)
0.59% 1.39% 2,046,441,355 vm_lookup_cc (ruby)
0.84% 1.43% 1,744,694,143 vm_call_iseq_setup (ruby)
0.17% 0.84% 1,525,408,878 vm_call_iseq_setup_normal_0start_1params_1locals (ruby)
0.00% 0.69% 1,469,133,757 zjit::ZJIT entry trampoline ([JIT])
0.56% 1.02% 1,305,074,719 setup_parameters_complex (ruby)
0.94% 1.29% 1,291,843,279 rb_managed_id_table_lookup (ruby)
0.21% 0.75% 1,271,876,434 rb_vm_send (ruby)
0.00% 0.52% 1,107,173,266 rb_vm_getinstancevariable (ruby)
1.02% 1.24% 1,061,571,707 rb_vm_exec (ruby)
0.12% 0.57% 1,027,913,328 vm_base_ptr (ruby)
0.10% 0.45% 803,364,956 vm_invoke_iseq_block (ruby)
1.50% 1.45% 765,823,750 _int_malloc (libc.so.6)
0.14% 0.45% 741,458,655 vm_call_ivar (ruby)
0.13% 0.39% 629,184,469 rb_vm_opt_getconstant_path (ruby)
1.67% 1.48% 566,597,348 rb_wb_protected_newobj_of (ruby)
0.13% 0.35% 544,017,294 vm_call_iseq_setup_normal_opt_start (ruby)
0.24% 0.41% 501,525,726 vm_call_method_each_type (ruby)
0.38% 0.51% 497,771,605 vm_callee_setup_arg (ruby)
1.00% 0.96% 496,354,638 __libc_malloc2 (libc.so.6)
0.23% 0.38% 453,126,920 rb_ec_stack_check (ruby)
0.05% 0.24% 433,620,169 vm_call_iseq_forwardable (ruby)
0.05% 0.24% 433,620,169 vm_call_iseq_setup_normal_0start_0params_1locals (ruby)
0.20% 0.34% 414,389,472 vm_call_iseq_bmethod (ruby)
0.00% 0.19% 404,544,078 zjit::each@<internal:array>:222 ([JIT])
1.01% 0.92% 395,710,888 callable_method_entry_or_negative (ruby)
==========================================================================================
SUMMARY
==========================================================================================
Total cycle gap: 58,152,181,218 cycles (ZJIT uses 37.6% more)
Breakdown of where ZJIT's extra cycles come from:
1. Interpreter (vm_exec_core) 16,407,323,694 ( 28.2% of gap)
2. VM dispatch/call infrastructure 24,326,178,477 ( 41.8% of gap)
3. ZJIT entry trampoline 1,469,133,757 ( 2.5% of gap)
4. Object model / data structure lookups 3,494,265,272 ( 6.0% of gap)
Key takeaways:
- The interpreter loop (vm_exec_core) is the single largest difference.
ZJIT: 8.60% vs YJIT: 1.23%. This means ZJIT is not compiling as many
code paths, or is bailing out to the interpreter more often.
- VM dispatch overhead (send, call setup, argument handling) is significantly
higher in ZJIT. YJIT inlines many of these operations into JIT code, while
ZJIT appears to call back into C helper functions for method dispatch.
- ZJIT's JIT code accounts for 9.83% of cycles vs YJIT's 12.54%.
Despite compiling some methods, the interpreter still handles the majority
of execution in ZJIT, limiting the benefit of compiled code.
- The most impactful improvement areas for ZJIT (in priority order):
1. Compile more methods / reduce interpreter fallbacks
2. Inline method dispatch (eliminate rb_vm_opt_send_without_block, etc.)
3. Optimize the ZJIT entry trampoline
4. Generate tighter code for hot compiled methods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment