Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
VALUE data2);
void rb_check_stack_overflow(void);

#if USE_YJIT
/* vm_exec.c */
extern uint64_t rb_vm_insns_count;
#endif

/* vm_insnhelper.c */
VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
VALUE rb_eql_opt(VALUE obj1, VALUE obj2);
Expand Down
5 changes: 5 additions & 0 deletions vm_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

#include <math.h>

#if USE_YJIT
// The number of instructions executed on vm_exec_core. --yjit-stats uses this.
uint64_t rb_vm_insns_count = 0;
#endif

#if VM_COLLECT_USAGE_DETAILS
static void vm_analysis_insn(int insn);
#endif
Expand Down
7 changes: 5 additions & 2 deletions vm_insnhelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
# define RJIT_STATS RUBY_DEBUG
#endif

#if YJIT_STATS
#define YJIT_COLLECT_USAGE_INSN(insn) rb_yjit_collect_vm_usage_insn(insn)
#if USE_YJIT // We want vm_insns_count on any YJIT-enabled build
// Increment vm_insns_count for --yjit-stats. We increment this even when
// --yjit or --yjit-stats is not used because branching to skip it is slower.
// We also don't use ATOMIC_INC for performance, allowing inaccuracy on Ractors.
#define YJIT_COLLECT_USAGE_INSN(insn) rb_vm_insns_count++
#else
#define YJIT_COLLECT_USAGE_INSN(insn) // none
#endif
Expand Down
2 changes: 0 additions & 2 deletions yjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ bool rb_yjit_compile_new_iseqs(void);
unsigned rb_yjit_call_threshold(void);
void rb_yjit_invalidate_all_method_lookup_assumptions(void);
void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme);
void rb_yjit_collect_vm_usage_insn(int insn);
void rb_yjit_collect_binding_alloc(void);
void rb_yjit_collect_binding_set(void);
bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec);
Expand All @@ -53,7 +52,6 @@ static inline bool rb_yjit_compile_new_iseqs(void) { return false; }
static inline unsigned rb_yjit_call_threshold(void) { return UINT_MAX; }
static inline void rb_yjit_invalidate_all_method_lookup_assumptions(void) {}
static inline void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
static inline void rb_yjit_collect_vm_usage_insn(int insn) {}
static inline void rb_yjit_collect_binding_alloc(void) {}
static inline void rb_yjit_collect_binding_set(void) {}
static inline bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec) { return false; }
Expand Down
23 changes: 8 additions & 15 deletions yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,11 @@ def self.runtime_stats(context: false)
# Average length of instruction sequences executed by YJIT
avg_len_in_yjit = total_exits > 0 ? retired_in_yjit.to_f / total_exits : 0

# 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
# 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

# Make those stats available in RubyVM::YJIT.runtime_stats as well
stats[:side_exit_count] = side_exits
Expand Down Expand Up @@ -318,14 +315,10 @@ def _print_stats(out: $stderr) # :nodoc:
out.puts "object_shape_count: " + format_number(13, stats[:object_shape_count])
out.puts "side_exit_count: " + format_number(13, stats[:side_exit_count])
out.puts "total_exit_count: " + format_number(13, stats[:total_exit_count])
out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count]) if stats.key?(:total_insns_count)
if stats.key?(:vm_insns_count)
out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count])
end
out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count])
out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count])
out.puts "yjit_insns_count: " + format_number(13, stats[:exec_instruction])
if stats.key?(:ratio_in_yjit)
out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%"
end
out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%"
out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit])

print_sorted_exit_counts(stats, out: out, prefix: "exit_")
Expand Down
3 changes: 3 additions & 0 deletions yjit/bindgen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ fn main() {
.allowlist_function("rb_ivar_defined")
.allowlist_function("rb_ivar_get")

// From internal/vm.h
.allowlist_var("rb_vm_insns_count")

// From include/ruby/internal/intern/vm.h
.allowlist_function("rb_get_alloc_func")

Expand Down
1 change: 1 addition & 0 deletions yjit/src/cruby_bindings.inc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,7 @@ extern "C" {
n: ::std::os::raw::c_long,
elts: *const VALUE,
) -> VALUE;
pub static mut rb_vm_insns_count: u64;
pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t;
pub fn rb_callable_method_entry(klass: VALUE, id: ID) -> *const rb_callable_method_entry_t;
pub fn rb_callable_method_entry_or_negative(
Expand Down
18 changes: 3 additions & 15 deletions yjit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,6 @@ make_counters! {
binding_allocations,
binding_set,

vm_insns_count,
compiled_iseq_entry,
compiled_iseq_count,
compiled_blockid_count,
Expand Down Expand Up @@ -507,7 +506,6 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {

let hash = unsafe { rb_hash_new() };

// CodeBlock stats
unsafe {
// Get the inline and outlined code blocks
let cb = CodegenGlobals::get_inline_cb();
Expand Down Expand Up @@ -547,6 +545,9 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {
hash_aset_usize!(hash, "live_context_count", live_context_count);
hash_aset_usize!(hash, "live_context_size", live_context_count * context_size);
}

// VM instructions count
hash_aset_usize!(hash, "vm_insns_count", rb_vm_insns_count as usize);
}

// If we're not generating stats, the hash is done
Expand All @@ -566,13 +567,6 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {
let counter_ptr = get_counter_ptr(counter_name);
let counter_val = *counter_ptr;

#[cfg(not(feature = "stats"))]
if counter_name == &"vm_insns_count" {
// If the stats feature is disabled, we don't have vm_insns_count
// so we are going to exclude the key
continue;
}

// Put counter into hash
let key = rust_str_to_sym(counter_name);
let value = VALUE::fixnum_from_usize(counter_val as usize);
Expand Down Expand Up @@ -750,12 +744,6 @@ pub extern "C" fn rb_yjit_reset_stats_bang(_ec: EcPtr, _ruby_self: VALUE) -> VAL
return Qnil;
}

/// Increment the number of instructions executed by the interpreter
#[no_mangle]
pub extern "C" fn rb_yjit_collect_vm_usage_insn() {
incr_counter!(vm_insns_count);
}

#[no_mangle]
pub extern "C" fn rb_yjit_collect_binding_alloc() {
incr_counter!(binding_allocations);
Expand Down