Skip to content

Commit 8b72e07

Browse files
committed
Disable ZJIT profiling at call-threshold (Shopify/zjit#99)
* Disable ZJIT profiling at call-threshold * Stop referencing ZJIT instructions in codegen
1 parent 2915806 commit 8b72e07

File tree

7 files changed

+60
-20
lines changed

7 files changed

+60
-20
lines changed
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
MAYBE_UNUSED(static int vm_insn_to_zjit_insn(int insn));
2-
1+
MAYBE_UNUSED(static int vm_bare_insn_to_zjit_insn(int insn));
32
static int
4-
vm_insn_to_zjit_insn(int insn)
3+
vm_bare_insn_to_zjit_insn(int insn)
54
{
65
switch (insn) {
76
% RubyVM::ZJITInstructions.to_a.each do |insn|
@@ -12,3 +11,17 @@ vm_insn_to_zjit_insn(int insn)
1211
return insn;
1312
}
1413
}
14+
15+
MAYBE_UNUSED(static int vm_zjit_insn_to_bare_insn(int insn));
16+
static int
17+
vm_zjit_insn_to_bare_insn(int insn)
18+
{
19+
switch (insn) {
20+
% RubyVM::ZJITInstructions.to_a.each do |insn|
21+
case <%= insn.bin %>:
22+
return BIN(<%= insn.jump_destination %>);
23+
% end
24+
default:
25+
return insn;
26+
}
27+
}

vm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ jit_compile(rb_execution_context_t *ec)
443443
// At profile-threshold, rewrite some of the YARV instructions
444444
// to zjit_* instructions to profile these instructions.
445445
if (body->jit_entry_calls == rb_zjit_profile_threshold) {
446-
rb_zjit_profile_iseq(iseq);
446+
rb_zjit_profile_enable(iseq);
447447
}
448448

449449
// At call-threshold, compile the ISEQ with ZJIT.

zjit.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,17 @@ rb_RSTRING_PTR(VALUE str)
168168
return RSTRING_PTR(str);
169169
}
170170

171+
void rb_zjit_profile_disable(const rb_iseq_t *iseq);
172+
171173
void
172174
rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception)
173175
{
174176
RB_VM_LOCK_ENTER();
175177
rb_vm_barrier();
176178

179+
// Convert ZJIT instructions back to bare instructions
180+
rb_zjit_profile_disable(iseq);
181+
177182
// Compile a block version starting at the current instruction
178183
uint8_t *rb_zjit_iseq_gen_entry_point(const rb_iseq_t *iseq, rb_execution_context_t *ec); // defined in Rust
179184
uintptr_t code_ptr = (uintptr_t)rb_zjit_iseq_gen_entry_point(iseq, ec);
@@ -652,22 +657,40 @@ rb_RCLASS_ORIGIN(VALUE c)
652657

653658
// Convert a given ISEQ's instructions to zjit_* instructions
654659
void
655-
rb_zjit_profile_iseq(const rb_iseq_t *iseq)
660+
rb_zjit_profile_enable(const rb_iseq_t *iseq)
656661
{
657662
// This table encodes an opcode into the instruction's address
658663
const void *const *insn_table = rb_vm_get_insns_address_table();
659664

660665
unsigned int insn_idx = 0;
661666
while (insn_idx < iseq->body->iseq_size) {
662667
int insn = rb_vm_insn_decode(iseq->body->iseq_encoded[insn_idx]);
663-
int zjit_insn = vm_insn_to_zjit_insn(insn);
668+
int zjit_insn = vm_bare_insn_to_zjit_insn(insn);
664669
if (insn != zjit_insn) {
665670
iseq->body->iseq_encoded[insn_idx] = (VALUE)insn_table[zjit_insn];
666671
}
667672
insn_idx += insn_len(insn);
668673
}
669674
}
670675

676+
// Convert a given ISEQ's ZJIT instructions to bare instructions
677+
void
678+
rb_zjit_profile_disable(const rb_iseq_t *iseq)
679+
{
680+
// This table encodes an opcode into the instruction's address
681+
const void *const *insn_table = rb_vm_get_insns_address_table();
682+
683+
unsigned int insn_idx = 0;
684+
while (insn_idx < iseq->body->iseq_size) {
685+
int insn = rb_vm_insn_decode(iseq->body->iseq_encoded[insn_idx]);
686+
int bare_insn = vm_zjit_insn_to_bare_insn(insn);
687+
if (insn != bare_insn) {
688+
iseq->body->iseq_encoded[insn_idx] = (VALUE)insn_table[bare_insn];
689+
}
690+
insn_idx += insn_len(insn);
691+
}
692+
}
693+
671694
// Get profiling information for ISEQ
672695
void *
673696
rb_iseq_get_zjit_payload(const rb_iseq_t *iseq)

zjit.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ extern uint64_t rb_zjit_call_threshold;
1010
extern uint64_t rb_zjit_profile_threshold;
1111
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
1212
void rb_zjit_profile_insn(enum ruby_vminsn_type insn, rb_execution_context_t *ec);
13-
void rb_zjit_profile_iseq(const rb_iseq_t *iseq);
13+
void rb_zjit_profile_enable(const rb_iseq_t *iseq);
1414
void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
1515
void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq);
1616
#else
1717
static inline void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception) {}
1818
static inline void rb_zjit_profile_insn(enum ruby_vminsn_type insn, rb_execution_context_t *ec) {}
19-
static inline void rb_zjit_profile_iseq(const rb_iseq_t *iseq) {}
19+
static inline void rb_zjit_profile_enable(const rb_iseq_t *iseq) {}
2020
static inline void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
2121
static inline void rb_zjit_invalidate_ep_is_bp(const rb_iseq_t *iseq) {}
2222
#endif // #if USE_YJIT

