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

ruby-changes:68912

From: Alan <ko1@a...>
Date: Thu, 21 Oct 2021 08:13:09 +0900 (JST)
Subject: [ruby-changes:68912] b7f93e81df (master): Implement --ujit-stats and instructoin counting

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

From b7f93e81dfe6864273707172be92896b54b6053e Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Tue, 26 Jan 2021 15:21:47 -0500
Subject: Implement --ujit-stats and instructoin counting

VM and ujit instruction counting in debug builds.

shopify/ruby#19
---
 ruby.c          | 27 ++++++++++++++++++++++-----
 ujit.h          |  7 ++++++-
 ujit_codegen.c  |  5 +++++
 ujit_iface.c    | 38 ++++++++++++++++++++++++++++++++------
 ujit_iface.h    |  3 +++
 vm.c            | 13 +++++++++++++
 vm_insnhelper.h |  5 +++++
 7 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/ruby.c b/ruby.c
index e8a4d4735b..55d5bf090c 100644
--- a/ruby.c
+++ b/ruby.c
@@ -189,6 +189,8 @@ struct ruby_cmdline_options { https://github.com/ruby/ruby/blob/trunk/ruby.c#L189
 #if USE_MJIT
     struct mjit_options mjit;
 #endif
+    struct rb_ujit_options ujit;
+
     int sflag, xflag;
     unsigned int warning: 1;
     unsigned int verbose: 1;
@@ -1018,10 +1020,6 @@ set_option_encoding_once(const char *type, VALUE *name, const char *e, long elen https://github.com/ruby/ruby/blob/trunk/ruby.c#L1020
 #define set_source_encoding_once(opt, e, elen) \
     set_option_encoding_once("source", &(opt)->src.enc.name, (e), (elen))
 
-#if USE_MJIT
-static void
-setup_mjit_options(const char *s, struct mjit_options *mjit_opt)
-{
 #define opt_match(s, l, name) \
     ((((l) > rb_strlen_lit(name)) ? (s)[rb_strlen_lit(name)] == '=' : \
       (l) == rb_strlen_lit(name)) && \
@@ -1031,6 +1029,24 @@ setup_mjit_options(const char *s, struct mjit_options *mjit_opt) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1029
     opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --jit-" name " is ignored"), 1) : 1)
 #define opt_match_arg(s, l, name) \
     opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--jit-" name " needs an argument"), 0))
+
+static void
+setup_ujit_options(const char *s, struct rb_ujit_options *ujit_opt)
+{
+    *ujit_opt = (struct rb_ujit_options) { 0 };
+
+    if (*s != '-') return;
+    const size_t l = strlen(++s);
+
+    if (opt_match_noarg(s, l, "stats")) {
+        ujit_opt->gen_stats = true;
+    }
+}
+
+#if USE_MJIT
+static void
+setup_mjit_options(const char *s, struct mjit_options *mjit_opt)
+{
     if (*s != '-') return;
     const size_t l = strlen(++s);
     if (*s == 0) return;
@@ -1442,6 +1458,7 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1458
             }
             else if (strncmp("ujit", s, 4) == 0) {
                 FEATURE_SET(opt->features, FEATURE_BIT(ujit));
+                setup_ujit_options(s + 4, &opt->ujit);
             }
 	    else if (strcmp("yydebug", s) == 0) {
 		if (envopt) goto noenvopt_long;
@@ -1804,7 +1821,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1821
         rb_warning("-K is specified; it is for 1.8 compatibility and may cause odd behavior");
 
     if (opt->features.set & FEATURE_BIT(ujit))
-        rb_ujit_init();
+        rb_ujit_init(&opt->ujit);
 #if USE_MJIT
     if (opt->features.set & FEATURE_BIT(jit)) {
         opt->mjit.on = TRUE; /* set mjit.on for ruby_show_version() API and check to call mjit_init() */
diff --git a/ujit.h b/ujit.h
index 04c8dcae29..9186714387 100644
--- a/ujit.h
+++ b/ujit.h
@@ -31,6 +31,10 @@ typedef struct rb_iseq_struct rb_iseq_t; https://github.com/ruby/ruby/blob/trunk/ujit.h#L31
 #define rb_iseq_t rb_iseq_t
 #endif
 
+struct rb_ujit_options {
+    bool gen_stats;
+};
+
 RUBY_SYMBOL_EXPORT_BEGIN
 RUBY_EXTERN bool rb_ujit_enabled;
 RUBY_SYMBOL_EXPORT_END
@@ -44,8 +48,9 @@ bool rb_ujit_enabled_p(void) https://github.com/ruby/ruby/blob/trunk/ujit.h#L48
 // Threshold==1 means compile on first execution
 #define UJIT_CALL_THRESHOLD (2u)
 
+void rb_ujit_collect_vm_usage_insn(int insn);
 void rb_ujit_method_lookup_change(VALUE cme_or_cc);
 void rb_ujit_compile_iseq(const rb_iseq_t *iseq);
-void rb_ujit_init(void);
+void rb_ujit_init(struct rb_ujit_options *options);
 
 #endif // #ifndef UJIT_H
diff --git a/ujit_codegen.c b/ujit_codegen.c
index 7c7866f403..010e98ae86 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -179,6 +179,11 @@ ujit_gen_block(ctx_t* ctx, block_t* block) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L179
             break;
         }
 
+#if RUBY_DEBUG
+        mov(cb, REG0, const_ptr_opnd((void *)&rb_ujit_exec_insns_count));
+        add(cb, mem_opnd(64, REG0, 0), imm_opnd(1));
+#endif
+
         //fprintf(stderr, "compiling %d: %s\n", insn_idx, insn_name(opcode));
         //print_str(cb, insn_name(opcode));
 
diff --git a/ujit_iface.c b/ujit_iface.c
index 3eb134a3bc..2237d37f5f 100644
--- a/ujit_iface.c
+++ b/ujit_iface.c
@@ -23,8 +23,17 @@ VALUE cUjitBlock; https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L23
 VALUE cUjitDisasm;
 VALUE cUjitDisasmInsn;
 
+bool rb_ujit_enabled;
+
+static int64_t vm_insns_count = 0;
+int64_t rb_ujit_exec_insns_count = 0;
+
 extern st_table * version_tbl;
 extern codeblock_t *cb;
+// Hash table of encoded instructions
+extern st_table *rb_encoded_insn_data;
+
+struct rb_ujit_options rb_ujit_opts;
 
 static const rb_data_type_t ujit_block_type = {
     "UJIT/Block",
@@ -32,11 +41,6 @@ static const rb_data_type_t ujit_block_type = { https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L41
     0, 0, RUBY_TYPED_FREE_IMMEDIATELY
 };
 
-bool rb_ujit_enabled;
-
-// Hash table of encoded instructions
-extern st_table *rb_encoded_insn_data;
-
 // Write the uJIT entry point pre-call bytes
 void 
 cb_write_pre_call_bytes(codeblock_t* cb)
@@ -412,14 +416,36 @@ ujit_disasm(VALUE self, VALUE code, VALUE from) https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L416
 }
 #endif
 
+__attribute__((destructor))
+static void
+print_ujit_stats(void)
+{
+    if (rb_ujit_opts.gen_stats) {
+        double double_ujit_exec_insns_count = rb_ujit_exec_insns_count;
+        double total_insns_count = vm_insns_count + rb_ujit_exec_insns_count;
+        double ratio = double_ujit_exec_insns_count / total_insns_count;
+
+        fprintf(stderr, "vm_insns_count:        %10" PRId64 "\n", vm_insns_count);
+        fprintf(stderr, "ujit_exec_insns_count: %10" PRId64 "\n", rb_ujit_exec_insns_count);
+        fprintf(stderr, "ratio_in_ujit:         %9.1f%%\n", ratio * 100);
+    }
+}
+
+void rb_ujit_collect_vm_usage_insn(int insn)
+{
+    vm_insns_count++;
+}
+
 void
-rb_ujit_init(void)
+rb_ujit_init(struct rb_ujit_options *options)
 {
     if (!ujit_scrape_successful || !PLATFORM_SUPPORTED_P)
     {
         return;
     }
 
+    rb_ujit_opts = *options;
+
     rb_ujit_enabled = true;
 
     ujit_init_core();
diff --git a/ujit_iface.h b/ujit_iface.h
index aa335dbf19..597b0cbbb5 100644
--- a/ujit_iface.h
+++ b/ujit_iface.h
@@ -20,6 +20,9 @@ struct rb_callcache; https://github.com/ruby/ruby/blob/trunk/ujit_iface.h#L20
 #define rb_callcache rb_callcache
 #endif
 
+RUBY_EXTERN struct rb_ujit_options rb_ujit_opts;
+RUBY_EXTERN int64_t rb_ujit_exec_insns_count;
+
 void cb_write_pre_call_bytes(codeblock_t* cb);
 void cb_write_post_call_bytes(codeblock_t* cb);
 
diff --git a/vm.c b/vm.c
index 03813db448..1fb366f882 100644
--- a/vm.c
+++ b/vm.c
@@ -37,6 +37,7 @@ https://github.com/ruby/ruby/blob/trunk/vm.c#L37
 #include "vm_insnhelper.h"
 #include "ractor_core.h"
 #include "vm_sync.h"
+#include "ujit.h"
 
 #include "builtin.h"
 
@@ -344,6 +345,10 @@ static void vm_collect_usage_insn(int insn); https://github.com/ruby/ruby/blob/trunk/vm.c#L345
 static void vm_collect_usage_register(int reg, int isset);
 #endif
 
+#if RUBY_DEBUG
+static void vm_ujit_collect_usage_insn(int insn);
+#endif
+
 static VALUE vm_make_env_object(const rb_execution_context_t *ec, rb_control_frame_t *cfp);
 extern VALUE rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
                                   int argc, const VALUE *argv, int kw_splat, VALUE block_handler,
@@ -4054,6 +4059,14 @@ MAYBE_UNUSED(static void (*ruby_vm_collect_usage_func_register)(int reg, int iss https://github.com/ruby/ruby/blob/trunk/vm.c#L4059
 
 #endif
 
+#if RUBY_DEBUG
+static void
+vm_ujit_collect_usage_insn(int insn)
+{
+    rb_ujit_collect_vm_usage_insn(insn);
+}
+#endif
+
 #if VM_COLLECT_USAGE_DETAILS
 /* @param insn instruction number */
 static void
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index 0d90eb9434..9c610304f8 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -25,6 +25,11 @@ MJIT_SYMBOL_EXPORT_END https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.h#L25
 #define COLLECT_USAGE_OPERAND(insn, n, op) vm_collect_usage_operand((insn), (n), ((VALUE)(op)))
 
 #define COLLECT_USAGE_REGISTER(reg, s)     vm_collect_usage_register((reg), (s))
+#elif RUBY_DEBUG
+/* for --ujit-stats */
+#define COLLECT_USAGE_INSN(insn)           vm_ujit_collect_usage_insn(insn)
+#define COLLECT_USAGE_OPERAND(insn, n, op)	/* none */
+#define COLLECT_USAGE_REGISTER(reg, s)		/* none */
 #else
 #define COLLECT_USAGE_INSN(insn)		/* none */
 #define COLLECT_USAGE_OPERAND(insn, n, op)	/* none */
-- 
cgit v1.2.1


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

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