ZJIT: Count all calls to C functions from generated code (#15240)

lobsters:

```
Top-20 calls to C functions from JIT code (79.9% of total 97,004,883):
                             rb_vm_opt_send_without_block: 19,874,212 (20.5%)
                                rb_vm_setinstancevariable:  9,774,841 (10.1%)
                                              rb_ivar_get:  9,358,866 ( 9.6%)
                                             rb_hash_aref:  6,828,948 ( 7.0%)
                                               rb_vm_send:  6,441,551 ( 6.6%)
                                          rb_vm_env_write:  5,375,989 ( 5.5%)
                                        rb_vm_invokesuper:  3,037,836 ( 3.1%)
                                               Module#===:  2,562,446 ( 2.6%)
                                             rb_ary_entry:  2,354,546 ( 2.4%)
                                             Kernel#is_a?:  1,424,092 ( 1.5%)
                               rb_vm_opt_getconstant_path:  1,344,923 ( 1.4%)
                                           Thread.current:  1,300,822 ( 1.3%)
                                     rb_zjit_defined_ivar:  1,222,613 ( 1.3%)
                                        rb_vm_invokeblock:  1,184,555 ( 1.2%)
                                                 Hash#[]=:  1,061,969 ( 1.1%)
                                              rb_ary_push:  1,024,987 ( 1.1%)
                                          rb_ary_new_capa:    904,003 ( 0.9%)
                                        rb_str_buf_append:    833,782 ( 0.9%)
                               rb_class_allocate_instance:    822,626 ( 0.8%)
                                               Hash#fetch:    755,913 ( 0.8%)
```

railsbench:

```
Top-20 calls to C functions from JIT code (74.8% of total 189,170,268):
               rb_vm_opt_send_without_block: 29,870,307 (15.8%)
                  rb_vm_setinstancevariable: 17,631,199 ( 9.3%)
                               rb_hash_aref: 16,928,890 ( 8.9%)
                                rb_ivar_get: 14,441,240 ( 7.6%)
                            rb_vm_env_write: 11,571,001 ( 6.1%)
                                 rb_vm_send: 11,153,457 ( 5.9%)
                          rb_vm_invokesuper:  7,568,267 ( 4.0%)
                                 Module#===:  6,065,923 ( 3.2%)
                                   Hash#[]=:  2,842,990 ( 1.5%)
                               rb_ary_entry:  2,766,125 ( 1.5%)
                                rb_ary_push:  2,722,079 ( 1.4%)
                          rb_vm_invokeblock:  2,594,398 ( 1.4%)
                             Thread.current:  2,560,129 ( 1.4%)
                             rb_str_getbyte:  1,965,627 ( 1.0%)
                               Kernel#is_a?:  1,961,815 ( 1.0%)
                 rb_vm_opt_getconstant_path:  1,863,678 ( 1.0%)
                      rb_hash_new_with_size:  1,796,456 ( 0.9%)
                 rb_class_allocate_instance:  1,785,043 ( 0.9%)
                              String#empty?:  1,713,414 ( 0.9%)
                            rb_ary_new_capa:  1,678,834 ( 0.9%)
```

shipit:

```
Top-20 calls to C functions from JIT code (83.4% of total 182,402,821):
                             rb_vm_opt_send_without_block: 45,753,484 (25.1%)
                                              rb_ivar_get: 21,020,650 (11.5%)
                                rb_vm_setinstancevariable: 17,528,603 ( 9.6%)
                                             rb_hash_aref: 11,892,856 ( 6.5%)
                                               rb_vm_send: 11,723,471 ( 6.4%)
                                          rb_vm_env_write: 10,434,452 ( 5.7%)
                                               Module#===:  4,225,048 ( 2.3%)
                                        rb_vm_invokesuper:  3,705,906 ( 2.0%)
                                           Thread.current:  3,337,603 ( 1.8%)
                                             rb_ary_entry:  3,114,378 ( 1.7%)
                                                 Hash#[]=:  2,509,912 ( 1.4%)
                                             Array#empty?:  2,282,994 ( 1.3%)
                                        rb_vm_invokeblock:  2,210,511 ( 1.2%)
                                               Hash#fetch:  2,017,960 ( 1.1%)
                                                    _bi20:  1,975,147 ( 1.1%)
                                     rb_zjit_defined_ivar:  1,897,127 ( 1.0%)
                               rb_vm_opt_getconstant_path:  1,813,294 ( 1.0%)
                                          rb_ary_new_capa:  1,615,406 ( 0.9%)
                                             Kernel#is_a?:  1,567,854 ( 0.9%)
                               rb_class_allocate_instance:  1,560,035 ( 0.9%)
```

Thanks to @eregon for the idea.

Co-authored-by: Jacob Denbeaux <jacob.denbeaux@shopify.com>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
This commit is contained in:
Max Bernstein 2025-11-19 12:58:24 -08:00 committed by GitHub
parent 28908a95c4
commit 4a1af72a13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-11-19 20:58:55 +00:00
Merged-By: tekknolagi <donotemailthisaddress@bernsteinbear.com>
8 changed files with 127 additions and 75 deletions

View File

@ -174,6 +174,7 @@ class << RubyVM::ZJIT
# Show counters independent from exit_* or dynamic_send_*
print_counters_with_prefix(prefix: 'not_inlined_cfuncs_', prompt: 'not inlined C methods', buf:, stats:, limit: 20)
print_counters_with_prefix(prefix: 'ccall_', prompt: 'calls to C functions from JIT code', buf:, stats:, limit: 20)
# Don't show not_annotated_cfuncs right now because it mostly duplicates not_inlined_cfuncs
# print_counters_with_prefix(prefix: 'not_annotated_cfuncs_', prompt: 'not annotated C methods', buf:, stats:, limit: 20)

View File

@ -2065,6 +2065,17 @@ impl Assembler {
out
}
pub fn count_call_to(&mut self, fn_name: &str) {
// We emit ccalls while initializing the JIT. Unfortunately, we skip those because
// otherwise we have no counter pointers to read.
if crate::state::ZJITState::has_instance() && get_option!(stats) {
let ccall_counter_pointers = crate::state::ZJITState::get_ccall_counter_pointers();
let counter_ptr = ccall_counter_pointers.entry(fn_name.to_string()).or_insert_with(|| Box::new(0));
let counter_ptr: &mut u64 = counter_ptr.as_mut();
self.incr_counter(Opnd::const_ptr(counter_ptr), 1.into());
}
}
pub fn cmp(&mut self, left: Opnd, right: Opnd) {
self.push_insn(Insn::Cmp { left, right });
}
@ -2389,6 +2400,7 @@ pub(crate) use asm_comment;
macro_rules! asm_ccall {
[$asm: ident, $fn_name:ident, $($args:expr),* ] => {{
$crate::backend::lir::asm_comment!($asm, concat!("call ", stringify!($fn_name)));
$asm.count_call_to(stringify!($fn_name));
$asm.ccall($fn_name as *const u8, vec![$($args),*])
}};
}

View File

@ -419,14 +419,14 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
&Insn::GuardLess { left, right, state } => gen_guard_less(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
&Insn::GuardGreaterEq { left, right, state } => gen_guard_greater_eq(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
Insn::PatchPoint { invariant, state } => no_output!(gen_patch_point(jit, asm, invariant, &function.frame_state(*state))),
Insn::CCall { cfunc, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfunc, opnds!(args)),
Insn::CCall { cfunc, args, name, return_type: _, elidable: _ } => gen_ccall(asm, *cfunc, *name, opnds!(args)),
// Give up CCallWithFrame for 7+ args since asm.ccall() doesn't support it.
Insn::CCallWithFrame { cd, state, args, .. } if args.len() > C_ARG_OPNDS.len() =>
gen_send_without_block(jit, asm, *cd, &function.frame_state(*state), SendFallbackReason::CCallWithFrameTooManyArgs),
Insn::CCallWithFrame { cfunc, args, cme, state, blockiseq, .. } =>
gen_ccall_with_frame(jit, asm, *cfunc, opnds!(args), *cme, *blockiseq, &function.frame_state(*state)),
Insn::CCallVariadic { cfunc, recv, args, name: _, cme, state, return_type: _, elidable: _ } => {
gen_ccall_variadic(jit, asm, *cfunc, opnd!(recv), opnds!(args), *cme, &function.frame_state(*state))
Insn::CCallWithFrame { cfunc, name, args, cme, state, blockiseq, .. } =>
gen_ccall_with_frame(jit, asm, *cfunc, *name, opnds!(args), *cme, *blockiseq, &function.frame_state(*state)),
Insn::CCallVariadic { cfunc, recv, args, name, cme, state, return_type: _, elidable: _ } => {
gen_ccall_variadic(jit, asm, *cfunc, *name, opnd!(recv), opnds!(args), *cme, &function.frame_state(*state))
}
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))),
@ -697,6 +697,7 @@ fn gen_invokebuiltin(jit: &JITState, asm: &mut Assembler, state: &FrameState, bf
let mut cargs = vec![EC];
cargs.extend(args);
asm.count_call_to(unsafe { std::ffi::CStr::from_ptr(bf.name).to_str().unwrap() });
asm.ccall(bf.func_ptr as *const u8, cargs)
}
@ -754,6 +755,7 @@ fn gen_ccall_with_frame(
jit: &mut JITState,
asm: &mut Assembler,
cfunc: *const u8,
name: ID,
args: Vec<Opnd>,
cme: *const rb_callable_method_entry_t,
blockiseq: Option<IseqPtr>,
@ -801,6 +803,7 @@ fn gen_ccall_with_frame(
asm.mov(CFP, new_cfp);
asm.store(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP), CFP);
asm.count_call_to(&name.contents_lossy());
let result = asm.ccall(cfunc, args);
asm_comment!(asm, "pop C frame");
@ -817,7 +820,8 @@ fn gen_ccall_with_frame(
/// Lowering for [`Insn::CCall`]. This is a low-level raw call that doesn't know
/// anything about the callee, so handling for e.g. GC safety is dealt with elsewhere.
fn gen_ccall(asm: &mut Assembler, cfunc: *const u8, args: Vec<Opnd>) -> lir::Opnd {
fn gen_ccall(asm: &mut Assembler, cfunc: *const u8, name: ID, args: Vec<Opnd>) -> lir::Opnd {
asm.count_call_to(&name.contents_lossy());
asm.ccall(cfunc, args)
}
@ -827,6 +831,7 @@ fn gen_ccall_variadic(
jit: &mut JITState,
asm: &mut Assembler,
cfunc: *const u8,
name: ID,
recv: Opnd,
args: Vec<Opnd>,
cme: *const rb_callable_method_entry_t,
@ -859,6 +864,7 @@ fn gen_ccall_variadic(
asm.store(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP), CFP);
let argv_ptr = gen_push_opnds(asm, &args);
asm.count_call_to(&name.contents_lossy());
let result = asm.ccall(cfunc, vec![args.len().into(), argv_ptr, recv]);
gen_pop_opnds(asm, &args);
@ -1169,9 +1175,10 @@ fn gen_send(
unsafe extern "C" {
fn rb_vm_send(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
asm.ccall(
rb_vm_send as *const u8,
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
asm_ccall!(
asm,
rb_vm_send,
EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@ -1192,9 +1199,10 @@ fn gen_send_forward(
unsafe extern "C" {
fn rb_vm_sendforward(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
asm.ccall(
rb_vm_sendforward as *const u8,
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
asm_ccall!(
asm,
rb_vm_sendforward,
EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@ -1213,9 +1221,10 @@ fn gen_send_without_block(
unsafe extern "C" {
fn rb_vm_opt_send_without_block(ec: EcPtr, cfp: CfpPtr, cd: VALUE) -> VALUE;
}
asm.ccall(
rb_vm_opt_send_without_block as *const u8,
vec![EC, CFP, Opnd::const_ptr(cd)],
asm_ccall!(
asm,
rb_vm_opt_send_without_block,
EC, CFP, Opnd::const_ptr(cd)
)
}
@ -1331,9 +1340,10 @@ fn gen_invokeblock(
unsafe extern "C" {
fn rb_vm_invokeblock(ec: EcPtr, cfp: CfpPtr, cd: VALUE) -> VALUE;
}
asm.ccall(
rb_vm_invokeblock as *const u8,
vec![EC, CFP, Opnd::const_ptr(cd)],
asm_ccall!(
asm,
rb_vm_invokeblock,
EC, CFP, Opnd::const_ptr(cd)
)
}
@ -1353,9 +1363,10 @@ fn gen_invokesuper(
unsafe extern "C" {
fn rb_vm_invokesuper(ec: EcPtr, cfp: CfpPtr, cd: VALUE, blockiseq: IseqPtr) -> VALUE;
}
asm.ccall(
rb_vm_invokesuper as *const u8,
vec![EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()],
asm_ccall!(
asm,
rb_vm_invokesuper,
EC, CFP, Opnd::const_ptr(cd), VALUE::from(blockiseq).into()
)
}
@ -1436,9 +1447,10 @@ fn gen_array_include(
unsafe extern "C" {
fn rb_vm_opt_newarray_include_p(ec: EcPtr, num: c_long, elts: *const VALUE, target: VALUE) -> VALUE;
}
asm.ccall(
rb_vm_opt_newarray_include_p as *const u8,
vec![EC, num.into(), elements_ptr, target],
asm_ccall!(
asm,
rb_vm_opt_newarray_include_p,
EC, num.into(), elements_ptr, target
)
}
@ -1454,9 +1466,10 @@ fn gen_dup_array_include(
unsafe extern "C" {
fn rb_vm_opt_duparray_include_p(ec: EcPtr, ary: VALUE, target: VALUE) -> VALUE;
}
asm.ccall(
rb_vm_opt_duparray_include_p as *const u8,
vec![EC, ary.into(), target],
asm_ccall!(
asm,
rb_vm_opt_duparray_include_p,
EC, ary.into(), target
)
}
@ -1527,6 +1540,7 @@ fn gen_object_alloc_class(asm: &mut Assembler, class: VALUE, state: &FrameState)
let alloc_func = unsafe { rb_zjit_class_get_alloc_func(class) };
assert!(alloc_func.is_some(), "class {} passed to ObjectAllocClass must have an allocator", get_class_name(class));
asm_comment!(asm, "call allocator for class {}", get_class_name(class));
asm.count_call_to(&format!("{}::allocator", get_class_name(class)));
asm.ccall(alloc_func.unwrap() as *const u8, vec![class.into()])
}
}

View File

@ -775,11 +775,17 @@ pub fn rust_str_to_ruby(str: &str) -> VALUE {
unsafe { rb_utf8_str_new(str.as_ptr() as *const _, str.len() as i64) }
}
/// Produce a Ruby symbol from a Rust string slice
pub fn rust_str_to_sym(str: &str) -> VALUE {
/// Produce a Ruby ID from a Rust string slice
pub fn rust_str_to_id(str: &str) -> ID {
let c_str = CString::new(str).unwrap();
let c_ptr: *const c_char = c_str.as_ptr();
unsafe { rb_id2sym(rb_intern(c_ptr)) }
unsafe { rb_intern(c_ptr) }
}
/// Produce a Ruby symbol from a Rust string slice
pub fn rust_str_to_sym(str: &str) -> VALUE {
let id = rust_str_to_id(str);
unsafe { rb_id2sym(id) }
}
/// Produce an owned Rust String from a C char pointer

View File

@ -2889,12 +2889,13 @@ impl Function {
let mut cfunc_args = vec![recv];
cfunc_args.append(&mut args);
let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let ccall = fun.push_insn(block, Insn::CCallWithFrame {
cd,
cfunc,
args: cfunc_args,
cme,
name: method_id,
name,
state,
return_type: types::BasicObject,
elidable: false,
@ -3018,6 +3019,7 @@ impl Function {
// No inlining; emit a call
let cfunc = unsafe { get_mct_func(cfunc) }.cast();
let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let mut cfunc_args = vec![recv];
cfunc_args.append(&mut args);
let return_type = props.return_type;
@ -3025,7 +3027,7 @@ impl Function {
// Filter for a leaf and GC free function
if props.leaf && props.no_gc {
fun.push_insn(block, Insn::IncrCounter(Counter::inline_cfunc_optimized_send_count));
let ccall = fun.push_insn(block, Insn::CCall { cfunc, args: cfunc_args, name: method_id, return_type, elidable });
let ccall = fun.push_insn(block, Insn::CCall { cfunc, args: cfunc_args, name, return_type, elidable });
fun.make_equal_to(send_insn_id, ccall);
} else {
if get_option!(stats) {
@ -3036,7 +3038,7 @@ impl Function {
cfunc,
args: cfunc_args,
cme,
name: method_id,
name,
state,
return_type,
elidable,
@ -3099,12 +3101,13 @@ impl Function {
}
let return_type = props.return_type;
let elidable = props.elidable;
let name = rust_str_to_id(&qualified_method_name(unsafe { (*cme).owner }, unsafe { (*cme).called_id }));
let ccall = fun.push_insn(block, Insn::CCallVariadic {
cfunc,
recv,
args,
cme,
name: method_id,
name,
state,
return_type,
elidable,

View File

@ -560,7 +560,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(CustomEq@0x1000, !=@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(CustomEq@0x1000)
v28:HeapObject[class_exact:CustomEq] = GuardType v9, HeapObject[class_exact:CustomEq]
v29:BoolExact = CCallWithFrame !=@0x1038, v28, v9
v29:BoolExact = CCallWithFrame BasicObject#!=@0x1038, v28, v9
v20:NilClass = Const Value(nil)
CheckInterrupts
Return v20
@ -784,7 +784,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1000, fun_new_map@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v24:ArraySubclass[class_exact:C] = GuardType v13, ArraySubclass[class_exact:C]
v25:BasicObject = CCallWithFrame fun_new_map@0x1038, v24, block=0x1040
v25:BasicObject = CCallWithFrame C#fun_new_map@0x1038, v24, block=0x1040
v16:BasicObject = GetLocal l0, EP@3
CheckInterrupts
Return v25
@ -1043,7 +1043,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Object@0x1008, puts@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Object@0x1008)
v22:HeapObject[class_exact*:Object@VALUE(0x1008)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1008)]
v23:BasicObject = CCallVariadic puts@0x1040, v22, v12
v23:BasicObject = CCallVariadic Kernel#puts@0x1040, v22, v12
CheckInterrupts
Return v23
");
@ -2241,7 +2241,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Module@0x1010, name@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(Module@0x1010)
IncrCounter inline_cfunc_optimized_send_count
v34:StringExact|NilClass = CCall name@0x1048, v29
v34:StringExact|NilClass = CCall Module#name@0x1048, v29
PatchPoint NoEPEscape(test)
v22:Fixnum[1] = Const Value(1)
CheckInterrupts
@ -2273,7 +2273,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
v29:Fixnum = CCall length@0x1038, v13
v29:Fixnum = CCall Array#length@0x1038, v13
v20:Fixnum[5] = Const Value(5)
CheckInterrupts
Return v20
@ -2417,7 +2417,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
v29:Fixnum = CCall size@0x1038, v13
v29:Fixnum = CCall Array#size@0x1038, v13
v20:Fixnum[5] = Const Value(5)
CheckInterrupts
Return v20
@ -3150,7 +3150,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1008, new@0x1010, cme:0x1018)
PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Class@0x1040)
v57:BasicObject = CCallVariadic new@0x1048, v46, v16
v57:BasicObject = CCallVariadic Array.new@0x1048, v46, v16
CheckInterrupts
Return v57
");
@ -3181,7 +3181,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Set@0x1008, initialize@0x1040, cme:0x1048)
PatchPoint NoSingletonClass(Set@0x1008)
v49:SetExact = GuardType v18, SetExact
v50:BasicObject = CCallVariadic initialize@0x1070, v49
v50:BasicObject = CCallVariadic Set#initialize@0x1070, v49
CheckInterrupts
CheckInterrupts
Return v18
@ -3211,7 +3211,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1008, new@0x1010, cme:0x1018)
PatchPoint MethodRedefined(Class@0x1040, new@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Class@0x1040)
v54:BasicObject = CCallVariadic new@0x1048, v43
v54:BasicObject = CCallVariadic String.new@0x1048, v43
CheckInterrupts
Return v54
");
@ -3243,7 +3243,7 @@ mod hir_opt_tests {
v50:RegexpExact = ObjectAllocClass Regexp:VALUE(0x1008)
PatchPoint MethodRedefined(Regexp@0x1008, initialize@0x1048, cme:0x1050)
PatchPoint NoSingletonClass(Regexp@0x1008)
v54:BasicObject = CCallVariadic initialize@0x1078, v50, v17
v54:BasicObject = CCallVariadic Regexp#initialize@0x1078, v50, v17
CheckInterrupts
CheckInterrupts
Return v50
@ -3271,7 +3271,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
v30:Fixnum = CCall length@0x1038, v18
v30:Fixnum = CCall Array#length@0x1038, v18
CheckInterrupts
Return v30
");
@ -3298,7 +3298,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
IncrCounter inline_cfunc_optimized_send_count
v30:Fixnum = CCall size@0x1038, v18
v30:Fixnum = CCall Array#size@0x1038, v18
CheckInterrupts
Return v30
");
@ -3458,7 +3458,7 @@ mod hir_opt_tests {
v10:HashExact = NewHash
PatchPoint MethodRedefined(Hash@0x1000, dup@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Hash@0x1000)
v22:BasicObject = CCallWithFrame dup@0x1038, v10
v22:BasicObject = CCallWithFrame Kernel#dup@0x1038, v10
v14:BasicObject = SendWithoutBlock v22, :freeze
CheckInterrupts
Return v14
@ -3551,7 +3551,7 @@ mod hir_opt_tests {
v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, dup@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v22:BasicObject = CCallWithFrame dup@0x1038, v10
v22:BasicObject = CCallWithFrame Kernel#dup@0x1038, v10
v14:BasicObject = SendWithoutBlock v22, :freeze
CheckInterrupts
Return v14
@ -3645,7 +3645,7 @@ mod hir_opt_tests {
v11:StringExact = StringCopy v10
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
v23:BasicObject = CCallWithFrame dup@0x1040, v11
v23:BasicObject = CCallWithFrame String#dup@0x1040, v11
v15:BasicObject = SendWithoutBlock v23, :freeze
CheckInterrupts
Return v15
@ -3740,7 +3740,7 @@ mod hir_opt_tests {
v11:StringExact = StringCopy v10
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
v23:BasicObject = CCallWithFrame dup@0x1040, v11
v23:BasicObject = CCallWithFrame String#dup@0x1040, v11
v15:BasicObject = SendWithoutBlock v23, :-@
CheckInterrupts
Return v15
@ -3882,7 +3882,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1008, to_s@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
v31:ArrayExact = GuardType v9, ArrayExact
v32:BasicObject = CCallWithFrame to_s@0x1040, v31
v32:BasicObject = CCallWithFrame Array#to_s@0x1040, v31
v19:String = AnyToString v9, str: v32
v21:StringExact = StringConcat v13, v19
CheckInterrupts
@ -4745,7 +4745,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
v25:BoolExact = CCall empty?@0x1038, v23
v25:BoolExact = CCall Array#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@ -4773,7 +4773,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Hash@0x1000)
v23:HashExact = GuardType v9, HashExact
IncrCounter inline_cfunc_optimized_send_count
v25:BoolExact = CCall empty?@0x1038, v23
v25:BoolExact = CCall Hash#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@ -5036,7 +5036,7 @@ mod hir_opt_tests {
v11:ArrayExact = ArrayDup v10
PatchPoint MethodRedefined(Array@0x1008, map@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
v21:BasicObject = CCallWithFrame map@0x1040, v11, block=0x1048
v21:BasicObject = CCallWithFrame Array#map@0x1040, v11, block=0x1048
CheckInterrupts
Return v21
");
@ -5484,7 +5484,7 @@ mod hir_opt_tests {
v10:ArrayExact = NewArray
PatchPoint MethodRedefined(Array@0x1000, reverse@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v20:ArrayExact = CCallWithFrame reverse@0x1038, v10
v20:ArrayExact = CCallWithFrame Array#reverse@0x1038, v10
CheckInterrupts
Return v20
");
@ -5537,7 +5537,7 @@ mod hir_opt_tests {
v13:StringExact = StringCopy v12
PatchPoint MethodRedefined(Array@0x1008, join@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Array@0x1008)
v23:StringExact = CCallVariadic join@0x1040, v10, v13
v23:StringExact = CCallVariadic Array#join@0x1040, v10, v13
CheckInterrupts
Return v23
");
@ -5859,7 +5859,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Class@0x1010, current@0x1018, cme:0x1020)
PatchPoint NoSingletonClass(Class@0x1010)
IncrCounter inline_cfunc_optimized_send_count
v25:BasicObject = CCall current@0x1048, v20
v25:BasicObject = CCall Thread.current@0x1048, v20
CheckInterrupts
Return v25
");
@ -5889,7 +5889,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, []=@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v31:ArrayExact = GuardType v9, ArrayExact
v32:BasicObject = CCallVariadic []=@0x1038, v31, v16, v18
v32:BasicObject = CCallVariadic Array#[]=@0x1038, v31, v16, v18
CheckInterrupts
Return v18
");
@ -5980,7 +5980,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Array@0x1000, push@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(Array@0x1000)
v28:ArrayExact = GuardType v9, ArrayExact
v29:BasicObject = CCallVariadic push@0x1038, v28, v14, v16, v18
v29:BasicObject = CCallVariadic Array#push@0x1038, v28, v14, v16, v18
CheckInterrupts
Return v29
");
@ -6008,7 +6008,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
v25:Fixnum = CCall length@0x1038, v23
v25:Fixnum = CCall Array#length@0x1038, v23
CheckInterrupts
Return v25
");
@ -6036,7 +6036,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
v23:ArrayExact = GuardType v9, ArrayExact
IncrCounter inline_cfunc_optimized_send_count
v25:Fixnum = CCall size@0x1038, v23
v25:Fixnum = CCall Array#size@0x1038, v23
CheckInterrupts
Return v25
");
@ -6064,7 +6064,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1008, =~@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(String@0x1008)
v25:StringExact = GuardType v9, StringExact
v26:BasicObject = CCallWithFrame =~@0x1040, v25, v14
v26:BasicObject = CCallWithFrame String#=~@0x1040, v25, v14
CheckInterrupts
Return v26
");
@ -6235,7 +6235,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1000, setbyte@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v30:StringExact = GuardType v13, StringExact
v31:BasicObject = CCallWithFrame setbyte@0x1038, v30, v14, v15
v31:BasicObject = CCallWithFrame String#setbyte@0x1038, v30, v14, v15
CheckInterrupts
Return v31
");
@ -6264,7 +6264,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
v25:BoolExact = CCall empty?@0x1038, v23
v25:BoolExact = CCall String#empty?@0x1038, v23
CheckInterrupts
Return v25
");
@ -6348,7 +6348,7 @@ mod hir_opt_tests {
bb2(v8:BasicObject, v9:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, succ@0x1008, cme:0x1010)
v22:Integer = GuardType v9, Integer
v23:BasicObject = CCallWithFrame succ@0x1038, v22
v23:BasicObject = CCallWithFrame Integer#succ@0x1038, v22
CheckInterrupts
Return v23
");
@ -6405,7 +6405,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(String@0x1000, <<@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(String@0x1000)
v27:StringExact = GuardType v11, StringExact
v28:BasicObject = CCallWithFrame <<@0x1038, v27, v12
v28:BasicObject = CCallWithFrame String#<<@0x1038, v27, v12
CheckInterrupts
Return v28
");
@ -6465,7 +6465,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(MyString@0x1000, <<@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(MyString@0x1000)
v27:StringSubclass[class_exact:MyString] = GuardType v11, StringSubclass[class_exact:MyString]
v28:BasicObject = CCallWithFrame <<@0x1038, v27, v12
v28:BasicObject = CCallWithFrame String#<<@0x1038, v27, v12
CheckInterrupts
Return v28
");
@ -6622,7 +6622,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, ^@0x1008, cme:0x1010)
v25:Integer = GuardType v11, Integer
v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
v26:BasicObject = CCallWithFrame Integer#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@ -6645,7 +6645,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(Integer@0x1000, ^@0x1008, cme:0x1010)
v25:Fixnum = GuardType v11, Fixnum
v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
v26:BasicObject = CCallWithFrame Integer#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@ -6668,7 +6668,7 @@ mod hir_opt_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
PatchPoint MethodRedefined(TrueClass@0x1000, ^@0x1008, cme:0x1010)
v25:TrueClass = GuardType v11, TrueClass
v26:BasicObject = CCallWithFrame ^@0x1038, v25, v12
v26:BasicObject = CCallWithFrame TrueClass#^@0x1038, v25, v12
CheckInterrupts
Return v26
");
@ -6718,7 +6718,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Hash@0x1000)
v23:HashExact = GuardType v9, HashExact
IncrCounter inline_cfunc_optimized_send_count
v25:Fixnum = CCall size@0x1038, v23
v25:Fixnum = CCall Hash#size@0x1038, v23
CheckInterrupts
Return v25
");
@ -7086,7 +7086,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1008, respond_to?@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(C@0x1008)
v24:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
v25:BasicObject = CCallVariadic respond_to?@0x1040, v24, v14
v25:BasicObject = CCallVariadic Kernel#respond_to?@0x1040, v24, v14
CheckInterrupts
Return v25
");
@ -7637,7 +7637,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
v25:Fixnum = CCall size@0x1038, v23
v25:Fixnum = CCall String#size@0x1038, v23
CheckInterrupts
Return v25
");
@ -7756,7 +7756,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1000)
v23:StringExact = GuardType v9, StringExact
IncrCounter inline_cfunc_optimized_send_count
v25:Fixnum = CCall length@0x1038, v23
v25:Fixnum = CCall String#length@0x1038, v23
CheckInterrupts
Return v25
");
@ -7922,7 +7922,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Class@0x1038)
v30:ModuleSubclass[class_exact*:Class@VALUE(0x1038)] = GuardType v26, ModuleSubclass[class_exact*:Class@VALUE(0x1038)]
IncrCounter inline_cfunc_optimized_send_count
v32:StringExact|NilClass = CCall name@0x1070, v30
v32:StringExact|NilClass = CCall Module#name@0x1070, v30
CheckInterrupts
Return v32
");

View File

@ -59,6 +59,9 @@ pub struct ZJITState {
/// Counter pointers for un-annotated C functions
not_annotated_frame_cfunc_counter_pointers: HashMap<String, Box<u64>>,
/// Counter pointers for all calls to any kind of C function from JIT code
ccall_counter_pointers: HashMap<String, Box<u64>>,
/// Locations of side exists within generated code
exit_locations: Option<SideExitLocations>,
}
@ -135,6 +138,7 @@ impl ZJITState {
exit_trampoline_with_counter: exit_trampoline,
full_frame_cfunc_counter_pointers: HashMap::new(),
not_annotated_frame_cfunc_counter_pointers: HashMap::new(),
ccall_counter_pointers: HashMap::new(),
exit_locations,
};
unsafe { ZJIT_STATE = Enabled(zjit_state); }
@ -215,6 +219,11 @@ impl ZJITState {
&mut ZJITState::get_instance().not_annotated_frame_cfunc_counter_pointers
}
/// Get a mutable reference to ccall counter pointers
pub fn get_ccall_counter_pointers() -> &'static mut HashMap<String, Box<u64>> {
&mut ZJITState::get_instance().ccall_counter_pointers
}
/// Was --zjit-save-compiled-iseqs specified?
pub fn should_log_compiled_iseqs() -> bool {
get_option!(log_compiled_iseqs).is_some()

View File

@ -689,6 +689,13 @@ pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE, target_key: VALUE) ->
set_stat_usize!(hash, &key_string, **counter);
}
// Set ccall counters
let ccall = ZJITState::get_ccall_counter_pointers();
for (signature, counter) in ccall.iter() {
let key_string = format!("ccall_{}", signature);
set_stat_usize!(hash, &key_string, **counter);
}
hash
}