zjit/bindgen/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ fn main() {
100100
.allowlist_function("ruby_executable_node")
101101
.allowlist_function("rb_funcallv")
102102
.allowlist_function("rb_protect")
103+
.allowlist_function("rb_zjit_profile_disable")
103104

104105
// For crashing
105106
.allowlist_function("rb_bug")

zjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,38 +1598,38 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
15981598
}
15991599
}
16001600

1601-
YARVINSN_opt_plus | YARVINSN_zjit_opt_plus => {
1601+
YARVINSN_opt_plus => {
16021602
push_fixnum_insn!(FixnumAdd, "+", BOP_PLUS, state);
16031603
}
1604-
YARVINSN_opt_minus | YARVINSN_zjit_opt_minus => {
1604+
YARVINSN_opt_minus => {
16051605
push_fixnum_insn!(FixnumSub, "-", BOP_MINUS, state);
16061606
}
1607-
YARVINSN_opt_mult | YARVINSN_zjit_opt_mult => {
1607+
YARVINSN_opt_mult => {
16081608
push_fixnum_insn!(FixnumMult, "*", BOP_MULT, state);
16091609
}
1610-
YARVINSN_opt_div | YARVINSN_zjit_opt_div => {
1610+
YARVINSN_opt_div => {
16111611
push_fixnum_insn!(FixnumDiv, "/", BOP_DIV, state);
16121612
}
1613-
YARVINSN_opt_mod | YARVINSN_zjit_opt_mod => {
1613+
YARVINSN_opt_mod => {
16141614
push_fixnum_insn!(FixnumMod, "%", BOP_MOD, state);
16151615
}
16161616

1617-
YARVINSN_opt_eq | YARVINSN_zjit_opt_eq => {
1617+
YARVINSN_opt_eq => {
16181618
push_fixnum_insn!(FixnumEq, "==", BOP_EQ);
16191619
}
1620-
YARVINSN_opt_neq | YARVINSN_zjit_opt_neq => {
1620+
YARVINSN_opt_neq => {
16211621
push_fixnum_insn!(FixnumNeq, "!=", BOP_NEQ);
16221622
}
1623-
YARVINSN_opt_lt | YARVINSN_zjit_opt_lt => {
1623+
YARVINSN_opt_lt => {
16241624
push_fixnum_insn!(FixnumLt, "<", BOP_LT);
16251625
}
1626-
YARVINSN_opt_le | YARVINSN_zjit_opt_le => {
1626+
YARVINSN_opt_le => {
16271627
push_fixnum_insn!(FixnumLe, "<=", BOP_LE);
16281628
}
1629-
YARVINSN_opt_gt | YARVINSN_zjit_opt_gt => {
1629+
YARVINSN_opt_gt => {
16301630
push_fixnum_insn!(FixnumGt, ">", BOP_GT);
16311631
}
1632-
YARVINSN_opt_ge | YARVINSN_zjit_opt_ge => {
1632+
YARVINSN_opt_ge => {
16331633
push_fixnum_insn!(FixnumGe, ">==", BOP_GE);
16341634
}
16351635
YARVINSN_opt_ltlt => {
@@ -1654,7 +1654,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
16541654
break; // Don't enqueue the next block as a successor
16551655
}
16561656

1657-
YARVINSN_opt_send_without_block | YARVINSN_zjit_opt_send_without_block => {
1657+
YARVINSN_opt_send_without_block => {
16581658
let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
16591659
let call_info = unsafe { rb_get_call_data_ci(cd) };
16601660
let argc = unsafe { vm_ci_argc((*cd).ci) };
@@ -1991,6 +1991,7 @@ mod tests {
19911991
#[track_caller]
19921992
fn assert_method_hir(method: &str, hir: Expect) {
19931993
let iseq = crate::cruby::with_rubyvm(|| get_method_iseq(method));
1994+
unsafe { crate::cruby::rb_zjit_profile_disable(iseq) };
19941995
let function = iseq_to_hir(iseq).unwrap();
19951996
assert_function_hir(function, hir);
19961997
}
@@ -2531,6 +2532,7 @@ mod opt_tests {
25312532
#[track_caller]
25322533
fn assert_optimized_method_hir(method: &str, hir: Expect) {
25332534
let iseq = crate::cruby::with_rubyvm(|| get_method_iseq(method));
2535+
unsafe { crate::cruby::rb_zjit_profile_disable(iseq) };
25342536
let mut function = iseq_to_hir(iseq).unwrap();
25352537
function.optimize();
25362538
assert_function_hir(function, hir);

0 commit comments

Comments
 (0)