Skip to content

Commit d6912c7

Browse files
committed
ZJIT: Add stats for reasons why cfuncs are not optimized
1 parent c05ea92 commit d6912c7

3 files changed

Lines changed: 48 additions & 8 deletions

File tree

zjit.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def stats_string
4242
# Show non-exit counters
4343
print_counters_with_prefix(prefix: 'dynamic_send_type_', prompt: 'dynamic send types', buf:, stats:, limit: 20)
4444
print_counters_with_prefix(prefix: 'unspecialized_def_type_', prompt: 'send fallback unspecialized def_types', buf:, stats:, limit: 20)
45+
print_counters_with_prefix(prefix: 'not_optimized_cfunc_', prompt: 'reasons cfuncs are not optimized', buf:, stats:, limit: 20)
4546
print_counters_with_prefix(prefix: 'send_fallback_', prompt: 'dynamic send types', buf:, stats:, limit: 20)
4647

4748
# Show exit counters, ordered by the typical amount of exits for the prefix at the time

zjit/src/hir.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,15 +2122,30 @@ impl Function {
21222122
//
21232123
// Bail on argc mismatch
21242124
if argc != cfunc_argc as u32 {
2125+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_argc_mismatch));
21252126
return Err(());
21262127
}
21272128

21282129
// Filter for a leaf and GC free function
21292130
use crate::cruby_methods::FnProperties;
2130-
let Some(FnProperties { leaf: true, no_gc: true, return_type, elidable }) =
2131-
ZJITState::get_method_annotations().get_cfunc_properties(method)
2132-
else {
2133-
return Err(());
2131+
let cfunc_properties = ZJITState::get_method_annotations().get_cfunc_properties(method);
2132+
2133+
let (return_type, elidable) = match cfunc_properties {
2134+
Some(FnProperties { leaf: true, no_gc: true, return_type, elidable }) => {
2135+
(return_type, elidable)
2136+
}
2137+
Some(FnProperties { leaf: false, no_gc: true, .. }) => {
2138+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_not_leaf));
2139+
return Err(());
2140+
}
2141+
Some(FnProperties { leaf: true, no_gc: false, .. }) => {
2142+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_not_no_gc));
2143+
return Err(());
2144+
}
2145+
_ => {
2146+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_not_leaf_nor_no_gc));
2147+
return Err(());
2148+
}
21342149
};
21352150

21362151
let ci_flags = unsafe { vm_ci_flag(call_info) };
@@ -2147,7 +2162,10 @@ impl Function {
21472162
cfunc_args.append(&mut args);
21482163
let ccall = fun.push_insn(block, Insn::CCall { cfun, args: cfunc_args, name: method_id, return_type, elidable });
21492164
fun.make_equal_to(send_insn_id, ccall);
2150-
return Ok(());
2165+
Ok(())
2166+
} else {
2167+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_not_args_simple));
2168+
Err(())
21512169
}
21522170
}
21532171
// Variadic method
@@ -2186,17 +2204,20 @@ impl Function {
21862204

21872205
fun.make_equal_to(send_insn_id, ccall);
21882206
return Ok(());
2207+
} else {
2208+
// Fall through for complex cases (splat, kwargs, etc.)
2209+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_variadic_not_args_simple));
2210+
return Err(());
21892211
}
2190-
// Fall through for complex cases (splat, kwargs, etc.)
21912212
}
21922213
-2 => {
21932214
// (self, args_ruby_array) parameter form
21942215
// Falling through for now
2216+
fun.push_insn(block, Insn::IncrCounter(Counter::not_optimized_cfunc_variadic_ruby_array_arg));
2217+
return Err(());
21952218
}
21962219
_ => unreachable!("unknown cfunc kind: argc={argc}")
21972220
}
2198-
2199-
Err(())
22002221
}
22012222

