1
1
// We use the YARV bytecode constants which have a CRuby-style name
2
2
#![ allow( non_upper_case_globals) ]
3
3
4
- use crate :: { cruby:: * , gc:: get_or_create_iseq_payload, hir_type:: { types:: { Empty , Fixnum } , Type } } ;
4
+ use crate :: { cruby:: * , gc:: get_or_create_iseq_payload, hir_type:: { types:: { Empty , Fixnum } , Type } , options :: get_option } ;
5
5
6
6
/// Ephemeral state for profiling runtime information
7
7
struct Profiler {
@@ -38,43 +38,49 @@ impl Profiler {
38
38
39
39
/// API called from zjit_* instruction. opcode is the bare (non-zjit_*) instruction.
40
40
#[ unsafe( no_mangle) ]
41
- pub extern "C" fn rb_zjit_profile_insn ( opcode : ruby_vminsn_type , ec : EcPtr ) {
41
+ pub extern "C" fn rb_zjit_profile_insn ( bare_opcode : ruby_vminsn_type , ec : EcPtr ) {
42
42
with_vm_lock ( src_loc ! ( ) , || {
43
43
let mut profiler = Profiler :: new ( ec) ;
44
- profile_insn ( & mut profiler, opcode ) ;
44
+ profile_insn ( & mut profiler, bare_opcode ) ;
45
45
} ) ;
46
46
}
47
47
48
48
/// Profile a YARV instruction
49
- fn profile_insn ( profiler : & mut Profiler , opcode : ruby_vminsn_type ) {
50
- match opcode {
51
- YARVINSN_opt_nil_p => profile_operands ( profiler, 1 ) ,
52
- YARVINSN_opt_plus => profile_operands ( profiler, 2 ) ,
53
- YARVINSN_opt_minus => profile_operands ( profiler, 2 ) ,
54
- YARVINSN_opt_mult => profile_operands ( profiler, 2 ) ,
55
- YARVINSN_opt_div => profile_operands ( profiler, 2 ) ,
56
- YARVINSN_opt_mod => profile_operands ( profiler, 2 ) ,
57
- YARVINSN_opt_eq => profile_operands ( profiler, 2 ) ,
58
- YARVINSN_opt_neq => profile_operands ( profiler, 2 ) ,
59
- YARVINSN_opt_lt => profile_operands ( profiler, 2 ) ,
60
- YARVINSN_opt_le => profile_operands ( profiler, 2 ) ,
61
- YARVINSN_opt_gt => profile_operands ( profiler, 2 ) ,
62
- YARVINSN_opt_ge => profile_operands ( profiler, 2 ) ,
63
- YARVINSN_opt_and => profile_operands ( profiler, 2 ) ,
64
- YARVINSN_opt_or => profile_operands ( profiler, 2 ) ,
49
+ fn profile_insn ( profiler : & mut Profiler , bare_opcode : ruby_vminsn_type ) {
50
+ let profile = & mut get_or_create_iseq_payload ( profiler. iseq ) . profile ;
51
+ match bare_opcode {
52
+ YARVINSN_opt_nil_p => profile_operands ( profiler, profile, 1 ) ,
53
+ YARVINSN_opt_plus => profile_operands ( profiler, profile, 2 ) ,
54
+ YARVINSN_opt_minus => profile_operands ( profiler, profile, 2 ) ,
55
+ YARVINSN_opt_mult => profile_operands ( profiler, profile, 2 ) ,
56
+ YARVINSN_opt_div => profile_operands ( profiler, profile, 2 ) ,
57
+ YARVINSN_opt_mod => profile_operands ( profiler, profile, 2 ) ,
58
+ YARVINSN_opt_eq => profile_operands ( profiler, profile, 2 ) ,
59
+ YARVINSN_opt_neq => profile_operands ( profiler, profile, 2 ) ,
60
+ YARVINSN_opt_lt => profile_operands ( profiler, profile, 2 ) ,
61
+ YARVINSN_opt_le => profile_operands ( profiler, profile, 2 ) ,
62
+ YARVINSN_opt_gt => profile_operands ( profiler, profile, 2 ) ,
63
+ YARVINSN_opt_ge => profile_operands ( profiler, profile, 2 ) ,
64
+ YARVINSN_opt_and => profile_operands ( profiler, profile, 2 ) ,
65
+ YARVINSN_opt_or => profile_operands ( profiler, profile, 2 ) ,
65
66
YARVINSN_opt_send_without_block => {
66
67
let cd: * const rb_call_data = profiler. insn_opnd ( 0 ) . as_ptr ( ) ;
67
68
let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
68
69
// Profile all the arguments and self (+1).
69
- profile_operands ( profiler, ( argc + 1 ) as usize ) ;
70
+ profile_operands ( profiler, profile , ( argc + 1 ) as usize ) ;
70
71
}
71
72
_ => { }
72
73
}
74
+
75
+ // Once we profile the instruction num_profiles times, we stop profiling it.
76
+ profile. num_profiles [ profiler. insn_idx ] = profile. num_profiles [ profiler. insn_idx ] . saturating_add ( 1 ) ;
77
+ if profile. num_profiles [ profiler. insn_idx ] == get_option ! ( num_profiles) {
78
+ unsafe { rb_zjit_iseq_insn_set ( profiler. iseq , profiler. insn_idx as u32 , bare_opcode) ; }
79
+ }
73
80
}
74
81
75
82
/// Profile the Type of top-`n` stack operands
76
- fn profile_operands ( profiler : & mut Profiler , n : usize ) {
77
- let profile = & mut get_or_create_iseq_payload ( profiler. iseq ) . profile ;
83
+ fn profile_operands ( profiler : & mut Profiler , profile : & mut IseqProfile , n : usize ) {
78
84
let types = & mut profile. opnd_types [ profiler. insn_idx ] ;
79
85
if types. len ( ) <= n {
80
86
types. resize ( n, Empty ) ;
@@ -89,11 +95,17 @@ fn profile_operands(profiler: &mut Profiler, n: usize) {
89
95
pub struct IseqProfile {
90
96
/// Type information of YARV instruction operands, indexed by the instruction index
91
97
opnd_types : Vec < Vec < Type > > ,
98
+
99
+ /// Number of profiled executions for each YARV instruction, indexed by the instruction index
100
+ num_profiles : Vec < u8 > ,
92
101
}
93
102
94
103
impl IseqProfile {
95
104
pub fn new ( iseq_size : u32 ) -> Self {
96
- Self { opnd_types : vec ! [ vec![ ] ; iseq_size as usize ] }
105
+ Self {
106
+ opnd_types : vec ! [ vec![ ] ; iseq_size as usize ] ,
107
+ num_profiles : vec ! [ 0 ; iseq_size as usize ] ,
108
+ }
97
109
}
98
110
99
111
/// Get profiled operand types for a given instruction index
0 commit comments