ruby-changes:59015
From: Takashi <ko1@a...>
Date: Sun, 1 Dec 2019 18:00:12 +0900 (JST)
Subject: [ruby-changes:59015] a19d625e66 (master): Allow specifying arbitrary MJIT flags by --jit-debug
https://git.ruby-lang.org/ruby.git/commit/?id=a19d625e66 From a19d625e667024fe27dcee04dd748e914bc24762 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun <takashikkbn@g...> Date: Sun, 1 Dec 2019 00:56:27 -0800 Subject: Allow specifying arbitrary MJIT flags by --jit-debug This is a secret feature for me. It's only for testing and any behavior with this flag override is unsupported. I needed this because I sometimes want to add debug options but do not want to disable optimizations, for using Linux perf. diff --git a/mjit.c b/mjit.c index f1e3934..5749f21 100644 --- a/mjit.c +++ b/mjit.c @@ -700,6 +700,33 @@ start_worker(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L700 return true; } +// Convert "foo bar" to {"foo", "bar", NULL} array. Caller is responsible for +// freeing a returned buffer and its elements. +static char ** +split_flags(char *flags) +{ + char *buf[MAXPATHLEN]; + int i = 0; + char *next; + for (; flags != NULL; flags = next) { + next = strchr(flags, ' '); + if (next == NULL) { + if (strlen(flags) > 0) + buf[i++] = strdup(flags); + } + else { + if (next > flags) + buf[i++] = strndup(flags, next - flags); + next++; // skip space + } + } + buf[i] = NULL; + + char **ret = xmalloc(sizeof(char **) * i); + memcpy((void *)ret, buf, sizeof(char **) * i); + return ret; +} + // Initialize MJIT. Start a thread creating the precompiled header and // processing ISeqs. The function should be called first for using MJIT. // If everything is successful, MJIT_INIT_P will be TRUE. @@ -728,6 +755,8 @@ mjit_init(struct mjit_options *opts) https://github.com/ruby/ruby/blob/trunk/mjit.c#L755 verbose(2, "MJIT: CC defaults to %s", cc_path); cc_common_args = xmalloc(sizeof(CC_COMMON_ARGS)); memcpy((void *)cc_common_args, CC_COMMON_ARGS, sizeof(CC_COMMON_ARGS)); + cc_added_args = split_flags(opts->debug_flags); + xfree(opts->debug_flags); #if MJIT_CFLAGS_PIPE { // eliminate a flag incompatible with `-pipe` size_t i, j; @@ -921,6 +950,9 @@ mjit_finish(bool close_handle_p) https://github.com/ruby/ruby/blob/trunk/mjit.c#L950 xfree(header_file); header_file = NULL; #endif xfree((void *)cc_common_args); cc_common_args = NULL; + for (char **flag = cc_added_args; *flag != NULL; flag++) + xfree(*flag); + xfree((void *)cc_added_args); cc_added_args = NULL; xfree(tmp_dir); tmp_dir = NULL; xfree(pch_file); pch_file = NULL; diff --git a/mjit.h b/mjit.h index e89a2b9..ff16c0f 100644 --- a/mjit.h +++ b/mjit.h @@ -43,6 +43,8 @@ struct mjit_options { https://github.com/ruby/ruby/blob/trunk/mjit.h#L43 // Disable compiler optimization and add debug symbols. It can be // very slow. char debug; + // Add arbitrary cflags. + char* debug_flags; // If not 0, all ISeqs are synchronously compiled. For testing. unsigned int wait; // Number of calls to trigger JIT compilation. For testing. diff --git a/mjit_worker.c b/mjit_worker.c index b23baf6..ce8133a 100644 --- a/mjit_worker.c +++ b/mjit_worker.c @@ -221,6 +221,8 @@ static VALUE valid_class_serials; https://github.com/ruby/ruby/blob/trunk/mjit_worker.c#L221 static const char *cc_path; // Used C compiler flags. static const char **cc_common_args; +// Used C compiler flags added by --jit-debug=... +static char **cc_added_args; // Name of the precompiled header file. static char *pch_file; // The process id which should delete the pch_file on mjit_finish. @@ -759,7 +761,7 @@ make_pch(void) https://github.com/ruby/ruby/blob/trunk/mjit_worker.c#L761 }; verbose(2, "Creating precompiled header"); - char **args = form_args(3, cc_common_args, CC_CODEFLAG_ARGS, rest_args); + char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, rest_args); if (args == NULL) { mjit_warning("making precompiled header failed on forming args"); CRITICAL_SECTION_START(3, "in make_pch"); @@ -796,7 +798,7 @@ compile_c_to_o(const char *c_file, const char *o_file) https://github.com/ruby/ruby/blob/trunk/mjit_worker.c#L798 "-c", NULL }; - char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, files, CC_LINKER_ARGS); + char **args = form_args(5, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, files, CC_LINKER_ARGS); if (args == NULL) return false; diff --git a/ruby.c b/ruby.c index 6edc5c4..69963e3 100644 --- a/ruby.c +++ b/ruby.c @@ -298,7 +298,7 @@ usage(const char *name, int help) https://github.com/ruby/ruby/blob/trunk/ruby.c#L298 }; static const struct message mjit_options[] = { M("--jit-warnings", "", "Enable printing JIT warnings"), - M("--jit-debug", "", "Enable JIT debugging (very slow)"), + M("--jit-debug", "", "Enable JIT debugging (very slow), or add cflags if specified"), M("--jit-wait", "", "Wait until JIT compilation is finished everytime (for testing)"), M("--jit-save-temps", "", "Save JIT temporary files in $TMP or /tmp (for testing)"), M("--jit-verbose=num", "", "Print JIT logs of level num or less to stderr (default: 0)"), @@ -969,6 +969,9 @@ setup_mjit_options(const char *s, struct mjit_options *mjit_opt) https://github.com/ruby/ruby/blob/trunk/ruby.c#L969 else if (strcmp(s, "-warnings") == 0) { mjit_opt->warnings = 1; } + else if (strncmp(s, "-debug=", 7) == 0) { + mjit_opt->debug_flags = strdup(s + 7); + } else if (strcmp(s, "-debug") == 0) { mjit_opt->debug = 1; } diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index 10d5455..abdacc5 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -1043,6 +1043,12 @@ class TestRubyOptions < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_rubyoptions.rb#L1043 assert_in_out_err([IO::NULL], success: true) end + def test_jit_debug + if JITSupport.supported? + assert_in_out_err(["--jit-debug=-O0 -O1", "--jit-verbose=2", ""], "", [], /-O0 -O1/) + end + end + private def mjit_force_enabled? -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/