diff options
| -rw-r--r-- | common.mk | 2 | ||||
| -rw-r--r-- | yjit/Cargo.toml | 1 | ||||
| -rw-r--r-- | yjit/src/stats.rs | 43 | ||||
| -rw-r--r-- | yjit/src/virtualmem.rs | 5 | ||||
| -rw-r--r-- | yjit/yjit.mk | 1 | ||||
| -rw-r--r-- | zjit/Cargo.toml | 1 | ||||
| -rw-r--r-- | zjit/src/options.rs | 10 | ||||
| -rw-r--r-- | zjit/src/state.rs | 2 | ||||
| -rw-r--r-- | zjit/src/stats.rs | 7 | ||||
| -rw-r--r-- | zjit/src/virtualmem.rs | 11 | ||||
| -rw-r--r-- | zjit/zjit.mk | 1 |
11 files changed, 40 insertions, 44 deletions
@@ -266,6 +266,7 @@ MAKE_LINK = $(MINIRUBY) -rfileutils -e "include FileUtils::Verbose" \ YJIT_RUSTC_ARGS = --crate-name=yjit \ --crate-type=staticlib \ --edition=2021 \ + --cfg 'feature="stats_allocator"' \ -g \ -C lto=thin \ -C opt-level=3 \ @@ -276,6 +277,7 @@ YJIT_RUSTC_ARGS = --crate-name=yjit \ ZJIT_RUSTC_ARGS = --crate-name=zjit \ --crate-type=staticlib \ --edition=2024 \ + --cfg 'feature="stats_allocator"' \ -g \ -C lto=thin \ -C opt-level=3 \ diff --git a/yjit/Cargo.toml b/yjit/Cargo.toml index af9c18c0dc..e2f1d84ffd 100644 --- a/yjit/Cargo.toml +++ b/yjit/Cargo.toml @@ -25,3 +25,4 @@ disasm = ["capstone"] # from cfg!(debug_assertions) so that we can see disasm of the code # that would run in the release mode. runtime_checks = [] +stats_allocator = [] diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index ea6130973d..09971c5b3a 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -1,9 +1,8 @@ //! Everything related to the collection of runtime stats in YJIT //! See the --yjit-stats command-line option -use std::alloc::{GlobalAlloc, Layout, System}; use std::ptr::addr_of_mut; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::Ordering; use std::time::Instant; use std::collections::HashMap; @@ -12,6 +11,10 @@ use crate::cruby::*; use crate::options::*; use crate::yjit::{yjit_enabled_p, YJIT_INIT_TIME}; +#[cfg(feature = "stats_allocator")] +#[path = "../../jit/src/lib.rs"] +mod jit; + /// Running total of how many ISeqs are in the system. #[no_mangle] pub static mut rb_yjit_live_iseq_count: u64 = 0; @@ -20,43 +23,9 @@ pub static mut rb_yjit_live_iseq_count: u64 = 0; #[no_mangle] pub static mut rb_yjit_iseq_alloc_count: u64 = 0; -/// A middleware to count Rust-allocated bytes as yjit_alloc_size. -#[global_allocator] -static GLOBAL_ALLOCATOR: StatsAlloc = StatsAlloc { alloc_size: AtomicUsize::new(0) }; - -pub struct StatsAlloc { - alloc_size: AtomicUsize, -} - -unsafe impl GlobalAlloc for StatsAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst); - System.alloc(layout) - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - self.alloc_size.fetch_sub(layout.size(), Ordering::SeqCst); - System.dealloc(ptr, layout) - } - - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - self.alloc_size.fetch_add(layout.size(), Ordering::SeqCst); - System.alloc_zeroed(layout) - } - - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if new_size > layout.size() { - self.alloc_size.fetch_add(new_size - layout.size(), Ordering::SeqCst); - } else if new_size < layout.size() { - self.alloc_size.fetch_sub(layout.size() - new_size, Ordering::SeqCst); - } - System.realloc(ptr, layout, new_size) - } -} - /// The number of bytes YJIT has allocated on the Rust heap. pub fn yjit_alloc_size() -> usize { - GLOBAL_ALLOCATOR.alloc_size.load(Ordering::SeqCst) + jit::GLOBAL_ALLOCATOR.alloc_size.load(Ordering::SeqCst) } /// Mapping of C function / ISEQ name to integer indices diff --git a/yjit/src/virtualmem.rs b/yjit/src/virtualmem.rs index aa6d21f210..97409c796c 100644 --- a/yjit/src/virtualmem.rs +++ b/yjit/src/virtualmem.rs @@ -7,6 +7,9 @@ use std::{cell::RefCell, ptr::NonNull}; use crate::{backend::ir::Target, stats::yjit_alloc_size, utils::IntoUsize}; +#[cfg(test)] +use crate::options::get_option; + #[cfg(not(test))] pub type VirtualMem = VirtualMemory<sys::SystemAllocator>; @@ -411,7 +414,7 @@ pub mod tests { PAGE_SIZE.try_into().unwrap(), NonNull::new(mem_start as *mut u8).unwrap(), mem_size, - 128 * 1024 * 1024, + get_option!(mem_size), ) } diff --git a/yjit/yjit.mk b/yjit/yjit.mk index 6b22a15960..cf68edb297 100644 --- a/yjit/yjit.mk +++ b/yjit/yjit.mk @@ -6,6 +6,7 @@ YJIT_SRC_FILES = $(wildcard \ $(top_srcdir)/yjit/src/*/*.rs \ $(top_srcdir)/yjit/src/*/*/*.rs \ $(top_srcdir)/yjit/src/*/*/*/*.rs \ + $(top_srcdir)/jit/src/lib.rs \ ) # Because of Cargo cache, if the actual binary is not changed from the diff --git a/zjit/Cargo.toml b/zjit/Cargo.toml index 617cd11916..c97c845a6e 100644 --- a/zjit/Cargo.toml +++ b/zjit/Cargo.toml @@ -20,3 +20,4 @@ insta = "1.43.1" # Support --yjit-dump-disasm and RubyVM::YJIT.disasm using libcapstone. disasm = ["capstone"] runtime_checks = [] +stats_allocator = [] diff --git a/zjit/src/options.rs b/zjit/src/options.rs index dbb6ee8ebb..2a9b2e7d27 100644 --- a/zjit/src/options.rs +++ b/zjit/src/options.rs @@ -35,6 +35,10 @@ pub struct Options { /// Note that the command line argument is expressed in MiB and not bytes. pub exec_mem_bytes: usize, + /// Hard limit of ZJIT's total memory usage. + /// Note that the command line argument is expressed in MiB and not bytes. + pub mem_bytes: usize, + /// Number of times YARV instructions should be profiled. pub num_profiles: u8, @@ -79,6 +83,7 @@ impl Default for Options { fn default() -> Self { Options { exec_mem_bytes: 64 * 1024 * 1024, + mem_bytes: 128 * 1024 * 1024, num_profiles: DEFAULT_NUM_PROFILES, stats: false, print_stats: false, @@ -100,9 +105,8 @@ impl Default for Options { /// Note that --help allows only 80 chars per line, including indentation, and it also puts the /// description in a separate line if the option name is too long. 80-char limit --> | (any character beyond this `|` column fails the test) pub const ZJIT_OPTIONS: &[(&str, &str)] = &[ - // TODO: Hide --zjit-exec-mem-size from ZJIT_OPTIONS once we add --zjit-mem-size (Shopify/ruby#686) - ("--zjit-exec-mem-size=num", - "Size of executable memory block in MiB (default: 64)."), + ("--zjit-mem-size=num", + "Max amount of memory that ZJIT can use (in MiB)."), ("--zjit-call-threshold=num", "Number of calls to trigger JIT (default: 2)."), ("--zjit-num-profiles=num", diff --git a/zjit/src/state.rs b/zjit/src/state.rs index 02bba3b7a3..da97829e43 100644 --- a/zjit/src/state.rs +++ b/zjit/src/state.rs @@ -85,7 +85,7 @@ impl ZJITState { page_size, NonNull::new(virt_block).unwrap(), exec_mem_bytes, - exec_mem_bytes, // TODO: change this to --zjit-mem-size (Shopify/ruby#686) + get_option!(mem_bytes) ); let mem_block = Rc::new(RefCell::new(mem_block)); diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index d1a6d584b9..98ddc20226 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -1,6 +1,11 @@ //! Counters and associated methods for events when ZJIT is run. use std::time::Instant; +use std::sync::atomic::Ordering; + +#[cfg(feature = "stats_allocator")] +#[path = "../../jit/src/lib.rs"] +mod jit; use crate::{cruby::*, hir::ParseError, options::get_option, state::{zjit_enabled_p, ZJITState}}; @@ -353,5 +358,5 @@ pub fn with_time_stat<F, R>(counter: Counter, func: F) -> R where F: FnOnce() -> /// The number of bytes ZJIT has allocated on the Rust heap. pub fn zjit_alloc_size() -> usize { - 0 // TODO: report the actual memory usage to support --zjit-mem-size (Shopify/ruby#686) + jit::GLOBAL_ALLOCATOR.alloc_size.load(Ordering::SeqCst) } diff --git a/zjit/src/virtualmem.rs b/zjit/src/virtualmem.rs index 42ce525fde..11de4e08af 100644 --- a/zjit/src/virtualmem.rs +++ b/zjit/src/virtualmem.rs @@ -7,6 +7,9 @@ use std::ptr::NonNull; use crate::stats::zjit_alloc_size; +#[cfg(test)] +use crate::options::get_option; + #[cfg(not(test))] pub type VirtualMem = VirtualMemory<sys::SystemAllocator>; @@ -369,6 +372,12 @@ pub mod tests { // Fictional architecture where each page is 4 bytes long const PAGE_SIZE: usize = 4; fn new_dummy_virt_mem() -> VirtualMemory<TestingAllocator> { + unsafe { + if crate::options::OPTIONS.is_none() { + crate::options::OPTIONS = Some(crate::options::Options::default()); + } + } + let mem_size = PAGE_SIZE * 10; let alloc = TestingAllocator::new(mem_size); let mem_start: *const u8 = alloc.mem_start(); @@ -378,7 +387,7 @@ pub mod tests { PAGE_SIZE.try_into().unwrap(), NonNull::new(mem_start as *mut u8).unwrap(), mem_size, - 128 * 1024 * 1024, + get_option!(mem_bytes), ) } diff --git a/zjit/zjit.mk b/zjit/zjit.mk index be989bdecd..f0bf1b0da5 100644 --- a/zjit/zjit.mk +++ b/zjit/zjit.mk @@ -9,6 +9,7 @@ ZJIT_SRC_FILES = $(wildcard \ $(top_srcdir)/zjit/src/*/*.rs \ $(top_srcdir)/zjit/src/*/*/*.rs \ $(top_srcdir)/zjit/src/*/*/*/*.rs \ + $(top_srcdir)/jit/src/lib.rs \ ) $(RUST_LIB): $(ZJIT_SRC_FILES) |
