Skip to content

Commit 9fb34f4

Browse files
authored
ZJIT: Add --zjit-exec-mem-size (ruby#14175)
* ZJIT: Add --zjit-exec-mem-size * Add a comment about the limit
1 parent e29d333 commit 9fb34f4

3 files changed

Lines changed: 38 additions & 12 deletions

File tree

zjit/src/options.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ pub static mut OPTIONS: Option<Options> = None;
2222

2323
#[derive(Clone, Debug)]
2424
pub struct Options {
25+
/// Hard limit of the executable memory block to allocate in bytes.
26+
/// Note that the command line argument is expressed in MiB and not bytes.
27+
pub exec_mem_bytes: usize,
28+
2529
/// Number of times YARV instructions should be profiled.
2630
pub num_profiles: u8,
2731

@@ -58,6 +62,7 @@ pub struct Options {
5862
impl Default for Options {
5963
fn default() -> Self {
6064
Options {
65+
exec_mem_bytes: 64 * 1024 * 1024,
6166
num_profiles: 1,
6267
stats: false,
6368
debug: false,
@@ -74,12 +79,18 @@ impl Default for Options {
7479
}
7580

7681
/// `ruby --help` descriptions for user-facing options. Do not add options for ZJIT developers.
77-
/// Note that --help allows only 80 chars per line, including indentation. 80-char limit --> |
82+
/// Note that --help allows only 80 chars per line, including indentation, and it also puts the
83+
/// description in a separate line if the option name is too long. 80-char limit --> | (any character beyond this `|` column fails the test)
7884
pub const ZJIT_OPTIONS: &'static [(&str, &str)] = &[
79-
("--zjit-call-threshold=num", "Number of calls to trigger JIT (default: 2)."),
80-
("--zjit-num-profiles=num", "Number of profiled calls before JIT (default: 1, max: 255)."),
81-
("--zjit-stats", "Enable collecting ZJIT statistics."),
82-
("--zjit-perf", "Dump ISEQ symbols into /tmp/perf-{}.map for Linux perf."),
85+
// TODO: Hide --zjit-exec-mem-size from ZJIT_OPTIONS once we add --zjit-mem-size (Shopify/ruby#686)
86+
("--zjit-exec-mem-size=num",
87+
"Size of executable memory block in MiB (default: 64)."),
88+
("--zjit-call-threshold=num",
89+
"Number of calls to trigger JIT (default: 2)."),
90+
("--zjit-num-profiles=num",
91+
"Number of profiled calls before JIT (default: 1, max: 255)."),
92+
("--zjit-stats", "Enable collecting ZJIT statistics."),
93+
("--zjit-perf", "Dump ISEQ symbols into /tmp/perf-{}.map for Linux perf."),
8394
("--zjit-log-compiled-iseqs=path",
8495
"Log compiled ISEQs to the file. The file will be truncated."),
8596
];
@@ -163,6 +174,20 @@ fn parse_option(str_ptr: *const std::os::raw::c_char) -> Option<()> {
163174
match (opt_name, opt_val) {
164175
("", "") => {}, // Simply --zjit
165176

177+
("mem-size", _) => match opt_val.parse::<usize>() {
178+
Ok(n) => {
179+
// Reject 0 or too large values that could overflow.
180+
// The upper bound is 1 TiB but we could make it smaller.
181+
if n == 0 || n > 1024 * 1024 {
182+
return None
183+
}
184+
185+
// Convert from MiB to bytes internally for convenience
186+
options.exec_mem_bytes = n * 1024 * 1024;
187+
}
188+
Err(_) => return None,
189+
},
190+
166191
("call-threshold", _) => match opt_val.parse() {
167192
Ok(n) => {
168193
unsafe { rb_zjit_call_threshold = n; }

zjit/src/state.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl ZJITState {
4848
use crate::cruby::*;
4949
use crate::options::*;
5050

51-
let exec_mem_size: usize = 64 * 1024 * 1024; // TODO: implement the option
51+
let exec_mem_bytes: usize = get_option!(exec_mem_bytes);
5252
let virt_block: *mut u8 = unsafe { rb_zjit_reserve_addr_space(64 * 1024 * 1024) };
5353

5454
// Memory protection syscalls need page-aligned addresses, so check it here. Assuming
@@ -73,8 +73,8 @@ impl ZJITState {
7373
crate::virtualmem::sys::SystemAllocator {},
7474
page_size,
7575
NonNull::new(virt_block).unwrap(),
76-
exec_mem_size,
77-
64 * 1024 * 1024, // TODO: support the option
76+
exec_mem_bytes,
77+
exec_mem_bytes, // TODO: change this to --zjit-mem-size (Shopify/ruby#686)
7878
);
7979
let mem_block = Rc::new(RefCell::new(mem_block));
8080

zjit/src/stats.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ fn incr_counter(counter: Counter, amount: u64) {
7070
unsafe { *ptr += amount; }
7171
}
7272

73-
pub fn zjit_alloc_size() -> usize {
74-
0 // TODO: report the actual memory usage
75-
}
76-
7773
/// Return a Hash object that contains ZJIT statistics
7874
#[unsafe(no_mangle)]
7975
pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE) -> VALUE {
@@ -113,3 +109,8 @@ pub fn with_time_stat<F, R>(counter: Counter, func: F) -> R where F: FnOnce() ->
113109
incr_counter(counter, nanos as u64);
114110
ret
115111
}
112+
113+
/// The number of bytes ZJIT has allocated on the Rust heap.
114+
pub fn zjit_alloc_size() -> usize {
115+
0 // TODO: report the actual memory usage to support --zjit-mem-size (Shopify/ruby#686)
116+
}

0 commit comments

Comments
 (0)