Skip to content

Commit

Permalink
Merge pull request ruby#177 from Shopify/non-debug-yjit-stats
Browse files Browse the repository at this point in the history
Allow to compile with --yjit-stats support but not the full RUBY_DEBUG
casperisfine authored Aug 25, 2021

Verified

This commit was signed with the committer’s verified signature.
mislav Mislav Marohnić
2 parents 6b173b5 + 13bc521 commit 8153f44
Showing 5 changed files with 78 additions and 50 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -46,13 +46,13 @@ git clone https://github.com/Shopify/yjit
cd yjit
```

The YJIT `ruby` binary can be built with either GCC or Clang. We recommend enabling debug symbols so that assertions are enabled during development as this makes debugging easier. Enabling debug mode will also make it possible for you to disassemble code generated by YJIT, and get access to stat counters. More detailed build instructions are provided in the [Ruby README](https://github.com/ruby/ruby#how-to-compile-and-install).

The YJIT `ruby` binary can be built with either GCC or Clang. For development, we recommend enabling debug symbols so that assertions are enabled as this makes debugging easier. Enabling debug mode will also make it possible for you to disassemble code generated by YJIT. However, this causes a performance hit. For maximum performance, compile with GCC, without the `DRUBY_DEBUG` or `YJIT_STATS` build options. More detailed build instructions are provided in the [Ruby README](https://github.com/ruby/ruby#how-to-compile-and-install.
To support disassembly of the generated code, `libcapstone` is also required (`brew install capstone` on MacOS, `sudo apt-get install -y libcapstone-dev` on Ubuntu/Debian).

```
# Configure with debugging/stats options for development, build and install
./autogen.sh
./configure cppflags=-DRUBY_DEBUG --prefix=$HOME/.rubies/ruby-yjit
./configure cppflags="-DRUBY_DEBUG -DYJIT_STATS" --prefix=$HOME/.rubies/ruby-yjit
make -j16 install
```

67 changes: 40 additions & 27 deletions yjit_codegen.c
Original file line number Diff line number Diff line change
@@ -157,30 +157,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
@@ -266,14 +243,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)
@@ -300,7 +313,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);
2 changes: 1 addition & 1 deletion yjit_core.c
Original file line number Diff line number Diff line change
@@ -523,7 +523,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 changes: 16 additions & 9 deletions yjit_iface.c
Original file line number Diff line number Diff line change
@@ -25,11 +25,18 @@ static VALUE mYjit;
static VALUE cYjitBlock;

#if RUBY_DEBUG
static int64_t exit_op_count[VM_INSTRUCTION_SIZE] = { 0 };
struct rb_yjit_runtime_counters yjit_runtime_counters = { 0 };
# 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 };
#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 changes: 18 additions & 10 deletions yjit_iface.h
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 8153f44

Please sign in to comment.