22022223
for block in self.rpo() {
@@ -8072,6 +8093,7 @@ mod opt_tests {
80728093
bb0(v0:BasicObject):
80738094
v4:Fixnum[1] = Const Value(1)
80748095
v5:Fixnum[0] = Const Value(0)
8096+
IncrCounter not_optimized_cfunc_argc_mismatch
80758097
v7:BasicObject = SendWithoutBlock v4, :itself, v5
80768098
CheckInterrupts
80778099
Return v7
@@ -8709,6 +8731,7 @@ mod opt_tests {
87098731
fn test@<compiled>:2:
87108732
bb0(v0:BasicObject):
87118733
v5:HashExact = NewHash
8734+
IncrCounter not_optimized_cfunc_not_leaf_nor_no_gc
87128735
v7:BasicObject = SendWithoutBlock v5, :dup
87138736
v9:BasicObject = SendWithoutBlock v7, :freeze
87148737
CheckInterrupts
@@ -8726,6 +8749,7 @@ mod opt_tests {
87268749
bb0(v0:BasicObject):
87278750
v5:HashExact = NewHash
87288751
v6:NilClass = Const Value(nil)
8752+
IncrCounter not_optimized_cfunc_argc_mismatch
87298753
v8:BasicObject = SendWithoutBlock v5, :freeze, v6
87308754
CheckInterrupts
87318755
Return v8
@@ -8772,6 +8796,7 @@ mod opt_tests {
87728796
fn test@<compiled>:2:
87738797
bb0(v0:BasicObject):
87748798
v5:ArrayExact = NewArray
8799+
IncrCounter not_optimized_cfunc_not_leaf_nor_no_gc
87758800
v7:BasicObject = SendWithoutBlock v5, :dup
87768801
v9:BasicObject = SendWithoutBlock v7, :freeze
87778802
CheckInterrupts
@@ -8789,6 +8814,7 @@ mod opt_tests {
87898814
bb0(v0:BasicObject):
87908815
v5:ArrayExact = NewArray
87918816
v6:NilClass = Const Value(nil)
8817+
IncrCounter not_optimized_cfunc_argc_mismatch
87928818
v8:BasicObject = SendWithoutBlock v5, :freeze, v6
87938819
CheckInterrupts
87948820
Return v8
@@ -8836,6 +8862,7 @@ mod opt_tests {
88368862
bb0(v0:BasicObject):
88378863
v4:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
88388864
v6:StringExact = StringCopy v4
8865+
IncrCounter not_optimized_cfunc_not_leaf_nor_no_gc
88398866
v8:BasicObject = SendWithoutBlock v6, :dup
88408867
v10:BasicObject = SendWithoutBlock v8, :freeze
88418868
CheckInterrupts
@@ -8854,6 +8881,7 @@ mod opt_tests {
88548881
v4:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
88558882
v6:StringExact = StringCopy v4
88568883
v7:NilClass = Const Value(nil)
8884+
IncrCounter not_optimized_cfunc_argc_mismatch
88578885
v9:BasicObject = SendWithoutBlock v6, :freeze, v7
88588886
CheckInterrupts
88598887
Return v9
@@ -8901,6 +8929,7 @@ mod opt_tests {
89018929
bb0(v0:BasicObject):
89028930
v4:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
89038931
v6:StringExact = StringCopy v4
8932+
IncrCounter not_optimized_cfunc_not_leaf_nor_no_gc
89048933
v8:BasicObject = SendWithoutBlock v6, :dup
89058934
v10:BasicObject = SendWithoutBlock v8, :-@
89068935
CheckInterrupts
@@ -9000,6 +9029,7 @@ mod opt_tests {
90009029
bb0(v0:BasicObject, v1:BasicObject):
90019030
v5:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
90029031
v17:BasicObject = GuardTypeNot v1, String
9032+
IncrCounter not_optimized_cfunc_not_leaf_nor_no_gc
90039033
v18:BasicObject = SendWithoutBlock v1, :to_s
90049034
v9:String = AnyToString v1, str: v18
90059035
v11:StringExact = StringConcat v5, v9

zjit/src/stats.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,15 @@ make_counters! {
152152
unspecialized_def_type_refined,
153153
unspecialized_def_type_null,
154154

155+
// Specific reasons why a C function is not optimized
156+
not_optimized_cfunc_argc_mismatch,
157+
not_optimized_cfunc_not_no_gc,
158+
not_optimized_cfunc_not_leaf,
159+
not_optimized_cfunc_not_leaf_nor_no_gc,
160+
not_optimized_cfunc_not_args_simple,
161+
not_optimized_cfunc_variadic_not_args_simple,
162+
not_optimized_cfunc_variadic_ruby_array_arg,
163+
155164
send_fallback_polymorphic,
156165
send_fallback_no_profiles,
157166

0 commit comments

Comments
 (0)