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.
This commit is contained in:
Jean Boussier 2021-08-24 12:32:07 +02:00 коммит произвёл Alan Wu
Родитель 2ba090a1f9
Коммит 0dc3bba6f2
4 изменённых файлов: 76 добавлений и 48 удалений

Просмотреть файл

@ -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);

Просмотреть файл

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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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;