summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bernstein <rubybugs@bernsteinbear.com>2025-10-30 15:15:09 -0400
committerGitHub <noreply@github.com>2025-10-30 15:15:09 -0400
commit6707945f0c065d47a4a9e8fd1627345bfcb85c10 (patch)
tree1778ea37af07cea1e561c1682604570666d373ac
parent9b1894690fca424afa7d411748a315d880666376 (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.rs5
-rw-r--r--zjit/src/hir.rs27
-rw-r--r--zjit/src/stats.rs23
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::*;