YJIT: Count the number of actually written bytes (#7658)

This commit is contained in:
Takashi Kokubun 2023-04-05 07:32:04 -07:00 committed by GitHub
parent 3e1e09b2b7
commit 615a1bc470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-04-05 14:32:34 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
3 changed files with 32 additions and 14 deletions

View File

@ -294,8 +294,8 @@ module RubyVM::YJIT
$stderr.puts "get_ivar_max_depth: " + format_number(13, stats[:get_ivar_max_depth])
$stderr.puts "inline_code_size: " + format_number(13, stats[:inline_code_size])
$stderr.puts "outlined_code_size: " + format_number(13, stats[:outlined_code_size])
$stderr.puts "freed_code_size: " + format_number(13, stats[:freed_code_size])
$stderr.puts "code_region_size: " + format_number(13, stats[:code_region_size])
$stderr.puts "freed_code_size: " + format_number(13, stats[:freed_code_size])
$stderr.puts "yjit_alloc_size: " + format_number(13, stats[:yjit_alloc_size]) if stats.key?(:yjit_alloc_size)
$stderr.puts "live_context_size: " + format_number(13, stats[:live_context_size])
$stderr.puts "live_context_count: " + format_number(13, stats[:live_context_count])

View File

@ -62,6 +62,9 @@ pub struct CodeBlock {
// Current writing position
write_pos: usize,
// Total number of bytes written to past pages
past_page_bytes: usize,
// Size reserved for writing a jump to the next page
page_end_reserve: usize,
@ -119,6 +122,7 @@ impl CodeBlock {
mem_size,
page_size,
write_pos: 0,
past_page_bytes: 0,
page_end_reserve: JMP_PTR_BYTES,
label_addrs: Vec::new(),
label_names: Vec::new(),
@ -201,6 +205,9 @@ impl CodeBlock {
assert!(!cb.has_dropped_bytes());
});
// Update past_page_bytes for code_size()
self.past_page_bytes += self.current_page_bytes();
// Start the next code from dst_pos
self.write_pos = dst_pos;
}
@ -327,20 +334,14 @@ impl CodeBlock {
addrs
}
/// Return the code size that has been used by this CodeBlock.
/// Return the number of bytes written by this CodeBlock.
pub fn code_size(&self) -> usize {
let mut size = 0;
let current_page_idx = self.write_pos / self.page_size;
for page_idx in 0..self.num_mapped_pages() {
if page_idx == current_page_idx {
// Count only actually used bytes for the current page.
size += (self.write_pos % self.page_size).saturating_sub(self.page_start());
} else if !self.has_freed_page(page_idx) {
// Count an entire range for any non-freed pages that have been used.
size += self.page_end() - self.page_start() + self.page_end_reserve;
self.current_page_bytes() + self.past_page_bytes
}
}
size
/// Return the number of bytes written to the current page.
fn current_page_bytes(&self) -> usize {
(self.write_pos % self.page_size).saturating_sub(self.page_start())
}
/// Check if this code block has sufficient remaining capacity
@ -636,6 +637,7 @@ impl CodeBlock {
if let Some(&first_page) = freed_pages.first() {
for cb in [&mut *self, ocb.unwrap()] {
cb.write_pos = cb.get_page_pos(first_page);
cb.past_page_bytes = 0;
cb.dropped_bytes = false;
cb.clear_comments();
}
@ -796,4 +798,18 @@ mod tests
assert_eq!(uimm_num_bits((u32::MAX as u64) + 1), 64);
assert_eq!(uimm_num_bits(u64::MAX), 64);
}
#[test]
fn test_code_size() {
let mut cb = CodeBlock::new_dummy(CodeBlock::PREFERRED_CODE_PAGE_SIZE * 2);
cb.write_bytes(&[0, 0, 0, 0]);
assert_eq!(cb.code_size(), 4);
// Moving to the next page should not increase code_size
cb.next_page(cb.get_write_ptr(), |_, _| {});
assert_eq!(cb.code_size(), 4);
cb.write_bytes(&[0, 0, 0, 0]);
assert_eq!(cb.code_size(), 8);
}
}

View File

@ -480,6 +480,8 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {
#[cfg(feature="stats")]
hash_aset_usize!(hash, "yjit_alloc_size", global_allocation_size());
// `context` is true at RubyVM::YJIT._print_stats for --yjit-stats. It's false by default
// for RubyVM::YJIT.runtime_stats because counting all Contexts could be expensive.
if context {
let live_context_count = get_live_context_count();
let context_size = std::mem::size_of::<Context>();