зеркало из https://github.com/github/ruby.git
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:
Родитель
2ba090a1f9
Коммит
0dc3bba6f2
|
@ -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
|
||||
|
|
27
yjit_iface.c
27
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);
|
||||
}
|
||||
|
|
28
yjit_iface.h
28
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче