mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 16:44:01 +02:00
YJIT: add top C function call counts to --yjit-stats
(#9047)
* YJIT: gather call counts for individual cfuncs Co-authored by Takashi Kokubun
This commit is contained in:
parent
94015e0dce
commit
7f50c70574
3 changed files with 126 additions and 1 deletions
29
yjit.rb
29
yjit.rb
|
@ -369,6 +369,35 @@ module RubyVM::YJIT
|
||||||
out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit])
|
out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit])
|
||||||
|
|
||||||
print_sorted_exit_counts(stats, out: out, prefix: "exit_")
|
print_sorted_exit_counts(stats, out: out, prefix: "exit_")
|
||||||
|
|
||||||
|
print_sorted_cfunc_calls(stats, out:out)
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_sorted_cfunc_calls(stats, out:, how_many: 20, left_pad: 4) # :nodoc:
|
||||||
|
calls = stats[:cfunc_calls]
|
||||||
|
#puts calls
|
||||||
|
|
||||||
|
# Total number of cfunc calls
|
||||||
|
num_send_cfunc = stats[:num_send_cfunc]
|
||||||
|
|
||||||
|
# Sort calls by decreasing frequency and keep the top N
|
||||||
|
pairs = calls.map { |k,v| [k, v] }
|
||||||
|
pairs.sort_by! {|pair| pair[1] }
|
||||||
|
pairs.reverse!
|
||||||
|
pairs = pairs[0...how_many]
|
||||||
|
|
||||||
|
top_n_total = pairs.sum { |name, count| count }
|
||||||
|
top_n_pct = 100.0 * top_n_total / num_send_cfunc
|
||||||
|
longest_name_len = pairs.max_by { |name, count| name.length }.first.length
|
||||||
|
|
||||||
|
out.puts "Top-#{pairs.size} most frequent C calls (#{"%.1f" % top_n_pct}% of C calls):"
|
||||||
|
|
||||||
|
pairs.each do |name, count|
|
||||||
|
padding = longest_name_len + left_pad
|
||||||
|
padded_name = "%#{padding}s" % name
|
||||||
|
padded_count = format_number_pct(10, count, num_send_cfunc)
|
||||||
|
out.puts("#{padded_name}: #{padded_count}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def print_sorted_exit_counts(stats, out:, prefix:, how_many: 20, left_pad: 4) # :nodoc:
|
def print_sorted_exit_counts(stats, out:, prefix:, how_many: 20, left_pad: 4) # :nodoc:
|
||||||
|
|
|
@ -5398,6 +5398,7 @@ fn gen_send_cfunc(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Increment total cfunc send count
|
||||||
gen_counter_incr(asm, Counter::num_send_cfunc);
|
gen_counter_incr(asm, Counter::num_send_cfunc);
|
||||||
|
|
||||||
// Delegate to codegen for C methods if we have it.
|
// Delegate to codegen for C methods if we have it.
|
||||||
|
@ -5416,6 +5417,32 @@ fn gen_send_cfunc(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log the name of the method we're calling to,
|
||||||
|
// note that we intentionally don't do this for inlined cfuncs
|
||||||
|
if get_option!(gen_stats) {
|
||||||
|
// TODO: extract code to get method name string into its own function
|
||||||
|
|
||||||
|
// Assemble the method name string
|
||||||
|
let mid = unsafe { vm_ci_mid(ci) };
|
||||||
|
let class_name = if recv_known_klass != ptr::null() {
|
||||||
|
unsafe { cstr_to_rust_string(rb_class2name(*recv_known_klass)) }.unwrap()
|
||||||
|
} else {
|
||||||
|
"Unknown".to_string()
|
||||||
|
};
|
||||||
|
let method_name = if mid != 0 {
|
||||||
|
unsafe { cstr_to_rust_string(rb_id2name(mid)) }.unwrap()
|
||||||
|
} else {
|
||||||
|
"Unknown".to_string()
|
||||||
|
};
|
||||||
|
let name_str = format!("{}#{}", class_name, method_name);
|
||||||
|
|
||||||
|
// Get an index for this cfunc name
|
||||||
|
let cfunc_idx = get_cfunc_idx(&name_str);
|
||||||
|
|
||||||
|
// Increment the counter for this cfunc
|
||||||
|
asm.ccall(incr_cfunc_counter as *const u8, vec![cfunc_idx.into()]);
|
||||||
|
}
|
||||||
|
|
||||||
// Check for interrupts
|
// Check for interrupts
|
||||||
gen_check_ints(asm, Counter::guard_send_interrupted);
|
gen_check_ints(asm, Counter::guard_send_interrupted);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
use std::alloc::{GlobalAlloc, Layout, System};
|
use std::alloc::{GlobalAlloc, Layout, System};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::codegen::CodegenGlobals;
|
use crate::codegen::CodegenGlobals;
|
||||||
use crate::core::Context;
|
use crate::core::Context;
|
||||||
|
@ -52,6 +53,58 @@ unsafe impl GlobalAlloc for StatsAlloc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mapping of C function name to integer indices
|
||||||
|
/// This is accessed at compilation time only (protected by a lock)
|
||||||
|
static mut CFUNC_NAME_TO_IDX: Option<HashMap<String, usize>> = None;
|
||||||
|
|
||||||
|
/// Vector of call counts for each C function index
|
||||||
|
/// This is modified (but not resized) by JITted code
|
||||||
|
static mut CFUNC_CALL_COUNT: Option<Vec<u64>> = None;
|
||||||
|
|
||||||
|
/// Assign an index to a given cfunc name string
|
||||||
|
pub fn get_cfunc_idx(name: &str) -> usize
|
||||||
|
{
|
||||||
|
//println!("{}", name);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if CFUNC_NAME_TO_IDX.is_none() {
|
||||||
|
CFUNC_NAME_TO_IDX = Some(HashMap::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
if CFUNC_CALL_COUNT.is_none() {
|
||||||
|
CFUNC_CALL_COUNT = Some(Vec::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let name_to_idx = CFUNC_NAME_TO_IDX.as_mut().unwrap();
|
||||||
|
|
||||||
|
match name_to_idx.get(name) {
|
||||||
|
Some(idx) => *idx,
|
||||||
|
None => {
|
||||||
|
let idx = name_to_idx.len();
|
||||||
|
name_to_idx.insert(name.to_string(), idx);
|
||||||
|
|
||||||
|
// Resize the call count vector
|
||||||
|
let cfunc_call_count = CFUNC_CALL_COUNT.as_mut().unwrap();
|
||||||
|
if idx >= cfunc_call_count.len() {
|
||||||
|
cfunc_call_count.resize(idx + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment the counter for a C function
|
||||||
|
pub extern "C" fn incr_cfunc_counter(idx: usize)
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let cfunc_call_count = CFUNC_CALL_COUNT.as_mut().unwrap();
|
||||||
|
assert!(idx < cfunc_call_count.len());
|
||||||
|
cfunc_call_count[idx] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// YJIT exit counts for each instruction type
|
// YJIT exit counts for each instruction type
|
||||||
const VM_INSTRUCTION_SIZE_USIZE: usize = VM_INSTRUCTION_SIZE as usize;
|
const VM_INSTRUCTION_SIZE_USIZE: usize = VM_INSTRUCTION_SIZE as usize;
|
||||||
static mut EXIT_OP_COUNT: [u64; VM_INSTRUCTION_SIZE_USIZE] = [0; VM_INSTRUCTION_SIZE_USIZE];
|
static mut EXIT_OP_COUNT: [u64; VM_INSTRUCTION_SIZE_USIZE] = [0; VM_INSTRUCTION_SIZE_USIZE];
|
||||||
|
@ -663,7 +716,6 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the stats feature is enabled
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Indicate that the complete set of stats is available
|
// Indicate that the complete set of stats is available
|
||||||
rb_hash_aset(hash, rust_str_to_sym("all_stats"), Qtrue);
|
rb_hash_aset(hash, rust_str_to_sym("all_stats"), Qtrue);
|
||||||
|
@ -689,6 +741,23 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE {
|
||||||
let value = VALUE::fixnum_from_usize(EXIT_OP_COUNT[op_idx] as usize);
|
let value = VALUE::fixnum_from_usize(EXIT_OP_COUNT[op_idx] as usize);
|
||||||
rb_hash_aset(hash, key, value);
|
rb_hash_aset(hash, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a hash for the cfunc call counts
|
||||||
|
if let Some(cfunc_name_to_idx) = CFUNC_NAME_TO_IDX.as_mut() {
|
||||||
|
let call_counts = CFUNC_CALL_COUNT.as_mut().unwrap();
|
||||||
|
let calls_hash = rb_hash_new();
|
||||||
|
|
||||||
|
for (name, idx) in cfunc_name_to_idx {
|
||||||
|
let count = call_counts[*idx];
|
||||||
|
println!("{}: {}", name, count);
|
||||||
|
|
||||||
|
let key = rust_str_to_sym(name);
|
||||||
|
let value = VALUE::fixnum_from_usize(count as usize);
|
||||||
|
rb_hash_aset(calls_hash, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_hash_aset(hash, rust_str_to_sym("cfunc_calls"), calls_hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hash
|
hash
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue