From 0dc3bba6f2b2b1b23e1ec9dd2ec29f932c292db0 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 24 Aug 2021 12:32:07 +0200 Subject: [PATCH] Allow to compile with --yjit-stats support but not the full RUBY_DEBUG RUBY_DEBUG have a very significant performance overhead. Enough that YJIT with RUBY_DEBUG is noticeably slower than the interpreter without RUBY_DEBUG. This makes it hard to collect yjit-stats in production environments. By allowing to collect JIT statistics without the RUBy_DEBUG overhead, I hope to make such use cases smoother. --- yjit_codegen.c | 67 ++++++++++++++++++++++++++++++-------------------- yjit_core.c | 2 +- yjit_iface.c | 27 ++++++++++++-------- yjit_iface.h | 28 +++++++++++++-------- 4 files changed, 76 insertions(+), 48 deletions(-) diff --git a/yjit_codegen.c b/yjit_codegen.c index 3f9169a74b..a5f39d273b 100644 --- a/yjit_codegen.c +++ b/yjit_codegen.c @@ -159,30 +159,7 @@ jit_save_sp(jitstate_t* jit, ctx_t* ctx) static bool jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_t insn_opnd, VALUE sample_instance, const int max_chain_depth, uint8_t *side_exit); #if RUBY_DEBUG - -// Increment a profiling counter with counter_name -#define GEN_COUNTER_INC(cb, counter_name) _gen_counter_inc(cb, &(yjit_runtime_counters . counter_name)) -static void -_gen_counter_inc(codeblock_t *cb, int64_t *counter) -{ - if (!rb_yjit_opts.gen_stats) return; - mov(cb, REG0, const_ptr_opnd(counter)); - cb_write_lock_prefix(cb); // for ractors. - add(cb, mem_opnd(64, REG0, 0), imm_opnd(1)); -} - -// Increment a counter then take an existing side exit. -#define COUNTED_EXIT(side_exit, counter_name) _counted_side_exit(side_exit, &(yjit_runtime_counters . counter_name)) -static uint8_t * -_counted_side_exit(uint8_t *existing_side_exit, int64_t *counter) -{ - if (!rb_yjit_opts.gen_stats) return existing_side_exit; - - uint8_t *start = cb_get_ptr(ocb, ocb->write_pos); - _gen_counter_inc(ocb, counter); - jmp_ptr(ocb, existing_side_exit); - return start; -} +# define YJIT_STATS 1 // Add a comment at the current position in the code block static void @@ -268,14 +245,50 @@ verify_ctx(jitstate_t *jit, ctx_t *ctx) } #else +#ifndef YJIT_STATS +#define YJIT_STATS 0 +#endif // ifndef YJIT_STATS -#define GEN_COUNTER_INC(cb, counter_name) ((void)0) -#define COUNTED_EXIT(side_exit, counter_name) side_exit #define ADD_COMMENT(cb, comment) ((void)0) #define verify_ctx(jit, ctx) ((void)0) #endif // if RUBY_DEBUG +#if YJIT_STATS + +// Increment a profiling counter with counter_name +#define GEN_COUNTER_INC(cb, counter_name) _gen_counter_inc(cb, &(yjit_runtime_counters . counter_name)) +static void +_gen_counter_inc(codeblock_t *cb, int64_t *counter) +{ + if (!rb_yjit_opts.gen_stats) return; + mov(cb, REG0, const_ptr_opnd(counter)); + cb_write_lock_prefix(cb); // for ractors. + add(cb, mem_opnd(64, REG0, 0), imm_opnd(1)); +} + +// Increment a counter then take an existing side exit. +#define COUNTED_EXIT(side_exit, counter_name) _counted_side_exit(side_exit, &(yjit_runtime_counters . counter_name)) +static uint8_t * +_counted_side_exit(uint8_t *existing_side_exit, int64_t *counter) +{ + if (!rb_yjit_opts.gen_stats) return existing_side_exit; + + uint8_t *start = cb_get_ptr(ocb, ocb->write_pos); + _gen_counter_inc(ocb, counter); + jmp_ptr(ocb, existing_side_exit); + return start; +} + + +#else + +#define GEN_COUNTER_INC(cb, counter_name) ((void)0) +#define COUNTED_EXIT(side_exit, counter_name) side_exit + +#endif // if YJIT_STATS + + // Generate an exit to return to the interpreter static uint8_t * yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb) @@ -302,7 +315,7 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb) mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), RAX); // Accumulate stats about interpreter exits -#if RUBY_DEBUG +#if YJIT_STATS if (rb_yjit_opts.gen_stats) { mov(cb, RDI, const_ptr_opnd(exit_pc)); call_ptr(cb, RSI, (void *)&rb_yjit_count_side_exit_op); diff --git a/yjit_core.c b/yjit_core.c index 519da41230..ee3914acc6 100644 --- a/yjit_core.c +++ b/yjit_core.c @@ -522,7 +522,7 @@ add_block_version(blockid_t blockid, block_t* block) rb_bug("allocation failed"); } -#if RUBY_DEBUG +#if YJIT_STATS // First block compiled for this iseq yjit_runtime_counters.compiled_iseq_count++; #endif diff --git a/yjit_iface.c b/yjit_iface.c index 90b4ed9555..8ad6005bb9 100644 --- a/yjit_iface.c +++ b/yjit_iface.c @@ -25,11 +25,18 @@ static VALUE mYjit; static VALUE cYjitBlock; #if RUBY_DEBUG +# define YJIT_STATS 1 +static VALUE cYjitCodeComment; +#else +# ifndef YJIT_STATS +# define YJIT_STATS 0 +# endif +#endif + +#if YJIT_STATS +extern const int rb_vm_max_insn_name_size; static int64_t exit_op_count[VM_INSTRUCTION_SIZE] = { 0 }; struct rb_yjit_runtime_counters yjit_runtime_counters = { 0 }; -static VALUE cYjitCodeComment; - -extern const int rb_vm_max_insn_name_size; #endif // Machine code blocks (executable memory) @@ -721,7 +728,7 @@ get_yjit_stats(rb_execution_context_t *ec, VALUE self) rb_hash_aset(hash, key, value); } -#if RUBY_DEBUG +#if YJIT_STATS if (rb_yjit_opts.gen_stats) { // Indicate that the complete set of stats is available rb_hash_aset(hash, ID2SYM(rb_intern("all_stats")), Qtrue); @@ -783,16 +790,16 @@ get_yjit_stats(rb_execution_context_t *ec, VALUE self) static VALUE reset_stats_bang(rb_execution_context_t *ec, VALUE self) { -#if RUBY_DEBUG +#if YJIT_STATS memset(&exit_op_count, 0, sizeof(exit_op_count)); memset(&yjit_runtime_counters, 0, sizeof(yjit_runtime_counters)); -#endif // if RUBY_DEBUG +#endif // if YJIT_STATS return Qnil; } #include "yjit.rbinc" -#if RUBY_DEBUG +#if YJIT_STATS void rb_yjit_collect_vm_usage_insn(int insn) { @@ -1022,9 +1029,9 @@ rb_yjit_init(struct rb_yjit_options *options) rb_yjit_opts.gen_stats |= !!getenv("YJIT_STATS"); -#if !RUBY_DEBUG +#if !YJIT_STATS if(rb_yjit_opts.gen_stats) { - rb_warning("--yjit-stats requires that Ruby is compiled with CPPFLAGS='-DRUBY_DEBUG=1'"); + rb_warning("--yjit-stats requires that Ruby is compiled with CPPFLAGS='-DYJIT_STATS=1' or CPPFLAGS='-DRUBY_DEBUG=1'"); } #endif @@ -1070,7 +1077,7 @@ rb_yjit_init(struct rb_yjit_options *options) #endif #endif - if (RUBY_DEBUG && rb_yjit_opts.gen_stats) { + if (YJIT_STATS && rb_yjit_opts.gen_stats) { // Setup at_exit callback for printing out counters rb_block_call(rb_mKernel, rb_intern("at_exit"), 0, NULL, at_exit_print_stats, Qfalse); } diff --git a/yjit_iface.h b/yjit_iface.h index 4b3da00b76..6f7aa69cea 100644 --- a/yjit_iface.h +++ b/yjit_iface.h @@ -16,6 +16,23 @@ #endif #if RUBY_DEBUG +# define YJIT_STATS 1 +struct yjit_comment { + uint32_t offset; + const char *comment; +}; + +typedef rb_darray(struct yjit_comment) yjit_comment_array_t; + +extern yjit_comment_array_t yjit_code_comments; +#else +# ifndef YJIT_STATS +# define YJIT_STATS 0 +# endif // ifndef YJIT_STATS +#endif // if RUBY_DEBUG + + +#if YJIT_STATS #define YJIT_DECLARE_COUNTERS(...) struct rb_yjit_runtime_counters { \ int64_t __VA_ARGS__; \ @@ -81,16 +98,7 @@ YJIT_DECLARE_COUNTERS( #undef YJIT_DECLARE_COUNTERS -struct yjit_comment { - uint32_t offset; - const char *comment; -}; - -typedef rb_darray(struct yjit_comment) yjit_comment_array_t; - -extern yjit_comment_array_t yjit_code_comments; - -#endif // if RUBY_DEBUG +#endif // YJIT_STATS RUBY_EXTERN struct rb_yjit_options rb_yjit_opts; RUBY_EXTERN struct rb_yjit_runtime_counters yjit_runtime_counters;