module ZJIT

This module allows for introspection of ZJIT, CRuby’s just-in-time compiler. Everything in the module is highly implementation specific and the API might be less stable compared to the standard library.

This module may not exist if ZJIT does not support the particular platform for which CRuby is built.

Public Class Methods

Source
# File zjit.rb, line 123defdump_exit_locations(filename)unlesstrace_exit_locations_enabled?raiseArgumentError,"--zjit-trace-exits must be enabled to use dump_exit_locations."endFile.open(filename,"wb")do|file|Marshal.dump(RubyVM::ZJIT.exit_locations,file)file.sizeendend

Marshal dumps exit locations to the given filename.

Usage:

In a script call:

RubyVM::ZJIT.dump_exit_locations("my_file.dump")

Then run the file with the following options:

ruby --zjit --zjit-stats --zjit-trace-exits test.rb

Once the code is done running, use Stackprof to read the dump file. See Stackprof documentation for options.

Source
# File zjit.rb, line 21defenabled?Primitive.cexpr!'RBOOL(rb_zjit_enabled_p)'end

Check if ZJIT is enabled

Source
# File zjit.rb, line 34defexit_locationsreturnunlesstrace_exit_locations_enabled?results =Primitive.rb_zjit_get_exit_locationsraw_samples =results[:raw]line_samples =results[:lines]frames =results[:frames]samples_count =0# Use nonexistent.def as a dummy file name.frame_template = {samples:0,total_samples:0,edges: {},name:name,file:"nonexistent.def",line:nil,lines: {} }# Loop through all possible instructions and setup the frame hash.RubyVM::INSTRUCTION_NAMES.each_with_indexdo|name,frame_id|frames[frame_id] =frame_template.dup.tap {|h|h[:name] =name }end# Loop through the raw_samples and build the hashes for StackProf.# The loop is based off an example in the StackProf documentation and therefore# this functionality can only work with that library.## Raw Samples:# [ length, frame1, frame2, frameN, ..., instruction, count## Line Samples# [ length, line_1, line_2, line_n, ..., dummy value, counti =0whilei<raw_samples.lengthstack_length =raw_samples[i]i+=1# consume the stack lengthsample_count =raw_samples[i+stack_length]prev_frame_id =nilstack_length.timesdo|idx|idx+=iframe_id =raw_samples[idx]ifprev_frame_idprev_frame =frames[prev_frame_id]prev_frame[:edges][frame_id]||=0prev_frame[:edges][frame_id]+=sample_countendframe_info =frames[frame_id]frame_info[:total_samples]+=sample_countframe_info[:lines][line_samples[idx]]||= [0,0]frame_info[:lines][line_samples[idx]][0]+=sample_countprev_frame_id =frame_idendi+=stack_length# consume the stacktop_frame_id =prev_frame_idtop_frame_line =1frames[top_frame_id][:samples]+=sample_countframes[top_frame_id][:lines]||= {}frames[top_frame_id][:lines][top_frame_line]||= [0,0]frames[top_frame_id][:lines][top_frame_line][1]+=sample_countsamples_count+=sample_counti+=1endresults[:samples] =samples_count# These values are mandatory to include for stackprof, but we don't use them.results[:missed_samples] =0results[:gc_samples] =0resultsend

If –zjit-trace-exits is enabled parse the hashes from Primitive.rb_zjit_get_exit_locations into a format readable by Stackprof. This will allow us to find the exact location of a side exit in ZJIT based on the instruction that is exiting.

Source
# File zjit.rb, line 145defreset_stats!Primitive.rb_zjit_reset_stats_bangend

Discard statistics collected for ‘–zjit-stats`.

Source
# File zjit.rb, line 140defstats(target_key =nil)Primitive.rb_zjit_stats(target_key)end

Return ZJIT statistics as aHash

Source
# File zjit.rb, line 135defstats_enabled?Primitive.rb_zjit_stats_enabled_pend

Check if ‘–zjit-stats` is used

Source
# File zjit.rb, line 150defstats_stringbuf =+"***ZJIT: Printing ZJIT statistics on exit***\n"stats =self.statsstats[:guard_type_exit_ratio] =stats[:exit_guard_type_failure].to_f/stats[:guard_type_count]*100# Show counters independent from exit_* or dynamic_send_*print_counters_with_prefix(prefix:'not_inlined_cfuncs_',prompt:'not inlined C methods',buf:,stats:,limit:20)# Don't show not_annotated_cfuncs right now because it mostly duplicates not_inlined_cfuncs# print_counters_with_prefix(prefix: 'not_annotated_cfuncs_', prompt: 'not annotated C methods', buf:, stats:, limit: 20)# Show fallback counters, ordered by the typical amount of fallbacks for the prefix at the timeprint_counters_with_prefix(prefix:'unspecialized_send_def_type_',prompt:'not optimized method types for send',buf:,stats:,limit:20)print_counters_with_prefix(prefix:'unspecialized_send_without_block_def_type_',prompt:'not optimized method types for send_without_block',buf:,stats:,limit:20)print_counters_with_prefix(prefix:'not_optimized_yarv_insn_',prompt:'not optimized instructions',buf:,stats:,limit:20)print_counters_with_prefix(prefix:'send_fallback_',prompt:'send fallback reasons',buf:,stats:,limit:20)# Show most popular unsupported call features. Because each call can# use multiple complex features, a decrease in this number does not# necessarily mean an increase in number of optimized calls.print_counters_with_prefix(prefix:'complex_arg_pass_',prompt:'popular complex argument-parameter features not optimized',buf:,stats:,limit:10)# Show exit counters, ordered by the typical amount of exits for the prefix at the timeprint_counters_with_prefix(prefix:'unhandled_yarv_insn_',prompt:'unhandled YARV insns',buf:,stats:,limit:20)print_counters_with_prefix(prefix:'compile_error_',prompt:'compile error reasons',buf:,stats:,limit:20)print_counters_with_prefix(prefix:'exit_',prompt:'side exit reasons',buf:,stats:,limit:20)# Show no-prefix counters, having the most important stat `ratio_in_zjit` at the endprint_counters([:send_count,:dynamic_send_count,:optimized_send_count,:iseq_optimized_send_count,:inline_cfunc_optimized_send_count,:inline_iseq_optimized_send_count,:non_variadic_cfunc_optimized_send_count,:variadic_cfunc_optimized_send_count,  ],buf:,stats:,right_align:true,base::send_count)print_counters([:dynamic_getivar_count,:dynamic_setivar_count,:compiled_iseq_count,:failed_iseq_count,:compile_time_ns,:profile_time_ns,:gc_time_ns,:invalidation_time_ns,:vm_write_pc_count,:vm_write_sp_count,:vm_write_locals_count,:vm_write_stack_count,:vm_write_to_parent_iseq_local_count,:vm_read_from_parent_iseq_local_count,:guard_type_count,:guard_type_exit_ratio,:code_region_bytes,:side_exit_count,:total_insn_count,:vm_insn_count,:zjit_insn_count,:ratio_in_zjit,  ],buf:,stats:)bufend

Get the summary of ZJIT statistics as aString

Source
# File zjit.rb, line 26deftrace_exit_locations_enabled?Primitive.rb_zjit_trace_exit_locations_enabled_pend

Check if ‘–zjit-trace-exits` is used