Only count VM instructions in YJIT stats builds
The instruction counter is slowing multi-Ractor applications. I had changed it to use a thread local, but using a thread local is slowing single threaded applications. This commit only enables the instruction counter in YJIT stats builds until we can figure out a way to gather the information with lower overhead. Co-authored-by: Randy Stauner <randy.stauner@shopify.com>
This commit is contained in:
parent
c1ce3d719d
commit
8cafa5b8ce
Notes:
git
2025-02-14 19:39:53 +00:00
@ -81,7 +81,7 @@ struct vm_ifunc *rb_current_ifunc(void);
|
|||||||
|
|
||||||
#if USE_YJIT
|
#if USE_YJIT
|
||||||
/* vm_exec.c */
|
/* vm_exec.c */
|
||||||
extern RB_THREAD_LOCAL_SPECIFIER uint64_t rb_vm_insns_count;
|
extern uint64_t rb_vm_insns_count;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern bool rb_free_at_exit;
|
extern bool rb_free_at_exit;
|
||||||
|
@ -1637,7 +1637,7 @@ class TestYJIT < Test::Unit::TestCase
|
|||||||
|
|
||||||
[
|
[
|
||||||
stats[:object_shape_count].is_a?(Integer),
|
stats[:object_shape_count].is_a?(Integer),
|
||||||
stats[:ratio_in_yjit].is_a?(Float),
|
stats[:ratio_in_yjit].nil? || stats[:ratio_in_yjit].is_a?(Float),
|
||||||
].all?
|
].all?
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
@ -1648,7 +1648,7 @@ class TestYJIT < Test::Unit::TestCase
|
|||||||
3.times { test }
|
3.times { test }
|
||||||
|
|
||||||
# Collect single stat.
|
# Collect single stat.
|
||||||
stat = RubyVM::YJIT.runtime_stats(:ratio_in_yjit)
|
stat = RubyVM::YJIT.runtime_stats(:yjit_alloc_size)
|
||||||
|
|
||||||
# Ensure this invocation had stats.
|
# Ensure this invocation had stats.
|
||||||
return true unless RubyVM::YJIT.runtime_stats[:all_stats]
|
return true unless RubyVM::YJIT.runtime_stats[:all_stats]
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#if USE_YJIT
|
#if USE_YJIT
|
||||||
// The number of instructions executed on vm_exec_core. --yjit-stats uses this.
|
// The number of instructions executed on vm_exec_core. --yjit-stats uses this.
|
||||||
RB_THREAD_LOCAL_SPECIFIER uint64_t rb_vm_insns_count = 0;
|
uint64_t rb_vm_insns_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_COLLECT_USAGE_DETAILS
|
#if VM_COLLECT_USAGE_DETAILS
|
||||||
|
@ -16,7 +16,7 @@ RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_invalidations;
|
|||||||
RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_misses;
|
RUBY_EXTERN rb_serial_t ruby_vm_constant_cache_misses;
|
||||||
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
|
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
|
||||||
|
|
||||||
#if USE_YJIT // We want vm_insns_count on any JIT-enabled build.
|
#if USE_YJIT && YJIT_STATS // We want vm_insns_count only on stats builds.
|
||||||
// Increment vm_insns_count for --yjit-stats. We increment this even when
|
// 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.
|
// --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.
|
// We also don't use ATOMIC_INC for performance, allowing inaccuracy on Ractors.
|
||||||
|
6
yjit.c
6
yjit.c
@ -16,7 +16,6 @@
|
|||||||
#include "internal/fixnum.h"
|
#include "internal/fixnum.h"
|
||||||
#include "internal/numeric.h"
|
#include "internal/numeric.h"
|
||||||
#include "internal/gc.h"
|
#include "internal/gc.h"
|
||||||
#include "internal/vm.h"
|
|
||||||
#include "vm_core.h"
|
#include "vm_core.h"
|
||||||
#include "vm_callinfo.h"
|
#include "vm_callinfo.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
@ -96,11 +95,6 @@ rb_yjit_mark_executable(void *mem_block, uint32_t mem_size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
|
||||||
rb_yjit_vm_insns_count(void) {
|
|
||||||
return rb_vm_insns_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the specified memory block.
|
// Free the specified memory block.
|
||||||
bool
|
bool
|
||||||
rb_yjit_mark_unused(void *mem_block, uint32_t mem_size)
|
rb_yjit_mark_unused(void *mem_block, uint32_t mem_size)
|
||||||
|
6
yjit.rb
6
yjit.rb
@ -422,10 +422,10 @@ module RubyVM::YJIT
|
|||||||
out.puts "object_shape_count: " + format_number(13, stats[:object_shape_count])
|
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 "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_exit_count: " + format_number(13, stats[:total_exit_count])
|
||||||
out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count])
|
out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count]) if stats[:total_insns_count]
|
||||||
out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count])
|
out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count]) if stats[:vm_insns_count]
|
||||||
out.puts "yjit_insns_count: " + format_number(13, stats[:yjit_insns_count])
|
out.puts "yjit_insns_count: " + format_number(13, stats[:yjit_insns_count])
|
||||||
out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%"
|
out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%" if stats[:ratio_in_yjit]
|
||||||
out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit])
|
out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit])
|
||||||
|
|
||||||
print_sorted_exit_counts(stats, out: out, prefix: "exit_")
|
print_sorted_exit_counts(stats, out: out, prefix: "exit_")
|
||||||
|
@ -317,7 +317,6 @@ fn main() {
|
|||||||
.allowlist_function("rb_yjit_get_page_size")
|
.allowlist_function("rb_yjit_get_page_size")
|
||||||
.allowlist_function("rb_yjit_iseq_builtin_attrs")
|
.allowlist_function("rb_yjit_iseq_builtin_attrs")
|
||||||
.allowlist_function("rb_yjit_iseq_inspect")
|
.allowlist_function("rb_yjit_iseq_inspect")
|
||||||
.allowlist_function("rb_yjit_vm_insns_count")
|
|
||||||
.allowlist_function("rb_yjit_builtin_function")
|
.allowlist_function("rb_yjit_builtin_function")
|
||||||
.allowlist_function("rb_set_cfp_(pc|sp)")
|
.allowlist_function("rb_set_cfp_(pc|sp)")
|
||||||
.allowlist_function("rb_yjit_multi_ractor_p")
|
.allowlist_function("rb_yjit_multi_ractor_p")
|
||||||
@ -381,6 +380,9 @@ fn main() {
|
|||||||
.allowlist_function("rb_ivar_get")
|
.allowlist_function("rb_ivar_get")
|
||||||
.allowlist_function("rb_mod_name")
|
.allowlist_function("rb_mod_name")
|
||||||
|
|
||||||
|
// From internal/vm.h
|
||||||
|
.allowlist_var("rb_vm_insns_count")
|
||||||
|
|
||||||
// From include/ruby/internal/intern/vm.h
|
// From include/ruby/internal/intern/vm.h
|
||||||
.allowlist_function("rb_get_alloc_func")
|
.allowlist_function("rb_get_alloc_func")
|
||||||
|
|
||||||
|
@ -1060,6 +1060,7 @@ extern "C" {
|
|||||||
elts: *const VALUE,
|
elts: *const VALUE,
|
||||||
) -> VALUE;
|
) -> VALUE;
|
||||||
pub fn rb_vm_top_self() -> VALUE;
|
pub fn rb_vm_top_self() -> 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_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(klass: VALUE, id: ID) -> *const rb_callable_method_entry_t;
|
||||||
pub fn rb_callable_method_entry_or_negative(
|
pub fn rb_callable_method_entry_or_negative(
|
||||||
@ -1139,7 +1140,6 @@ extern "C" {
|
|||||||
pub fn rb_jit_cont_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void);
|
pub fn rb_jit_cont_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void);
|
||||||
pub fn rb_yjit_mark_writable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
|
pub fn rb_yjit_mark_writable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
|
||||||
pub fn rb_yjit_mark_executable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32);
|
pub fn rb_yjit_mark_executable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32);
|
||||||
pub fn rb_yjit_vm_insns_count() -> u64;
|
|
||||||
pub fn rb_yjit_mark_unused(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
|
pub fn rb_yjit_mark_unused(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
|
||||||
pub fn rb_yjit_array_len(a: VALUE) -> ::std::os::raw::c_long;
|
pub fn rb_yjit_array_len(a: VALUE) -> ::std::os::raw::c_long;
|
||||||
pub fn rb_yjit_icache_invalidate(
|
pub fn rb_yjit_icache_invalidate(
|
||||||
|
@ -789,7 +789,9 @@ fn rb_yjit_gen_stats_dict(key: VALUE) -> VALUE {
|
|||||||
set_stat_usize!(hash, "context_cache_bytes", crate::core::CTX_ENCODE_CACHE_BYTES + crate::core::CTX_DECODE_CACHE_BYTES);
|
set_stat_usize!(hash, "context_cache_bytes", crate::core::CTX_ENCODE_CACHE_BYTES + crate::core::CTX_DECODE_CACHE_BYTES);
|
||||||
|
|
||||||
// VM instructions count
|
// VM instructions count
|
||||||
set_stat_usize!(hash, "vm_insns_count", rb_yjit_vm_insns_count() as usize);
|
if rb_vm_insns_count > 0 {
|
||||||
|
set_stat_usize!(hash, "vm_insns_count", rb_vm_insns_count as usize);
|
||||||
|
}
|
||||||
|
|
||||||
set_stat_usize!(hash, "live_iseq_count", rb_yjit_live_iseq_count as usize);
|
set_stat_usize!(hash, "live_iseq_count", rb_yjit_live_iseq_count as usize);
|
||||||
set_stat_usize!(hash, "iseq_alloc_count", rb_yjit_iseq_alloc_count as usize);
|
set_stat_usize!(hash, "iseq_alloc_count", rb_yjit_iseq_alloc_count as usize);
|
||||||
@ -859,11 +861,13 @@ fn rb_yjit_gen_stats_dict(key: VALUE) -> VALUE {
|
|||||||
set_stat_double!(hash, "avg_len_in_yjit", avg_len_in_yjit);
|
set_stat_double!(hash, "avg_len_in_yjit", avg_len_in_yjit);
|
||||||
|
|
||||||
// Proportion of instructions that retire in YJIT
|
// Proportion of instructions that retire in YJIT
|
||||||
let total_insns_count = retired_in_yjit + rb_yjit_vm_insns_count();
|
if rb_vm_insns_count > 0 {
|
||||||
set_stat_usize!(hash, "total_insns_count", total_insns_count as usize);
|
let total_insns_count = retired_in_yjit + rb_vm_insns_count;
|
||||||
|
set_stat_usize!(hash, "total_insns_count", total_insns_count as usize);
|
||||||
|
|
||||||
let ratio_in_yjit: f64 = 100.0 * retired_in_yjit as f64 / total_insns_count as f64;
|
let ratio_in_yjit: f64 = 100.0 * retired_in_yjit as f64 / total_insns_count as f64;
|
||||||
set_stat_double!(hash, "ratio_in_yjit", ratio_in_yjit);
|
set_stat_double!(hash, "ratio_in_yjit", ratio_in_yjit);
|
||||||
|
}
|
||||||
|
|
||||||
// Set method call counts in a Ruby dict
|
// Set method call counts in a Ruby dict
|
||||||
fn set_call_counts(
|
fn set_call_counts(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user