[前][次][番号順一覧][スレッド一覧]

ruby-changes:68966

From: Noah <ko1@a...>
Date: Thu, 21 Oct 2021 08:19:29 +0900 (JST)
Subject: [ruby-changes:68966] d2e9932908 (master): Convert YJIT stats reporting on exit from C to Ruby.

https://git.ruby-lang.org/ruby.git/commit/?id=d2e9932908

From d2e9932908cf1a1075d07157bfa520a1714d43b0 Mon Sep 17 00:00:00 2001
From: Noah Gibbs <noah.gibbs@s...>
Date: Tue, 29 Jun 2021 16:36:05 +0100
Subject: Convert YJIT stats reporting on exit from C to Ruby.

---
 yjit.rb      |  80 +++++++++++++++++++++++++++++++++-----
 yjit_iface.c | 125 -----------------------------------------------------------
 2 files changed, 70 insertions(+), 135 deletions(-)

diff --git a/yjit.rb b/yjit.rb
index 3998e4fda8..db283fe33b 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -139,18 +139,78 @@ module YJIT https://github.com/ruby/ruby/blob/trunk/yjit.rb#L139
 
     # Format and print out counters
     def _print_stats
-      counters = runtime_stats
-      return unless counters
+      stats = runtime_stats
+      return unless stats
 
       $stderr.puts("***YJIT: Printing YJIT statistics on exit***")
