Skip to content

Commit 8a9b895

Browse files
committed
ZJIT: Add IncrDynamicCounter HIR instead
1 parent 20c6aa1 commit 8a9b895

5 files changed

Lines changed: 40 additions & 51 deletions

File tree

zjit.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def stats_string
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)
4545
print_counters_with_prefix(prefix: 'send_fallback_', prompt: 'dynamic send types', buf:, stats:, limit: 20)
46-
print_counters_with_prefix(prefix: 'not_optimized_cfuncs_', prompt: 'Unoptimized C functions', buf:, stats:, limit: 20)
46+
print_counters_with_prefix(prefix: 'not_optimized_cfuncs_', prompt: 'unoptimized sends to C functions', buf:, stats:, limit: 20)
4747

4848
# Show exit counters, ordered by the typical amount of exits for the prefix at the time
4949
print_counters_with_prefix(prefix: 'unhandled_yarv_insn_', prompt: 'unhandled YARV insns', buf:, stats:, limit: 20)

zjit/src/codegen.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
420420
Insn::GetSpecialSymbol { symbol_type, state: _ } => gen_getspecial_symbol(asm, *symbol_type),
421421
Insn::GetSpecialNumber { nth, state } => gen_getspecial_number(asm, *nth, &function.frame_state(*state)),
422422
&Insn::IncrCounter(counter) => no_output!(gen_incr_counter(asm, counter)),
423-
Insn::CountUnoptimizedCFunc { signature, counter_ptr } => no_output!(gen_count_unoptimized_cfunc(asm, signature, *counter_ptr)),
423+
Insn::IncrDynamicCounter { counter_ptr } => no_output!(gen_incr_dynamic_counter(asm, *counter_ptr)),
424424
Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state)),
425425
&Insn::CheckInterrupts { state } => no_output!(gen_check_interrupts(jit, asm, &function.frame_state(state))),
426426
&Insn::HashDup { val, state } => { gen_hash_dup(asm, opnd!(val), &function.frame_state(state)) },
@@ -1586,25 +1586,19 @@ fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd,
15861586
}
15871587

