Implement --mjit-stats
This commit is contained in:
parent
5ab8cf3f0d
commit
9f8f1afba2
2
inits.c
2
inits.c
@ -106,8 +106,8 @@ rb_call_builtin_inits(void)
|
||||
BUILTIN(nilclass);
|
||||
BUILTIN(marshal);
|
||||
#if USE_MJIT
|
||||
BUILTIN(mjit);
|
||||
BUILTIN(mjit_c);
|
||||
BUILTIN(mjit);
|
||||
#endif
|
||||
Init_builtin_prelude();
|
||||
}
|
||||
|
68
lib/mjit/stats.rb
Normal file
68
lib/mjit/stats.rb
Normal file
@ -0,0 +1,68 @@
|
||||
# frozen_string_literal: true
|
||||
module RubyVM::MJIT
|
||||
def self.runtime_stats
|
||||
stats = {}
|
||||
|
||||
# Insn exits
|
||||
INSNS.each_value do |insn|
|
||||
exits = C.mjit_insn_exits[insn.bin]
|
||||
if exits > 0
|
||||
stats[:"exit_#{insn.name}"] = exits
|
||||
end
|
||||
end
|
||||
|
||||
# Runtime stats
|
||||
C.rb_mjit_runtime_counters.members.each do |member|
|
||||
stats[member] = C.rb_mjit_counters.public_send(member)
|
||||
end
|
||||
|
||||
# Other stats are calculated here
|
||||
stats[:side_exit_count] = stats.select { |name, _count| name.start_with?('exit_') }.sum(&:last)
|
||||
if stats[:vm_insns_count] > 0
|
||||
retired_in_mjit = stats[:mjit_insns_count] - stats[:side_exit_count]
|
||||
stats[:total_insns_count] = retired_in_mjit + stats[:vm_insns_count]
|
||||
stats[:ratio_in_mjit] = 100.0 * retired_in_mjit / stats[:total_insns_count]
|
||||
end
|
||||
|
||||
stats
|
||||
end
|
||||
|
||||
at_exit do
|
||||
if C.mjit_opts.stats
|
||||
print_stats
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
private
|
||||
|
||||
def print_stats
|
||||
stats = runtime_stats
|
||||
$stderr.puts("***MJIT: Printing MJIT statistics on exit***")
|
||||
|
||||
$stderr.puts "side_exit_count: #{format('%10d', stats[:side_exit_count])}"
|
||||
$stderr.puts "total_insns_count: #{format('%10d', stats[:total_insns_count])}" if stats.key?(:total_insns_count)
|
||||
$stderr.puts "vm_insns_count: #{format('%10d', stats[:vm_insns_count])}" if stats.key?(:vm_insns_count)
|
||||
$stderr.puts "mjit_insns_count: #{format('%10d', stats[:mjit_insns_count])}"
|
||||
$stderr.puts "ratio_in_yjit: #{format('%9.1f', stats[:ratio_in_mjit])}%" if stats.key?(:ratio_in_mjit)
|
||||
|
||||
print_exit_counts(stats)
|
||||
end
|
||||
|
||||
def print_exit_counts(stats, how_many: 20, padding: 2)
|
||||
exits = stats.filter_map { |name, count| [name.to_s.delete_prefix('exit_'), count] if name.start_with?('exit_') }.to_h
|
||||
return if exits.empty?
|
||||
|
||||
top_exits = exits.sort_by { |_name, count| -count }.first(how_many).to_h
|
||||
total_exits = exits.values.sum
|
||||
$stderr.puts "Top-#{top_exits.size} most frequent exit ops (#{format("%.1f", 100.0 * top_exits.values.sum / total_exits)}% of exits):"
|
||||
|
||||
name_width = top_exits.map { |name, _count| name.length }.max + padding
|
||||
count_width = top_exits.map { |_name, count| count.to_s.length }.max + padding
|
||||
top_exits.each do |name, count|
|
||||
ratio = 100.0 * count / total_exits
|
||||
$stderr.puts "#{format("%#{name_width}s", name)}: #{format("%#{count_width}d", count)} (#{format('%.1f', ratio)}%)"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -34,7 +34,7 @@ module RubyVM::MJIT
|
||||
|
||||
def add(dst, src)
|
||||
case [dst, src]
|
||||
# ADD r/m64, imm8
|
||||
# ADD r/m64, imm8 (Mod 11)
|
||||
in [Symbol => dst_reg, Integer => src_imm] if r64?(dst_reg) && imm8?(src_imm)
|
||||
# REX.W + 83 /0 ib
|
||||
# MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
|
||||
@ -44,6 +44,16 @@ module RubyVM::MJIT
|
||||
mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)),
|
||||
imm: imm8(src_imm),
|
||||
)
|
||||
# ADD r/m64, imm8 (Mod 00)
|
||||
in [[Symbol => dst_reg], Integer => src_imm] if r64?(dst_reg) && imm8?(src_imm)
|
||||
# REX.W + 83 /0 ib
|
||||
# MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
|
||||
insn(
|
||||
prefix: REX_W,
|
||||
opcode: 0x83,
|
||||
mod_rm: mod_rm(mod: 0b00, rm: reg_code(dst_reg)), # Mod 00: [reg]
|
||||
imm: imm8(src_imm),
|
||||
)
|
||||
else
|
||||
raise NotImplementedError, "add: not-implemented operands: #{dst.inspect}, #{src.inspect}"
|
||||
end
|
||||
@ -189,6 +199,14 @@ module RubyVM::MJIT
|
||||
@labels[label] = @bytes.size
|
||||
end
|
||||
|
||||
def incr_counter(name)
|
||||
if C.mjit_opts.stats
|
||||
comment("increment counter #{name}")
|
||||
mov(:rax, C.rb_mjit_counters[name].to_i)
|
||||
add([:rax], 1) # TODO: lock
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def insn(prefix: nil, opcode:, mod_rm: nil, disp: nil, imm: nil)
|
||||
|
@ -57,11 +57,8 @@ module RubyVM::MJIT # :nodoc: all
|
||||
# Return the offset to a field
|
||||
define_singleton_method(:offsetof) { |field| members.fetch(field).last / 8 }
|
||||
|
||||
# Get the offset of a member named +name+
|
||||
define_singleton_method(:offsetof) { |name|
|
||||
_, offset = members.fetch(name)
|
||||
offset / 8
|
||||
}
|
||||
# Return member names
|
||||
define_singleton_method(:members) { members.keys }
|
||||
|
||||
define_method(:initialize) do |addr = nil|
|
||||
if addr.nil? # TODO: get rid of this feature later
|
||||
|
@ -26,6 +26,12 @@ module RubyVM::MJIT
|
||||
# @param ctx [RubyVM::MJIT::Context]
|
||||
# @param asm [RubyVM::MJIT::X86Assembler]
|
||||
def self.compile_exit(jit, ctx, asm)
|
||||
if C.mjit_opts.stats
|
||||
insn = decode_insn(C.VALUE.new(jit.pc).*)
|
||||
asm.comment("increment insn exit: #{insn.name}")
|
||||
asm.mov(:rax, (C.mjit_insn_exits + insn.bin).to_i)
|
||||
asm.add([:rax], 1) # TODO: lock
|
||||
end
|
||||
asm.comment("exit to interpreter")
|
||||
|
||||
# Update pc
|
||||
@ -45,6 +51,10 @@ module RubyVM::MJIT
|
||||
asm.ret
|
||||
end
|
||||
|
||||
def self.decode_insn(encoded)
|
||||
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
||||
end
|
||||
|
||||
# @param mem_block [Integer] JIT buffer address
|
||||
def initialize(mem_block)
|
||||
@comments = Hash.new { |h, k| h[k] = [] }
|
||||
@ -59,7 +69,7 @@ module RubyVM::MJIT
|
||||
return if iseq.body.param.flags.has_opt
|
||||
|
||||
asm = X86Assembler.new
|
||||
asm.comment("Block: #{iseq.body.location.label}@#{iseq.body.location.pathobj}:#{iseq.body.location.first_lineno}")
|
||||
asm.comment("Block: #{iseq.body.location.label}@#{pathobj_path(iseq.body.location.pathobj)}:#{iseq.body.location.first_lineno}")
|
||||
compile_prologue(asm)
|
||||
compile_block(asm, iseq)
|
||||
iseq.body.jit_func = compile(asm)
|
||||
@ -121,7 +131,7 @@ module RubyVM::MJIT
|
||||
|
||||
index = 0
|
||||
while index < iseq.body.iseq_size
|
||||
insn = decode_insn(iseq.body.iseq_encoded[index])
|
||||
insn = self.class.decode_insn(iseq.body.iseq_encoded[index])
|
||||
jit.pc = (iseq.body.iseq_encoded + index).to_i
|
||||
|
||||
case compile_insn(jit, ctx, asm, insn)
|
||||
@ -139,7 +149,9 @@ module RubyVM::MJIT
|
||||
# @param ctx [RubyVM::MJIT::Context]
|
||||
# @param asm [RubyVM::MJIT::X86Assembler]
|
||||
def compile_insn(jit, ctx, asm, insn)
|
||||
asm.incr_counter(:mjit_insns_count)
|
||||
asm.comment("Insn: #{insn.name}")
|
||||
|
||||
case insn.name
|
||||
when :putnil then @insn_compiler.putnil(jit, ctx, asm)
|
||||
when :leave then @insn_compiler.leave(jit, ctx, asm)
|
||||
@ -147,16 +159,12 @@ module RubyVM::MJIT
|
||||
end
|
||||
end
|
||||
|
||||
def decode_insn(encoded)
|
||||
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
||||
end
|
||||
|
||||
def dump_disasm(from, to)
|
||||
C.dump_disasm(from, to).each do |address, mnemonic, op_str|
|
||||
@comments.fetch(address, []).each do |comment|
|
||||
puts bold(" # #{comment}")
|
||||
end
|
||||
puts " 0x#{"%x" % address}: #{mnemonic} #{op_str}"
|
||||
puts " 0x#{format("%x", address)}: #{mnemonic} #{op_str}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
@ -164,5 +172,14 @@ module RubyVM::MJIT
|
||||
def bold(text)
|
||||
"\e[1m#{text}\e[0m"
|
||||
end
|
||||
|
||||
# vm_core.h: pathobj_path
|
||||
def pathobj_path(pathobj)
|
||||
if pathobj.is_a?(String)
|
||||
pathobj
|
||||
else
|
||||
pathobj.first
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
29
mjit.c
29
mjit.c
@ -300,6 +300,9 @@ mjit_setup_options(const char *s, struct mjit_options *mjit_opt)
|
||||
else if (opt_match_arg(s, l, "call-threshold")) {
|
||||
mjit_opt->call_threshold = atoi(s + 1);
|
||||
}
|
||||
else if (opt_match_noarg(s, l, "stats")) {
|
||||
mjit_opt->stats = true;
|
||||
}
|
||||
// --mjit=pause is an undocumented feature for experiments
|
||||
else if (opt_match_noarg(s, l, "pause")) {
|
||||
mjit_opt->pause = true;
|
||||
@ -320,10 +323,9 @@ const struct ruby_opt_message mjit_option_messages[] = {
|
||||
M("--mjit-wait", "", "Wait until JIT compilation finishes every time (for testing)"),
|
||||
M("--mjit-save-temps", "", "Save JIT temporary files in $TMP or /tmp (for testing)"),
|
||||
M("--mjit-verbose=num", "", "Print JIT logs of level num or less to stderr (default: 0)"),
|
||||
M("--mjit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: "
|
||||
STRINGIZE(DEFAULT_MAX_CACHE_SIZE) ")"),
|
||||
M("--mjit-call-threshold=num", "", "Number of calls to trigger JIT (for testing, default: "
|
||||
STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
|
||||
M("--mjit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: " STRINGIZE(DEFAULT_MAX_CACHE_SIZE) ")"),
|
||||
M("--mjit-call-threshold=num", "", "Number of calls to trigger JIT (for testing, default: " STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
|
||||
M("--mjit-stats", "", "Enable collecting MJIT statistics"),
|
||||
{0}
|
||||
};
|
||||
#undef M
|
||||
@ -370,6 +372,22 @@ mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id)
|
||||
// JIT buffer
|
||||
uint8_t *rb_mjit_mem_block = NULL;
|
||||
|
||||
#if MJIT_STATS
|
||||
|
||||
struct rb_mjit_runtime_counters rb_mjit_counters = { 0 };
|
||||
|
||||
// Basically mjit_opts.stats, but this becomes false during MJIT compilation.
|
||||
static bool mjit_stats_p = false;
|
||||
|
||||
void
|
||||
rb_mjit_collect_vm_usage_insn(int insn)
|
||||
{
|
||||
if (!mjit_stats_p) return;
|
||||
rb_mjit_counters.vm_insns_count++;
|
||||
}
|
||||
|
||||
#endif // YJIT_STATS
|
||||
|
||||
void
|
||||
rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop)
|
||||
{
|
||||
@ -398,10 +416,12 @@ rb_mjit_compile(const rb_iseq_t *iseq)
|
||||
rb_vm_barrier();
|
||||
bool original_call_p = mjit_call_p;
|
||||
mjit_call_p = false; // Avoid impacting JIT metrics by itself
|
||||
mjit_stats_p = false; // Avoid impacting JIT stats by itself
|
||||
|
||||
VALUE iseq_ptr = rb_funcall(rb_cMJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
|
||||
rb_funcall(rb_MJITCompiler, rb_intern("call"), 1, iseq_ptr);
|
||||
|
||||
mjit_stats_p = mjit_opts.stats;
|
||||
mjit_call_p = original_call_p;
|
||||
RB_VM_LOCK_LEAVE();
|
||||
}
|
||||
@ -443,6 +463,7 @@ mjit_init(const struct mjit_options *opts)
|
||||
rb_cMJITIseqPtr = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
|
||||
|
||||
mjit_call_p = true;
|
||||
mjit_stats_p = mjit_opts.stats;
|
||||
|
||||
// Normalize options
|
||||
if (mjit_opts.call_threshold == 0)
|
||||
|
8
mjit.h
8
mjit.h
@ -15,6 +15,10 @@
|
||||
|
||||
# if USE_MJIT
|
||||
|
||||
#ifndef MJIT_STATS
|
||||
# define MJIT_STATS RUBY_DEBUG
|
||||
#endif
|
||||
|
||||
#include "ruby.h"
|
||||
#include "vm_core.h"
|
||||
|
||||
@ -53,6 +57,8 @@ struct mjit_options {
|
||||
bool wait;
|
||||
// Number of calls to trigger JIT compilation. For testing.
|
||||
unsigned int call_threshold;
|
||||
// Collect MJIT statistics
|
||||
bool stats;
|
||||
// Force printing info about MJIT work of level VERBOSE or
|
||||
// less. 0=silence, 1=medium, 2=verbose.
|
||||
int verbose;
|
||||
@ -117,6 +123,7 @@ void mjit_child_after_fork(void);
|
||||
extern void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
|
||||
extern void rb_mjit_before_ractor_spawn(void);
|
||||
extern void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
|
||||
extern void rb_mjit_collect_vm_usage_insn(int insn);
|
||||
|
||||
# ifdef MJIT_HEADER
|
||||
#define mjit_enabled true
|
||||
@ -150,6 +157,7 @@ static inline void mjit_finish(bool close_handle_p){}
|
||||
static inline void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
|
||||
static inline void rb_mjit_before_ractor_spawn(void) {}
|
||||
static inline void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events) {}
|
||||
static inline void rb_mjit_collect_vm_usage_insn(int insn) {}
|
||||
|
||||
# endif // USE_MJIT
|
||||
#endif // RUBY_MJIT_H
|
||||
|
2
mjit.rb
2
mjit.rb
@ -23,7 +23,7 @@ if RubyVM::MJIT.enabled?
|
||||
return # miniruby doesn't support MJIT
|
||||
end
|
||||
|
||||
RubyVM::MJIT::C = Object.new # forward declaration for mjit/compiler
|
||||
require 'mjit/c_type'
|
||||
require 'mjit/compiler'
|
||||
require 'mjit/stats'
|
||||
end
|
||||
|
12
mjit_c.c
12
mjit_c.c
@ -38,6 +38,11 @@
|
||||
#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
|
||||
#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
|
||||
|
||||
#if MJIT_STATS
|
||||
// Insn side exit counters
|
||||
static size_t mjit_insn_exits[VM_INSTRUCTION_SIZE] = { 0 };
|
||||
#endif // YJIT_STATS
|
||||
|
||||
// macOS: brew install capstone
|
||||
// Ubuntu/Debian: apt-get install libcapstone-dev
|
||||
// Fedora: dnf -y install capstone-devel
|
||||
@ -74,6 +79,13 @@ dump_disasm(rb_execution_context_t *ec, VALUE self, VALUE from, VALUE to)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Same as `RubyVM::MJIT.enabled?`, but this is used before it's defined.
|
||||
static VALUE
|
||||
mjit_enabled_p(rb_execution_context_t *ec, VALUE self)
|
||||
{
|
||||
return RBOOL(mjit_enabled);
|
||||
}
|
||||
|
||||
#include "mjit_c.rbinc"
|
||||
|
||||
#endif // USE_MJIT
|
||||
|
8
mjit_c.h
8
mjit_c.h
@ -104,4 +104,12 @@ struct compile_status {
|
||||
|
||||
extern uint8_t *rb_mjit_mem_block;
|
||||
|
||||
#define MJIT_RUNTIME_COUNTERS(...) struct rb_mjit_runtime_counters { size_t __VA_ARGS__; };
|
||||
MJIT_RUNTIME_COUNTERS(
|
||||
vm_insns_count,
|
||||
mjit_insns_count
|
||||
)
|
||||
#undef MJIT_RUNTIME_COUNTERS
|
||||
extern struct rb_mjit_runtime_counters rb_mjit_counters;
|
||||
|
||||
#endif /* MJIT_C_H */
|
||||
|
35
mjit_c.rb
35
mjit_c.rb
@ -4,7 +4,7 @@
|
||||
module RubyVM::MJIT # :nodoc: all
|
||||
# This `class << C` section is for calling C functions. For importing variables
|
||||
# or macros as is, please consider using tool/mjit/bindgen.rb instead.
|
||||
class << C
|
||||
class << C = Object.new
|
||||
#========================================================================================
|
||||
#
|
||||
# New stuff
|
||||
@ -25,6 +25,28 @@ module RubyVM::MJIT # :nodoc: all
|
||||
}
|
||||
end
|
||||
|
||||
def mjit_insn_exits
|
||||
addr = Primitive.cstmt! %{
|
||||
#if MJIT_STATS
|
||||
return SIZET2NUM((size_t)mjit_insn_exits);
|
||||
#else
|
||||
return SIZET2NUM(0);
|
||||
#endif
|
||||
}
|
||||
CType::Immediate.parse("size_t").new(addr)
|
||||
end
|
||||
|
||||
def rb_mjit_counters
|
||||
addr = Primitive.cstmt! %{
|
||||
#if MJIT_STATS
|
||||
return SIZET2NUM((size_t)&rb_mjit_counters);
|
||||
#else
|
||||
return SIZET2NUM(0);
|
||||
#endif
|
||||
}
|
||||
rb_mjit_runtime_counters.new(addr)
|
||||
end
|
||||
|
||||
# @param from [Integer] - From address
|
||||
# @param to [Integer] - To address
|
||||
def dump_disasm(from, to)
|
||||
@ -374,6 +396,7 @@ module RubyVM::MJIT # :nodoc: all
|
||||
debug_flags: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), debug_flags)")],
|
||||
wait: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), wait)")],
|
||||
call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), call_threshold)")],
|
||||
stats: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), stats)")],
|
||||
verbose: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), verbose)")],
|
||||
max_cache_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), max_cache_size)")],
|
||||
pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), pause)")],
|
||||
@ -657,6 +680,14 @@ module RubyVM::MJIT # :nodoc: all
|
||||
)
|
||||
end
|
||||
|
||||
def C.rb_mjit_runtime_counters
|
||||
@rb_mjit_runtime_counters ||= CType::Struct.new(
|
||||
"rb_mjit_runtime_counters", Primitive.cexpr!("SIZEOF(struct rb_mjit_runtime_counters)"),
|
||||
vm_insns_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), vm_insns_count)")],
|
||||
mjit_insns_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_runtime_counters *)NULL)), mjit_insns_count)")],
|
||||
)
|
||||
end
|
||||
|
||||
def C.rb_mjit_unit
|
||||
@rb_mjit_unit ||= CType::Struct.new(
|
||||
"rb_mjit_unit", Primitive.cexpr!("SIZEOF(struct rb_mjit_unit)"),
|
||||
@ -835,4 +866,4 @@ module RubyVM::MJIT # :nodoc: all
|
||||
end
|
||||
|
||||
### MJIT bindgen end ###
|
||||
end if RubyVM::MJIT.enabled? && RubyVM::MJIT.const_defined?(:C) # not defined for miniruby
|
||||
end if Primitive.mjit_enabled_p
|
||||
|
@ -406,6 +406,7 @@ generator = BindingGenerator.new(
|
||||
rb_method_iseq_t
|
||||
rb_method_type_t
|
||||
rb_mjit_compile_info
|
||||
rb_mjit_runtime_counters
|
||||
rb_mjit_unit
|
||||
rb_serial_t
|
||||
rb_shape
|
||||
|
@ -20,11 +20,20 @@ RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
|
||||
|
||||
MJIT_SYMBOL_EXPORT_END
|
||||
|
||||
#ifndef MJIT_STATS
|
||||
# define MJIT_STATS RUBY_DEBUG
|
||||
#endif
|
||||
|
||||
#if VM_COLLECT_USAGE_DETAILS
|
||||
#define COLLECT_USAGE_INSN(insn) vm_collect_usage_insn(insn)
|
||||
#define COLLECT_USAGE_OPERAND(insn, n, op) vm_collect_usage_operand((insn), (n), ((VALUE)(op)))
|
||||
|
||||
#define COLLECT_USAGE_REGISTER(reg, s) vm_collect_usage_register((reg), (s))
|
||||
#elif MJIT_STATS
|
||||
// for --mjit-stats TODO: make it possible to support both MJIT_STATS and YJIT_STATS
|
||||
#define COLLECT_USAGE_INSN(insn) rb_mjit_collect_vm_usage_insn(insn)
|
||||
#define COLLECT_USAGE_OPERAND(insn, n, op) /* none */
|
||||
#define COLLECT_USAGE_REGISTER(reg, s) /* none */
|
||||
#elif YJIT_STATS
|
||||
/* for --yjit-stats */
|
||||
#define COLLECT_USAGE_INSN(insn) rb_yjit_collect_vm_usage_insn(insn)
|
||||
|
Loading…
x
Reference in New Issue
Block a user