Skip to content

Commit 2915806

Browse files
committed
Add --zjit-num-profiles option (Shopify/zjit#98)
* Add --zjit-profile-interval option * Fix min to max * Avoid rewriting instructions for --zjit-call-threshold=1 * Rename the option to --zjit-num-profiles
1 parent 31106af commit 2915806

File tree

3 files changed

+42
-10
lines changed

3 files changed

+42
-10
lines changed

vm.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,15 +437,12 @@ jit_compile(rb_execution_context_t *ec)
437437
struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
438438

439439
#if USE_ZJIT
440-
// Number of calls used to profile a YARV instruction for ZJIT
441-
#define ZJIT_PROFILE_COUNT 1
442-
443440
if (body->jit_entry == NULL && rb_zjit_enabled_p) {
444441
body->jit_entry_calls++;
445442

446-
// At call-threshold - ZJIT_PROFILE_COUNT, rewrite some of the YARV
447-
// instructions to zjit_* instructions to profile these instructions.
448-
if (body->jit_entry_calls + ZJIT_PROFILE_COUNT == rb_zjit_call_threshold) {
443+
// At profile-threshold, rewrite some of the YARV instructions
444+
// to zjit_* instructions to profile these instructions.
445+
if (body->jit_entry_calls == rb_zjit_profile_threshold) {
449446
rb_zjit_profile_iseq(iseq);
450447
}
451448

zjit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#if USE_ZJIT
88
extern bool rb_zjit_enabled_p;
99
extern uint64_t rb_zjit_call_threshold;
10+
extern uint64_t rb_zjit_profile_threshold;
1011
void rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit_exception);
1112
void rb_zjit_profile_insn(enum ruby_vminsn_type insn, rb_execution_context_t *ec);
1213
void rb_zjit_profile_iseq(const rb_iseq_t *iseq);

zjit/src/options.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
use std::{ffi::CStr, os::raw::c_char};
22

3-
// This option is exposed to the C side in a global variable for performance, see vm.c
4-
// Number of method calls after which to start generating code
5-
// Threshold==1 means compile on first execution
3+
/// Number of calls to start profiling YARV instructions.
4+
/// They are profiled `rb_zjit_call_threshold - rb_zjit_profile_threshold` times,
5+
/// which is equal to --zjit-num-profiles.
6+
#[unsafe(no_mangle)]
7+
#[allow(non_upper_case_globals)]
8+
pub static mut rb_zjit_profile_threshold: u64 = 1;
9+
10+
/// Number of calls to compile ISEQ with ZJIT at jit_compile() in vm.c.
11+
/// --zjit-call-threshold=1 compiles on first execution without profiling information.
612
#[unsafe(no_mangle)]
713
#[allow(non_upper_case_globals)]
814
pub static mut rb_zjit_call_threshold: u64 = 2;
915

1016
#[derive(Clone, Copy, Debug)]
1117
pub struct Options {
18+
/// Number of times YARV instructions should be profiled.
19+
pub num_profiles: u64,
20+
1221
/// Enable debug logging
1322
pub debug: bool,
1423

@@ -57,6 +66,7 @@ pub extern "C" fn rb_zjit_init_options() -> *const u8 {
5766
/// Return an Options with default values
5867
pub fn init_options() -> Options {
5968
Options {
69+
num_profiles: 1,
6070
debug: false,
6171
dump_hir_init: None,
6272
dump_hir_opt: None,
@@ -91,7 +101,18 @@ fn parse_option(options: &mut Options, str_ptr: *const std::os::raw::c_char) ->
91101
("", "") => {}, // Simply --zjit
92102

93103
("call-threshold", _) => match opt_val.parse() {
94-
Ok(n) => unsafe { rb_zjit_call_threshold = n },
104+
Ok(n) => {
105+
unsafe { rb_zjit_call_threshold = n; }
106+
update_profile_threshold(options);
107+
},
108+
Err(_) => return None,
109+
},
110+
111+
("num-profiles", _) => match opt_val.parse() {
112+
Ok(n) => {
113+
options.num_profiles = n;
114+
update_profile_threshold(options);
115+
},
95116
Err(_) => return None,
96117
},
97118

@@ -115,6 +136,19 @@ fn parse_option(options: &mut Options, str_ptr: *const std::os::raw::c_char) ->
115136
Some(())
116137
}
117138

139+
/// Update rb_zjit_profile_threshold based on rb_zjit_call_threshold and options.num_profiles
140+
fn update_profile_threshold(options: &Options) {
141+
unsafe {
142+
if rb_zjit_call_threshold == 1 {
143+
// If --zjit-call-threshold=1, never rewrite ISEQs to profile instructions.
144+
rb_zjit_profile_threshold = 0;
145+
} else {
146+
// Otherwise, profile instructions at least once.
147+
rb_zjit_profile_threshold = rb_zjit_call_threshold.saturating_sub(options.num_profiles).max(1);
148+
}
149+
}
150+
}
151+
118152
/// Macro to print a message only when --zjit-debug is given
119153
macro_rules! debug {
120154
($($msg:tt)*) => {

0 commit comments

Comments
 (0)