diff options
| author | Max Bernstein <rubybugs@bernsteinbear.com> | 2025-11-19 12:58:24 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-19 15:58:24 -0500 |
| commit | 4a1af72a13d41dcc38af7d69ea1f44856265d43f (patch) | |
| tree | 38846de07c6ca3fd1399ddca16859c55de797226 | |
| parent | 28908a95c4d303e3cf12f03b0b475a48778435a7 (diff) | |
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>
| -rw-r--r-- | zjit.rb | 1 | ||||
| -rw-r--r-- | zjit/src/backend/lir.rs | 12 | ||||
| -rw-r--r-- | zjit/src/codegen.rs | 68 | ||||
| -rw-r--r-- | zjit/src/cruby.rs | 12 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 11 | ||||
| -rw-r--r-- | zjit/src/hir/opt_tests.rs | 82 | ||||
| -rw-r--r-- | zjit/src/state.rs | 9 | ||||
| -rw-r--r-- | zjit/src/stats.rs | 7 |
8 files changed, 127 insertions, 75 deletions
@@ -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) diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index cb8382a43c..3c9bf72023 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -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),*]) }}; } diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 8fc66791a6..18266b4693 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -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()]) } } diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index db47385bc8..61c25a4092 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -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 diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 58638f30f0..982400db50 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -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, diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index fadb6ced5f..19f0e91b47 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -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 "); diff --git a/zjit/src/state.rs b/zjit/src/state.rs index 06296eb8f2..fd59161812 100644 --- a/zjit/src/state.rs +++ b/zjit/src/state.rs @@ -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() diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index b0ca28d258..df172997ce 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -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 } |
