Spec-Zone.ru › Ruby 3.2

модуль RubyVM::YJIT

Этот модуль позволяет получить доступ к данным о YJIT, инкрементальном компиляторе в процессе выполнения CRuby. Этот модуль предназначен только для разработки YJIT, поэтому все элементы модуля являются специфичными для реализации и не гарантируют стабильности API.

Этот модуль может отсутствовать, если YJIT не поддерживает платформу, для которой построен CRuby. Также не гарантируется стабильность API в ситуациях, когда этот модуль определён.

Методы публичного класса

code_gc() Показать исходный код
# File yjit.rb, line 209
def self.code_gc
  Primitive.rb_yjit_code_gc
end

Освобождает и перекомпилирует весь существующий JIT-код

disasm(iseq) Показать исходный код
# File yjit.rb, line 183
def self.disasm(iseq)
  # If a method or proc is passed in, get its iseq
  iseq = RubyVM::InstructionSequence.of(iseq)

  if self.enabled?
    # Produce the disassembly string
    # Include the YARV iseq disasm in the string for additional context
    iseq.disasm + "\n" + Primitive.rb_yjit_disasm_iseq(iseq)
  else
    iseq.disasm
  end
end

Производит дизассемблирование для iseq

dump_exit_locations(filename) Показать исходный код
# File yjit.rb, line 138
def self.dump_exit_locations(filename)
  unless trace_exit_locations_enabled?
    raise ArgumentError, "--yjit-trace-exits must be enabled to use dump_exit_locations."
  end

  File.binwrite(filename, Marshal.dump(RubyVM::YJIT.exit_locations))
end

Marshal сохраняет местоположения выхода в указанный файл.

Использование:

Если передаётся `–yjit-exit-locations`, автоматически будет создан файл с именем «yjit_exit_locations.dump».

Если нужно вручную собирать трассы, вызовите `dump_exit_locations` напрямую.

Обратите внимание, что вызов этого метода в скрипте сгенерирует статистику после создания дампа, поэтому данные статистики могут включать выходы из самого дампа.

В скрипте вызов:

at_exit do
  RubyVM::YJIT.dump_exit_locations("my_file.dump")
end

Затем запустите файл с указанными параметрами:

ruby --yjit --yjit-trace-exits test.rb

После завершения работы кода используйте Stackprof для чтения файла дампа. См. документацию Stackprof для опций.

enabled?() Показать исходный код
# File yjit.rb, line 13
def self.enabled?
  Primitive.cexpr! 'RBOOL(rb_yjit_enabled_p())'
end

Проверяет, включён ли YJIT

exit_locations() Показать исходный код
# File yjit.rb, line 36
def self.exit_locations
  return unless trace_exit_locations_enabled?

  results = Primitive.rb_yjit_get_exit_locations
  raw_samples = results[:raw].dup
  line_samples = results[:lines].dup
  frames = results[:frames].dup
  samples_count = 0

  # Loop through the instructions and set the frame hash with the data.
  # We use nonexistent.def for the file name, otherwise insns.def will be displayed
  # and that information isn't useful in this context.
  RubyVM::INSTRUCTION_NAMES.each_with_index do |name, frame_id|
    frame_hash = { samples: 0, total_samples: 0, edges: {}, name: name, file: "nonexistent.def", line: nil, lines: {} }
    results[:frames][frame_id] = frame_hash
    frames[frame_id] = frame_hash
  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, count
  i = 0
  while i < raw_samples.length
    stack_length = raw_samples[i] + 1
    i += 1 # consume the stack length

    prev_frame_id = nil
    stack_length.times do |idx|
      idx += i
      frame_id = raw_samples[idx]

      if prev_frame_id
        prev_frame = frames[prev_frame_id]
        prev_frame[:edges][frame_id] ||= 0
        prev_frame[:edges][frame_id] += 1
      end

      frame_info = frames[frame_id]
      frame_info[:total_samples] += 1

      frame_info[:lines][line_samples[idx]] ||= [0, 0]
      frame_info[:lines][line_samples[idx]][0] += 1

      prev_frame_id = frame_id
    end

    i += stack_length # consume the stack

    top_frame_id = prev_frame_id
    top_frame_line = 1

    sample_count = raw_samples[i]

    frames[top_frame_id][:samples] += sample_count
    frames[top_frame_id][:lines] ||= {}
    frames[top_frame_id][:lines][top_frame_line] ||= [0, 0]
    frames[top_frame_id][:lines][top_frame_line][1] += sample_count

    samples_count += sample_count
    i += 1
  end

  results[:samples] = samples_count
  # Set missed_samples and gc_samples to 0 as their values
  # don't matter to us in this context.
  results[:missed_samples] = 0
  results[:gc_samples] = 0
  results
end

Если включено `–yjit-trace-exits`, парсит хеши из Primitive.rb_yjit_get_exit_locations в формат, читаемый Stackprof. Это позволит нам найти точное местоположение выхода в YJIT на основе инструкции, которая его производит.

insns_compiled(iseq) Показать исходный код
# File yjit.rb, line 197
def self.insns_compiled(iseq)
  # If a method or proc is passed in, get its iseq
  iseq = RubyVM::InstructionSequence.of(iseq)

  if self.enabled?
    Primitive.rb_yjit_insns_compiled(iseq)
  else
    Qnil
  end
end

Возвращает список инструкций, скомпилированных YJIT для iseq

reset_stats!() Показать исходный код
# File yjit.rb, line 28
def self.reset_stats!
  Primitive.rb_yjit_reset_stats_bang
end

Удаляет статистику, собранную для `–yjit-stats`.

runtime_stats() Показать исходный код
# File yjit.rb, line 148
def self.runtime_stats
  stats = Primitive.rb_yjit_get_stats
  return stats if stats.nil?

  stats[:object_shape_count] = Primitive.object_shape_count
  return stats unless Primitive.rb_yjit_stats_enabled_p

  side_exits = total_exit_count(stats)
  total_exits = side_exits + stats[:leave_interp_return]

  # Number of instructions that finish executing in YJIT.
  # See :count-placement: about the subtraction.
  retired_in_yjit = stats[:exec_instruction] - side_exits

  # Average length of instruction sequences executed by YJIT
  avg_len_in_yjit = retired_in_yjit.to_f / total_exits

  # This only available on yjit stats builds
  if stats.key?(:vm_insns_count)
    # Proportion of instructions that retire in YJIT
    total_insns_count = retired_in_yjit + stats[:vm_insns_count]
    yjit_ratio_pct = 100.0 * retired_in_yjit.to_f / total_insns_count
    stats[:total_insns_count] = total_insns_count
    stats[:ratio_in_yjit] = yjit_ratio_pct
  end

  # Make those stats available in RubyVM::YJIT.runtime_stats as well
  stats[:side_exit_count]  = side_exits
  stats[:total_exit_count] = total_exits
  stats[:avg_len_in_yjit]  = avg_len_in_yjit

  stats
end

Возвращает хеш статистики, сгенерированный для командной строки `–yjit-stats`. Возвращает nil, если опция не передана или недоступна.

stats_enabled?() Показать исходный код
# File yjit.rb, line 18
def self.stats_enabled?
  Primitive.rb_yjit_stats_enabled_p
end

Проверяет использование `–yjit-stats`.

trace_exit_locations_enabled?() Показать исходный код
# File yjit.rb, line 23
def self.trace_exit_locations_enabled?
  Primitive.rb_yjit_trace_exit_locations_enabled_p
end

Проверяет, включено ли `rb_yjit_trace_exit_locations_enabled_p`.

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API