15881588
/// Generate code that records unoptimized C functions if --zjit-stats is enabled
1589-
fn gen_count_unoptimized_cfunc(asm: &mut Assembler, signature: &str, counter_ptr: *mut u64) {
1589+
fn gen_incr_dynamic_counter(asm: &mut Assembler, counter_ptr: *mut u64) {
15901590
if get_option!(stats) {
1591-
unsafe extern "C" {
1592-
fn rb_zjit_count_unoptimized_cfunc(counter_ptr: *mut u64);
1593-
}
1594-
asm_comment!(asm, "count unoptimized cfunc: {}", signature);
1595-
asm_ccall!(asm, rb_zjit_count_unoptimized_cfunc, Opnd::const_ptr(counter_ptr as *const u8));
1591+
let ptr_reg = asm.load(Opnd::const_ptr(counter_ptr as *const u8));
1592+
let counter_opnd = Opnd::mem(64, ptr_reg, 0);
1593+
asm.incr_counter(counter_opnd, Opnd::UImm(1));
15961594
}
15971595
}
15981596

15991597
/// Generate code that increments a counter if --zjit-stats
16001598
fn gen_incr_counter(asm: &mut Assembler, counter: Counter) {
16011599
if get_option!(stats) {
16021600
let ptr = counter_ptr(counter);
1603-
let ptr_reg = asm.load(Opnd::const_ptr(ptr as *const u8));
1604-
let counter_opnd = Opnd::mem(64, ptr_reg, 0);
1605-
1606-
// Increment and store the updated value
1607-
asm.incr_counter(counter_opnd, Opnd::UImm(1));
1601+
gen_incr_dynamic_counter(asm, ptr);
16081602
}
16091603
}
16101604

zjit/src/hir.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::{
1414
use crate::hir_type::{Type, types};
1515
use crate::bitset::BitSet;
1616
use crate::profile::{TypeDistributionSummary, ProfiledType};
17-
use crate::stats::{Counter, get_or_create_unoptimized_cfunc_counter_ptr};
17+
use crate::stats::Counter;
1818

1919
/// An index of an [`Insn`] in a [`Function`]. This is a popular
2020
/// type since this effectively acts as a pointer to an [`Insn`].
@@ -707,8 +707,8 @@ pub enum Insn {
707707
/// Increment a counter in ZJIT stats
708708
IncrCounter(Counter),
709709

710-
/// Increment a counter in ZJIT stats for the given unoptimized C function
711-
CountUnoptimizedCFunc { signature: String, counter_ptr: *mut u64 },
710+
/// Increment a counter in ZJIT stats for the given counter pointer
711+
IncrDynamicCounter { counter_ptr: *mut u64 },
712712

713713
/// Equivalent of RUBY_VM_CHECK_INTS. Automatically inserted by the compiler before jumps and
714714
/// return instructions.
@@ -723,7 +723,7 @@ impl Insn {
723723
| Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::EntryPoint { .. } | Insn::Return { .. }
724724
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. }
725725
| Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetGlobal { .. }
726-
| Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) | Insn::CountUnoptimizedCFunc { .. }
726+
| Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) | Insn::IncrDynamicCounter { .. }
727727
| Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } => false,
728728
_ => true,
729729
}
@@ -975,7 +975,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
975975
}
976976
Ok(())
977977
},
978-
Insn::CountUnoptimizedCFunc { signature, .. } => write!(f, "CountUnoptimizedCFunc {}", signature),
978+
Insn::IncrDynamicCounter { .. } => write!(f, "IncrDynamicCounter"),
979979
Insn::Snapshot { state } => write!(f, "Snapshot {}", state.print(self.ptr_map)),
980980
Insn::Defined { op_type, v, .. } => {
981981
// op_type (enum defined_type) printing logic from iseq.c.
@@ -1380,7 +1380,7 @@ impl Function {
13801380
| SideExit {..}
13811381
| EntryPoint {..}
13821382
| LoadPC
1383-
| CountUnoptimizedCFunc {..}
1383+
| IncrDynamicCounter {..}
13841384
| IncrCounter(_)) => result.clone(),
13851385
&Snapshot { state: FrameState { iseq, insn_idx, pc, ref stack, ref locals } } =>
13861386
Snapshot {
@@ -1530,7 +1530,7 @@ impl Function {
15301530
| Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::Throw { .. }
15311531
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. }
15321532
| Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetLocal { .. } | Insn::IncrCounter(_)
1533-
| Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } | Insn::CountUnoptimizedCFunc { .. } =>
1533+
| Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } | Insn::IncrDynamicCounter { .. } =>
15341534
panic!("Cannot infer type of instruction with no output: {}", self.insns[insn.0]),
15351535
Insn::Const { val: Const::Value(val) } => Type::from_value(*val),
15361536
Insn::Const { val: Const::CBool(val) } => Type::from_cbool(*val),
@@ -2284,10 +2284,12 @@ impl Function {
22842284
let called_id = unsafe { (*cme).called_id };
22852285
let class_name = get_class_name(owner);
22862286
let method_name = called_id.contents_lossy();
2287-
let signature = format!("{}#{}", class_name, method_name);
2288-
let counter_ptr = get_or_create_unoptimized_cfunc_counter_ptr(signature.clone());
2287+
let qualified_method_name = format!("{}#{}", class_name, method_name);
2288+
let unoptimized_cfunc_counter_pointers = ZJITState::get_unoptimized_cfunc_counter_pointers();
2289+
let counter_ptr = unoptimized_cfunc_counter_pointers.entry(qualified_method_name.clone()).or_insert_with(|| Box::new(0));
2290+
let counter_ptr = &mut **counter_ptr as *mut u64;
22892291

2290-
self.push_insn(block, Insn::CountUnoptimizedCFunc { signature, counter_ptr });
2292+
self.push_insn(block, Insn::IncrDynamicCounter { counter_ptr });
22912293
}
22922294
_ => {}
22932295
}
@@ -2435,7 +2437,7 @@ impl Function {
24352437
| &Insn::GetLocal { .. }
24362438
| &Insn::PutSpecialObject { .. }
24372439
| &Insn::IncrCounter(_)
2438-
| &Insn::CountUnoptimizedCFunc { .. } =>
2440+
| &Insn::IncrDynamicCounter { .. } =>
24392441
{}
24402442
&Insn::PatchPoint { state, .. }
24412443
| &Insn::CheckInterrupts { state }
@@ -9502,7 +9504,7 @@ mod opt_tests {
95029504
bb2(v6:BasicObject):
95039505
v10:Fixnum[1] = Const Value(1)
95049506
v11:Fixnum[0] = Const Value(0)
9505-
CountUnoptimizedCFunc Kernel#itself
9507+
IncrDynamicCounter
95069508
v13:BasicObject = SendWithoutBlock v10, :itself, v11
95079509
CheckInterrupts
95089510
Return v13
@@ -10341,7 +10343,7 @@ mod opt_tests {
1034110343
Jump bb2(v4)
1034210344
bb2(v6:BasicObject):
1034310345
v11:HashExact = NewHash
10344-
CountUnoptimizedCFunc Kernel#dup
10346+
IncrDynamicCounter
1034510347
v13:BasicObject = SendWithoutBlock v11, :dup
1034610348
v15:BasicObject = SendWithoutBlock v13, :freeze
1034710349
CheckInterrupts
@@ -10365,7 +10367,7 @@ mod opt_tests {
1036510367
bb2(v6:BasicObject):
1036610368
v11:HashExact = NewHash
1036710369
v12:NilClass = Const Value(nil)
10368-
CountUnoptimizedCFunc Hash#freeze
10370+
IncrDynamicCounter
1036910371
v14:BasicObject = SendWithoutBlock v11, :freeze, v12
1037010372
CheckInterrupts
1037110373
Return v14
@@ -10430,7 +10432,7 @@ mod opt_tests {
1043010432
Jump bb2(v4)
1043110433
bb2(v6:BasicObject):
1043210434
v11:ArrayExact = NewArray
10433-
CountUnoptimizedCFunc Kernel#dup
10435+
IncrDynamicCounter
1043410436
v13:BasicObject = SendWithoutBlock v11, :dup
1043510437
v15:BasicObject = SendWithoutBlock v13, :freeze
1043610438
CheckInterrupts
@@ -10454,7 +10456,7 @@ mod opt_tests {
1045410456
bb2(v6:BasicObject):
1045510457
v11:ArrayExact = NewArray
1045610458
v12:NilClass = Const Value(nil)
10457-
CountUnoptimizedCFunc Array#freeze
10459+
IncrDynamicCounter
1045810460
v14:BasicObject = SendWithoutBlock v11, :freeze, v12
1045910461
CheckInterrupts
1046010462
Return v14
@@ -10520,7 +10522,7 @@ mod opt_tests {
1052010522
bb2(v6:BasicObject):
1052110523
v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1052210524
v12:StringExact = StringCopy v10
10523-
CountUnoptimizedCFunc String#dup
10525+
IncrDynamicCounter
1052410526
v14:BasicObject = SendWithoutBlock v12, :dup
1052510527
v16:BasicObject = SendWithoutBlock v14, :freeze
1052610528
CheckInterrupts
@@ -10545,7 +10547,7 @@ mod opt_tests {
1054510547
v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1054610548
v12:StringExact = StringCopy v10
1054710549
v13:NilClass = Const Value(nil)
10548-
CountUnoptimizedCFunc String#freeze
10550+
IncrDynamicCounter
1054910551
v15:BasicObject = SendWithoutBlock v12, :freeze, v13
1055010552
CheckInterrupts
1055110553
Return v15
@@ -10611,7 +10613,7 @@ mod opt_tests {
1061110613
bb2(v6:BasicObject):
1061210614
v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1061310615
v12:StringExact = StringCopy v10
10614-
CountUnoptimizedCFunc String#dup
10616+
IncrDynamicCounter
1061510617
v14:BasicObject = SendWithoutBlock v12, :dup
1061610618
v16:BasicObject = SendWithoutBlock v14, :-@
1061710619
CheckInterrupts
@@ -10741,7 +10743,7 @@ mod opt_tests {
1074110743
bb2(v8:BasicObject, v9:BasicObject):
1074210744
v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1074310745
v25:BasicObject = GuardTypeNot v9, String
10744-
CountUnoptimizedCFunc Array#to_s
10746+
IncrDynamicCounter
1074510747
v26:BasicObject = SendWithoutBlock v9, :to_s
1074610748
v17:String = AnyToString v9, str: v26
1074710749
v19:StringExact = StringConcat v13, v17

zjit/src/state.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::asm::CodeBlock;
88
use crate::options::get_option;
99
use crate::stats::{Counters, ExitCounters};
1010
use crate::virtualmem::CodePtr;
11+
use std::collections::HashMap;
1112

1213
#[allow(non_upper_case_globals)]
1314
#[unsafe(no_mangle)]
@@ -46,6 +47,9 @@ pub struct ZJITState {
4647

4748
/// Trampoline to call function_stub_hit
4849
function_stub_hit_trampoline: CodePtr,
50+
51+
/// Counter pointers for unoptimized C functions
52+
unoptimized_cfunc_counter_pointers: HashMap<String, Box<u64>>,
4953
}
5054

5155
/// Private singleton instance of the codegen globals
@@ -80,6 +84,7 @@ impl ZJITState {
8084
exit_trampoline,
8185
function_stub_hit_trampoline,
8286
exit_trampoline_with_counter: exit_trampoline,
87+
unoptimized_cfunc_counter_pointers: HashMap::new(),
8388
};
8489
unsafe { ZJIT_STATE = Some(zjit_state); }
8590

@@ -138,6 +143,11 @@ impl ZJITState {
138143
&mut ZJITState::get_instance().exit_counters
139144
}
140145

146+
/// Get a mutable reference to unoptimized cfunc counter pointers
147+
pub fn get_unoptimized_cfunc_counter_pointers() -> &'static mut HashMap<String, Box<u64>> {
148+
&mut ZJITState::get_instance().unoptimized_cfunc_counter_pointers
149+
}
150+
141151
/// Was --zjit-save-compiled-iseqs specified?
142152
pub fn should_log_compiled_iseqs() -> bool {
143153
get_option!(log_compiled_iseqs).is_some()

zjit/src/stats.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
33
use std::time::Instant;
44
use std::sync::atomic::Ordering;
5-
use std::sync::{LazyLock, Mutex};
6-
use std::collections::HashMap;
75

86
#[cfg(feature = "stats_allocator")]
97
#[path = "../../jit/src/lib.rs"]
@@ -190,21 +188,6 @@ pub(crate) use incr_counter;
190188
/// The number of side exits from each YARV instruction
191189
pub type ExitCounters = [u64; VM_INSTRUCTION_SIZE as usize];
192190

193-
/// Store signature ("Klass#method") to counter pointer mappings for unoptimized cfuncs
194-
pub static UNOPTIMIZED_CFUNC_COUNTER_POINTERS: LazyLock<Mutex<HashMap<String, Box<u64>>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
195-
196-
/// Get or create a counter pointer for the given signature
197-
pub fn get_or_create_unoptimized_cfunc_counter_ptr(signature: String) -> *mut u64 {
198-
let mut map = UNOPTIMIZED_CFUNC_COUNTER_POINTERS.lock().unwrap();
199-
let counter = map.entry(signature).or_insert_with(|| Box::new(0));
200-
&mut **counter as *mut u64
201-
}
202-
203-
#[unsafe(no_mangle)]
204-
pub extern "C" fn rb_zjit_count_unoptimized_cfunc(counter_ptr: *mut u64) {
205-
unsafe { *counter_ptr += 1 }
206-
}
207-
208191
/// Return a raw pointer to the exit counter for a given YARV opcode
209192
pub fn exit_counter_ptr_for_opcode(opcode: u32) -> *mut u64 {
210193
let exit_counters = ZJITState::get_exit_counters();
@@ -402,7 +385,7 @@ pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE, target_key: VALUE) ->
402385
}
403386

404387
// Set unoptimized cfunc counters
405-
let unoptimized_cfuncs = UNOPTIMIZED_CFUNC_COUNTER_POINTERS.lock().unwrap();
388+
let unoptimized_cfuncs = ZJITState::get_unoptimized_cfunc_counter_pointers();
406389
for (signature, counter) in unoptimized_cfuncs.iter() {
407390
let key_string = format!("not_optimized_cfuncs_{}", signature);
408391
set_stat_usize!(hash, &key_string, **counter);

0 commit comments

Comments
 (0)