diff --git a/yjit.rb b/yjit.rb index 118cf412deb1fb..fdc9fb4e0386ef 100644 --- a/yjit.rb +++ b/yjit.rb @@ -253,9 +253,12 @@ def _print_stats # :nodoc: # Number of failed compiler invocations compilation_failure = stats[:compilation_failure] - if stats[:x86_call_rel32] != 0 || stats[:x86_call_reg] != 0 - $stderr.puts "x86_call_rel32: " + format_number(10, stats[:x86_call_rel32]) - $stderr.puts "x86_call_reg: " + format_number(10, stats[:x86_call_reg]) + $stderr.puts "num_send: " + format_number(10, stats[:num_send]) + $stderr.puts "num_send_known_class: " + format_number_pct(10, stats[:num_send_known_class], stats[:num_send]) + $stderr.puts "num_send_polymorphic: " + format_number_pct(10, stats[:num_send_polymorphic], stats[:num_send]) + if stats[:num_send_x86_rel32] != 0 || stats[:num_send_x86_reg] != 0 + $stderr.puts "num_send_x86_rel32: " + format_number(10, stats[:num_send_x86_rel32]) + $stderr.puts "num_send_x86_reg: " + format_number(10, stats[:num_send_x86_reg]) end $stderr.puts "bindings_allocations: " + format_number(10, stats[:binding_allocations]) @@ -315,10 +318,8 @@ def print_sorted_exit_counts(stats, prefix:, how_many: 20, left_pad: 4) # :nodoc exits.each do |name, count| padding = longest_insn_name_len + left_pad padded_name = "%#{padding}s" % name - padded_count = format_number(10, count) - percent = 100.0 * count / total_exits - formatted_percent = "%.1f" % percent - $stderr.puts("#{padded_name}: #{padded_count} (#{formatted_percent}%)" ) + padded_count = format_number_pct(10, count, total_exits) + $stderr.puts("#{padded_name}: #{padded_count}") end else $stderr.puts "total_exits: " + format_number(10, total_exits) @@ -350,11 +351,9 @@ def print_counters(counters, prefix:, prompt:) # :nodoc: total = counters.sum { |(_, counter_value)| counter_value } counters.reverse_each do |(name, value)| - percentage = value.fdiv(total) * 100 padded_name = name.rjust(longest_name_length, ' ') - padded_count = format_number(10, value) - formatted_pct = "%4.1f%%" % percentage - $stderr.puts(" #{padded_name}: #{padded_count} (#{formatted_pct})") + padded_count = format_number_pct(10, value, total) + $stderr.puts(" #{padded_name}: #{padded_count}") end end @@ -366,5 +365,13 @@ def format_number(pad, number) formatted = [with_commas, decimal].compact.join(".") formatted.rjust(pad, ' ') end + + # Format a number along with a percentage over a total value + def format_number_pct(pad, number, total) + padded_count = format_number(pad, number) + percentage = number.fdiv(total) * 100 + formatted_pct = "%4.1f%%" % percentage + "#{padded_count} (#{formatted_pct})" + end end end diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index 67bb5d1ffb43e0..0bb1a6381f2435 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -700,13 +700,13 @@ pub fn call_ptr(cb: &mut CodeBlock, scratch_opnd: X86Opnd, dst_ptr: *const u8) { // If the offset fits in 32-bit if rel64 >= i32::MIN.into() && rel64 <= i32::MAX.into() { - incr_counter!(x86_call_rel32); + incr_counter!(num_send_x86_rel32); call_rel32(cb, rel64.try_into().unwrap()); return; } // Move the pointer into the scratch register and call - incr_counter!(x86_call_reg); + incr_counter!(num_send_x86_reg); mov(cb, scratch_opnd, const_ptr_opnd(dst_ptr)); call(cb, scratch_opnd); } else { diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 6726bb2bd438db..74d7784b21c201 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5205,7 +5205,6 @@ fn gen_send_iseq( } } - if flags & VM_CALL_ARGS_SPLAT != 0 && flags & VM_CALL_ZSUPER != 0 { // zsuper methods are super calls without any arguments. // They are also marked as splat, but don't actually have an array @@ -5933,10 +5932,16 @@ fn gen_send_general( } let recv_idx = argc + if flags & VM_CALL_ARGS_BLOCKARG != 0 { 1 } else { 0 }; - let comptime_recv = jit_peek_at_stack(jit, ctx, recv_idx as isize); let comptime_recv_klass = comptime_recv.class_of(); + // Guard that the receiver has the same class as the one from compile time + let side_exit = get_side_exit(jit, ocb, ctx); + + // Points to the receiver operand on the stack + let recv = ctx.stack_opnd(recv_idx); + let recv_opnd = StackOpnd(recv_idx.try_into().unwrap()); + // Log the name of the method we're calling to #[cfg(feature = "disasm")] { @@ -5950,12 +5955,14 @@ fn gen_send_general( } } - // Guard that the receiver has the same class as the one from compile time - let side_exit = get_side_exit(jit, ocb, ctx); - - // Points to the receiver operand on the stack - let recv = ctx.stack_opnd(recv_idx); - let recv_opnd = StackOpnd(recv_idx.try_into().unwrap()); + // Gather some statistics about sends + gen_counter_incr!(asm, num_send); + if let Some(_known_klass) = ctx.get_opnd_type(recv_opnd).known_class() { + gen_counter_incr!(asm, num_send_known_class); + } + if ctx.get_chain_depth() > 1 { + gen_counter_incr!(asm, num_send_polymorphic); + } let megamorphic_exit = counted_exit!(ocb, side_exit, send_klass_megamorphic); jit_guard_known_klass( diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index 9fff7f0e273cc0..91b253ecfb9295 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -318,8 +318,11 @@ make_counters! { num_gc_obj_refs, - x86_call_rel32, - x86_call_reg, + num_send, + num_send_known_class, + num_send_polymorphic, + num_send_x86_rel32, + num_send_x86_reg, } //===========================================================================