summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-07-13 15:14:43 -0700
committerGitHub <[email protected]>2023-07-13 18:14:43 -0400
commitd814722fb8299c4baace3e76447a55a3d5478e3a (patch)
tree9a2c1ad1a2eec7f7df26ca4deef4a52cddb3750f
parente850181acf0e68a162c75d47b7a0951ab7d878b1 (diff)
YJIT: Make ratio_in_yjit always available (#8064)
Notes
Notes: Merged-By: maximecb <[email protected]>
-rw-r--r--internal/vm.h5
-rw-r--r--vm_exec.c5
-rw-r--r--vm_insnhelper.h7
-rw-r--r--yjit.h2
-rw-r--r--yjit.rb23
-rw-r--r--yjit/bindgen/src/main.rs3
-rw-r--r--yjit/src/cruby_bindings.inc.rs1
-rw-r--r--yjit/src/stats.rs18
8 files changed, 30 insertions, 34 deletions
diff --git a/internal/vm.h b/internal/vm.h
index 7943027946..a89af3d9a9 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -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);
diff --git a/vm_exec.c b/vm_exec.c
index cc4df7351c..1a4e0ad514 100644
--- a/vm_exec.c
+++ b/vm_exec.c
@@ -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
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 0e5f12c3b2..66895cd142 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -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
diff --git a/yjit.h b/yjit.h
index a640d5982a..a76dc6a850 100644
--- a/yjit.h
+++ b/yjit.h
@@ -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);
@@ -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; }
diff --git a/yjit.rb b/yjit.rb
index dc4699c7e6..06a3fd5e14 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -167,14 +167,11 @@ module RubyVM::YJIT
# 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
@@ -318,14 +315,10 @@ module RubyVM::YJIT
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_")
diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs
index b9bef8e176..30b4c8b5d7 100644
--- a/yjit/bindgen/src/main.rs
+++ b/yjit/bindgen/src/main.rs
@@ -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")
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index 3a901b105b..c27fa1f29d 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -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(
diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs
index 7f1a4e3d9f..216c7bddc8 100644
--- a/yjit/src/stats.rs
+++ b/yjit/src/stats.rs
@@ -369,7 +369,6 @@ make_counters! {
binding_allocations,
binding_set,
- vm_insns_count,
compiled_iseq_entry,
compiled_iseq_count,
compiled_blockid_count,
@@ -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();
@@ -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
@@ -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);
@@ -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);