diff options
| author | Max Bernstein <rubybugs@bernsteinbear.com> | 2025-10-30 15:15:09 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-30 15:15:09 -0400 |
| commit | 6707945f0c065d47a4a9e8fd1627345bfcb85c10 (patch) | |
| tree | 1778ea37af07cea1e561c1682604570666d373ac | |
| parent | 9b1894690fca424afa7d411748a315d880666376 (diff) | |
ZJIT: Split out optimized method types in stats (#15002)
We can see send/block call/struct aref/... e.g. on lobsters:
```
Top-9 not optimized method types for send_without_block (100.0% of total 3,133,812):
iseq: 2,004,557 (64.0%)
optimized_struct_aref: 496,232 (15.8%)
alias: 268,579 ( 8.6%)
optimized_call: 224,883 ( 7.2%)
optimized_send: 120,531 ( 3.8%)
bmethod: 12,011 ( 0.4%)
null: 4,636 ( 0.1%)
optimized_block_call: 1,930 ( 0.1%)
cfunc: 453 ( 0.0%)
```
railsbench:
```
Top-8 not optimized method types for send_without_block (100.0% of total 5,735,608):
iseq: 2,854,551 (49.8%)
optimized_struct_aref: 871,459 (15.2%)
optimized_call: 862,185 (15.0%)
alias: 588,486 (10.3%)
optimized_send: 482,171 ( 8.4%)
null: 39,942 ( 0.7%)
bmethod: 36,784 ( 0.6%)
cfunc: 30 ( 0.0%)
```
shipit:
```
Top-10 not optimized method types for send_without_block (100.0% of total 4,844,304):
iseq: 2,881,206 (59.5%)
optimized_struct_aref: 1,158,935 (23.9%)
optimized_call: 472,898 ( 9.8%)
alias: 208,010 ( 4.3%)
optimized_send: 55,479 ( 1.1%)
null: 47,273 ( 1.0%)
bmethod: 12,608 ( 0.3%)
optimized_block_call: 7,860 ( 0.2%)
cfunc: 31 ( 0.0%)
optimized_struct_aset: 4 ( 0.0%)
```
| -rw-r--r-- | zjit/src/codegen.rs | 5 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 27 | ||||
| -rw-r--r-- | zjit/src/stats.rs | 23 |
3 files changed, 54 insertions, 1 deletions
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index db9d6a14e3..6e8038335f 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -15,7 +15,7 @@ use crate::invariants::{ }; use crate::gc::{append_gc_offsets, get_or_create_iseq_payload, get_or_create_iseq_payload_ptr, IseqCodePtrs, IseqPayload, IseqStatus}; use crate::state::ZJITState; -use crate::stats::{send_fallback_counter, exit_counter_for_compile_error, incr_counter, incr_counter_by, send_fallback_counter_for_method_type, send_without_block_fallback_counter_for_method_type, send_fallback_counter_ptr_for_opcode, CompileError}; +use crate::stats::{send_fallback_counter, exit_counter_for_compile_error, incr_counter, incr_counter_by, send_fallback_counter_for_method_type, send_without_block_fallback_counter_for_method_type, send_without_block_fallback_counter_for_optimized_method_type, send_fallback_counter_ptr_for_opcode, CompileError}; use crate::stats::{counter_ptr, with_time_stat, Counter, Counter::{compile_time_ns, exit_compile_error}}; use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr}; use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, NATIVE_BASE_PTR, SP}; @@ -1741,6 +1741,9 @@ fn gen_incr_send_fallback_counter(asm: &mut Assembler, reason: SendFallbackReaso SendWithoutBlockNotOptimizedMethodType(method_type) => { gen_incr_counter(asm, send_without_block_fallback_counter_for_method_type(method_type)); } + SendWithoutBlockNotOptimizedOptimizedMethodType(method_type) => { + gen_incr_counter(asm, send_without_block_fallback_counter_for_optimized_method_type(method_type)); + } SendNotOptimizedMethodType(method_type) => { gen_incr_counter(asm, send_fallback_counter_for_method_type(method_type)); } diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index b284ae6c11..ea8dacd40b 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -512,6 +512,28 @@ impl From<u32> for MethodType { } } +#[derive(Debug, Clone, Copy)] +pub enum OptimizedMethodType { + Send, + Call, + BlockCall, + StructAref, + StructAset, +} + +impl From<u32> for OptimizedMethodType { + fn from(value: u32) -> Self { + match value { + OPTIMIZED_METHOD_TYPE_SEND => OptimizedMethodType::Send, + OPTIMIZED_METHOD_TYPE_CALL => OptimizedMethodType::Call, + OPTIMIZED_METHOD_TYPE_BLOCK_CALL => OptimizedMethodType::BlockCall, + OPTIMIZED_METHOD_TYPE_STRUCT_AREF => OptimizedMethodType::StructAref, + OPTIMIZED_METHOD_TYPE_STRUCT_ASET => OptimizedMethodType::StructAset, + _ => unreachable!("unknown send_without_block optimized method type: {}", value), + } + } +} + impl std::fmt::Display for SideExitReason { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { @@ -539,6 +561,7 @@ pub enum SendFallbackReason { SendWithoutBlockCfuncNotVariadic, SendWithoutBlockCfuncArrayVariadic, SendWithoutBlockNotOptimizedMethodType(MethodType), + SendWithoutBlockNotOptimizedOptimizedMethodType(OptimizedMethodType), SendWithoutBlockDirectTooManyArgs, SendPolymorphic, SendNoProfiles, @@ -2335,6 +2358,10 @@ impl Function { } self.push_insn(block, Insn::SetIvar { self_val: recv, id, val, state }); self.make_equal_to(insn_id, val); + } else if def_type == VM_METHOD_TYPE_OPTIMIZED { + let opt_type = unsafe { get_cme_def_body_optimized_type(cme) }; + self.set_dynamic_send_reason(insn_id, SendWithoutBlockNotOptimizedOptimizedMethodType(OptimizedMethodType::from(opt_type))); + self.push_insn_id(block, insn_id); continue; } else { self.set_dynamic_send_reason(insn_id, SendWithoutBlockNotOptimizedMethodType(MethodType::from(def_type))); self.push_insn_id(block, insn_id); continue; diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 9965526b76..ad027ef593 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -167,6 +167,7 @@ make_counters! { send_fallback_send_without_block_cfunc_not_variadic, send_fallback_send_without_block_cfunc_array_variadic, send_fallback_send_without_block_not_optimized_method_type, + send_fallback_send_without_block_not_optimized_optimized_method_type, send_fallback_send_without_block_direct_too_many_args, send_fallback_send_polymorphic, send_fallback_send_no_profiles, @@ -227,6 +228,13 @@ make_counters! { unspecialized_send_without_block_def_type_refined, unspecialized_send_without_block_def_type_null, + // Method call optimized_type related to send without block fallback to dynamic dispatch + unspecialized_send_without_block_def_type_optimized_send, + unspecialized_send_without_block_def_type_optimized_call, + unspecialized_send_without_block_def_type_optimized_block_call, + unspecialized_send_without_block_def_type_optimized_struct_aref, + unspecialized_send_without_block_def_type_optimized_struct_aset, + // Method call def_type related to send fallback to dynamic dispatch unspecialized_send_def_type_iseq, unspecialized_send_def_type_cfunc, @@ -388,6 +396,8 @@ pub fn send_fallback_counter(reason: crate::hir::SendFallbackReason) -> Counter SendWithoutBlockCfuncNotVariadic => send_fallback_send_without_block_cfunc_not_variadic, SendWithoutBlockCfuncArrayVariadic => send_fallback_send_without_block_cfunc_array_variadic, SendWithoutBlockNotOptimizedMethodType(_) => send_fallback_send_without_block_not_optimized_method_type, + SendWithoutBlockNotOptimizedOptimizedMethodType(_) + => send_fallback_send_without_block_not_optimized_optimized_method_type, SendWithoutBlockDirectTooManyArgs => send_fallback_send_without_block_direct_too_many_args, SendPolymorphic => send_fallback_send_polymorphic, SendNoProfiles => send_fallback_send_no_profiles, @@ -419,6 +429,19 @@ pub fn send_without_block_fallback_counter_for_method_type(method_type: crate::h } } +pub fn send_without_block_fallback_counter_for_optimized_method_type(method_type: crate::hir::OptimizedMethodType) -> Counter { + use crate::hir::OptimizedMethodType::*; + use crate::stats::Counter::*; + + match method_type { + Send => unspecialized_send_without_block_def_type_optimized_send, + Call => unspecialized_send_without_block_def_type_optimized_call, + BlockCall => unspecialized_send_without_block_def_type_optimized_block_call, + StructAref => unspecialized_send_without_block_def_type_optimized_struct_aref, + StructAset => unspecialized_send_without_block_def_type_optimized_struct_aset, + } +} + pub fn send_fallback_counter_for_method_type(method_type: crate::hir::MethodType) -> Counter { use crate::hir::MethodType::*; use crate::stats::Counter::*; |