-      $stderr.puts("Number of bindings allocated: %d\n" % counters[:binding_allocations])
-      $stderr.puts("Number of locals modified through binding: %d\n" % counters[:binding_set])
-
-      print_counters(counters, prefix: 'send_', prompt: 'method call exit reasons: ')
-      print_counters(counters, prefix: 'leave_', prompt: 'leave exit reasons: ')
-      print_counters(counters, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons:')
-      print_counters(counters, prefix: 'setivar_', prompt: 'setinstancevariable exit reasons:')
-      print_counters(counters, prefix: 'oaref_', prompt: 'opt_aref exit reasons: ')
+      $stderr.puts("Number of bindings allocated: %d\n" % stats[:binding_allocations])
+      $stderr.puts("Number of locals modified through binding: %d\n" % stats[:binding_set])
+
+      print_counters(stats, prefix: 'send_', prompt: 'method call exit reasons: ')
+      print_counters(stats, prefix: 'leave_', prompt: 'leave exit reasons: ')
+      print_counters(stats, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons:')
+      print_counters(stats, prefix: 'setivar_', prompt: 'setinstancevariable exit reasons:')
+      print_counters(stats, prefix: 'oaref_', prompt: 'opt_aref exit reasons: ')
+
+      total_exits = total_exit_count(stats)
+
+      # Number of instructions that finish executing in YJIT
+      retired_in_yjit = stats[:exec_instruction] - total_exits
+
+      # Average length of instruction sequences executed by YJIT
+      avg_len_in_yjit = retired_in_yjit.to_f / total_exits
+
+      # Proportion of instructions that retire in YJIT
+      total_insns_count = retired_in_yjit + stats[:vm_insns_count]
+      yjit_ratio_pct = 100.0 * retired_in_yjit.to_f / total_insns_count
+
+      $stderr.puts "compiled_iseq_count:   " + ("%10d" % stats[:compiled_iseq_count])
+      $stderr.puts "inline_code_size:      " + ("%10d" % stats[:inline_code_size])
+      $stderr.puts "outlined_code_size:    " + ("%10d" % stats[:outlined_code_size])
+
+      $stderr.puts "total_exit_count:      " + ("%10d" % total_exits)
+      $stderr.puts "total_insns_count:     " + ("%10d" % total_insns_count)
+      $stderr.puts "vm_insns_count:        " + ("%10d" % stats[:vm_insns_count])
+      $stderr.puts "yjit_insns_count:      " + ("%10d" % stats[:exec_instruction])
+      $stderr.puts "ratio_in_yjit:         " + ("%9.1f" % yjit_ratio_pct) + "%"
+      $stderr.puts "avg_len_in_yjit:       " + ("%10.1f" % avg_len_in_yjit)
+
+      print_sorted_exit_counts(stats, prefix: "exit_")
+    end
+
+    def print_sorted_exit_counts(stats, prefix:, how_many: 20, left_pad: 4)
+      exits = []
+      stats.each do |k, v|
+        if k.start_with?(prefix)
+          exits.push [k.to_s.delete_prefix(prefix), v]
+        end
+      end
+
+      exits = exits.sort_by { |name, count| -count }[0...how_many]
+      total_exits = total_exit_count(stats)
+
+      top_n_total = exits.map { |name, count| count }.sum
+      top_n_exit_pct = top_n_total / total_exits
+
+      $stderr.puts "Top-#{how_many} most frequent exit ops (#{"%.1f" % top_n_exit_pct}% of exits):"
+
+      longest_insn_name_len = exits.map { |name, count| name.length }.max
+      exits.each do |name, count|
+        padding = longest_insn_name_len + left_pad
+        padded_name = "%#{padding}s" % name
+        padded_count = "%10d" % count
+        percent = 100.0 * count / total_exits
+        formatted_percent = "%.1f" % percent
+        $stderr.puts("#{padded_name}: #{padded_count} (#{formatted_percent})" )
+      end
+    end
+
+    def total_exit_count(stats, prefix: "exit_")
+      total = 0
+      stats.each do |k,v|
+        total += v if k.start_with?(prefix)
+      end
+      total
     end
 
     def print_counters(counters, prefix:, prompt:)
diff --git a/yjit_iface.c b/yjit_iface.c
index e8a6dde969..a019458074 100644
--- a/yjit_iface.c
+++ b/yjit_iface.c
@@ -796,9 +796,6 @@ reset_stats_bang(rb_execution_context_t *ec, VALUE self) https://github.com/ruby/ruby/blob/trunk/yjit_iface.c#L796
 
 #include "yjit.rbinc"
 
-#if RUBY_DEBUG
-// implementation for --yjit-stats
-
 void
 rb_yjit_collect_vm_usage_insn(int insn)
 {
@@ -825,128 +822,6 @@ rb_yjit_count_side_exit_op(const VALUE *exit_pc) https://github.com/ruby/ruby/blob/trunk/yjit_iface.c#L822
     return exit_pc; // This function must return exit_pc!
 }
 
-struct insn_count {
-    int64_t insn;
-    int64_t count;
-};
-
-static int
-insn_count_sort_comp(const void *a, const void *b)
-{
-    const struct insn_count *count_a = a;
-    const struct insn_count *count_b = b;
-    if (count_a->count > count_b->count) {
-        return -1;
-    }
-    else if (count_a->count < count_b->count) {
-        return 1;
-    }
-    return 0;
-}
-
-static struct insn_count insn_sorting_buffer[VM_INSTRUCTION_SIZE];
-static const struct insn_count *
-sort_insn_count_array(int64_t *array)
-{
-    for (int i = 0; i < VM_INSTRUCTION_SIZE; i++) {
-        insn_sorting_buffer[i] = (struct insn_count) { i, array[i] };
-    }
-    qsort(insn_sorting_buffer, VM_INSTRUCTION_SIZE, sizeof(insn_sorting_buffer[0]), &insn_count_sort_comp);
-    return insn_sorting_buffer;
-}
-
-// Compute the total interpreter exit count
-static int64_t
-calc_total_exit_count()
-{
-    size_t total_exit_count = 0;
-    for (int i = 0; i < VM_INSTRUCTION_SIZE; i++) {
-        total_exit_count += exit_op_count[i];
-    }
-
-    return total_exit_count;
-}
-
-static void
-print_insn_count_buffer(int how_many, int left_pad)
-{
-    size_t total_exit_count = calc_total_exit_count();
-
-    // Sort the exit ops by decreasing frequency
-    const struct insn_count *sorted_exit_ops = sort_insn_count_array(exit_op_count);
-
-    // Compute the longest instruction name and top10_exit_count
-    size_t longest_insn_len = 0;
-    size_t top10_exit_count = 0;
-    for (int i = 0; i < how_many; i++) {
-        const char *instruction_name = insn_name(sorted_exit_ops[i].insn);
-        size_t len = strlen(instruction_name);
-        if (len > longest_insn_len) {
-            longest_insn_len = len;
-        }
-        top10_exit_count += sorted_exit_ops[i].count;
-    }
-
-    double top10_exit_percent = 100.0 * top10_exit_count / total_exit_count;
-
-    fprintf(stderr, "top-%d most frequent exit ops (%.1f%% of exits):\n", how_many, top10_exit_percent);
-
-    // Print the top-N most frequent exit counts
-    for (int i = 0; i < how_many; i++) {
-        const char *instruction_name = insn_name(sorted_exit_ops[i].insn);
-        size_t padding = left_pad + longest_insn_len - strlen(instruction_name);
-        for (size_t j = 0; j < padding; j++) {
-            fputc(' ', stderr);
-        }
-        double percent = 100 * sorted_exit_ops[i].count / (double)total_exit_count;
-        fprintf(stderr, "%s: %10" PRId64 " (%.1f%%)\n", instruction_name, sorted_exit_ops[i].count, percent);
-    }
-}
-
-__attribute__((destructor))
-static void
-print_yjit_stats(void)
-{
-    if (!rb_yjit_opts.gen_stats) {
-        return;
-    }
-
-    // Warn if the executable code block is out of the relative
-    // 32-bit jump range away from compiled C code
-    ptrdiff_t start_diff = (cb->mem_block + cb->mem_size) - (uint8_t*)&print_yjit_stats;
-    if (start_diff < INT32_MIN || start_diff > INT32_MAX) {
-        fprintf(stderr, "WARNING: end of code block past rel32 offset range from C code\n");
-    }
-
-    // Compute the total exit count
-    int64_t total_exit_count = calc_total_exit_count();
-
-    // Number of instructions that finish executing in YJIT. See :count-placement:.
-    int64_t retired_in_yjit = yjit_runtime_counters.exec_instruction - total_exit_count;
-
-    // Average length of instruction sequences executed by YJIT
-    double avg_len_in_yjit = (double)retired_in_yjit / total_exit_count;
-
-    // Proportion of instructions that retire in YJIT
-    int64_t total_insns_count = retired_in_yjit + yjit_runtime_counters.vm_insns_count;
-    double ratio = retired_in_yjit / (double)total_insns_count;
-
-    fprintf(stderr, "compiled_iseq_count:   %10" PRId64 "\n", yjit_runtime_counters.compiled_iseq_count);
-    fprintf(stderr, "inline_code_size:      %10d\n", cb->write_pos);
-    fprintf(stderr, "outlined_code_size:    %10d\n", ocb->write_pos);
-
-    fprintf(stderr, "total_exit_count:      %10" PRId64 "\n", total_exit_count);
-    fprintf(stderr, "total_insns_count:     %10" PRId64 "\n", total_insns_count);
-    fprintf(stderr, "vm_insns_count:        %10" PRId64 "\n", yjit_runtime_counters.vm_insns_count);
-    fprintf(stderr, "yjit_insns_count:      %10" PRId64 "\n", yjit_runtime_counters.exec_instruction);
-    fprintf(stderr, "ratio_in_yjit:         %9.1f%%\n", ratio * 100);
-    fprintf(stderr, "avg_len_in_yjit:       %10.1f\n", avg_len_in_yjit);
-
-    // Print the top-N most frequent exit ops
-    print_insn_count_buffer(20, 4);
-}
-#endif // if RUBY_DEBUG
-
 void
 rb_yjit_iseq_mark(const struct rb_iseq_constant_body *body)
 {
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]