Skip to content

Support setting the MMTk plan as a flag #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#error MMTk does not use transient heap.
#endif // USE_TRANSIENT_HEAP
#include "mmtk.h"
#include "internal/cmdlineopt.h"

RubyUpcalls ruby_upcalls;
#endif
Expand Down Expand Up @@ -156,6 +157,13 @@ RubyUpcalls ruby_upcalls;
#define MAP_ANONYMOUS MAP_ANON
#endif

#ifdef USE_THIRD_PARTY_HEAP
static char *mmtk_env_plan = NULL;
static char *mmtk_pre_arg_plan = NULL;
static char *mmtk_post_arg_plan = NULL;
static char *mmtk_chosen_plan = NULL;
#endif

static inline struct rbimpl_size_mul_overflow_tag
size_add_overflow(size_t x, size_t y)
{
Expand Down Expand Up @@ -1442,7 +1450,7 @@ asan_poison_object_restore(VALUE obj, void *ptr)
#define FL_SET2(x,f) FL_CHECK2("FL_SET2", x, RBASIC(x)->flags |= (f))
#define FL_UNSET2(x,f) FL_CHECK2("FL_UNSET2", x, RBASIC(x)->flags &= ~(f))

// Comment for easy location
// Comment for easy location
#ifdef USE_THIRD_PARTY_HEAP
#define RVALUE_MARK_BITMAP(obj) 0
#define RVALUE_PIN_BITMAP(obj) 0
Expand Down Expand Up @@ -1863,10 +1871,20 @@ rb_objspace_alloc(void)
dont_gc_on();

#ifdef USE_THIRD_PARTY_HEAP
if (!mmtk_env_plan && setenv("MMTK_PLAN", mmtk_chosen_plan, 0) != 0) {
fputs("[FATAL] could not set MMTK_PLAN\n", stderr);
exit(EXIT_FAILURE);
}

// Note: the limit is currently broken for NoGC, but we still attempt to
// initialise it properly regardless.
// See https://github.com/mmtk/mmtk-core/issues/214
mmtk_init_binding(rb_mmtk_heap_limit(), &ruby_upcalls);

if (!mmtk_env_plan && unsetenv("MMTK_PLAN") != 0) {
fputs("[FATAL] could not unset MMTK_PLAN\n", stderr);
exit(EXIT_FAILURE);
}
#endif

return objspace;
Expand Down Expand Up @@ -15092,4 +15110,93 @@ size_t rb_mmtk_heap_limit(void) {
}
}

void rb_mmtk_pre_process_opts(int argc, char **argv) {
bool enable_rubyopt = true;

mmtk_env_plan = getenv("MMTK_PLAN");

for (int n = 1; n < argc; n++) {
if (strcmp(argv[n], "--") == 0) {
break;
}
else if (strcmp(argv[n], "--enable-rubyopt") == 0
|| strcmp(argv[n], "--enable=rubyopt") == 0) {
enable_rubyopt = true;
}
else if (strcmp(argv[n], "--disable-rubyopt") == 0
|| strcmp(argv[n], "--disable=rubyopt") == 0) {
enable_rubyopt = false;
}
else if (strncmp(argv[n], "--mmtk-plan=", strlen("--mmtk-plan=")) == 0) {
mmtk_pre_arg_plan = argv[n] + strlen("--mmtk-plan=");
}
}

if (enable_rubyopt) {
char *env_args = getenv("RUBYOPT");
if (env_args != NULL) {
while (*env_args != '\0') {
if (ISSPACE(*env_args)) {
env_args++;
}
else {
size_t length = 0;
while (env_args[length] != '\0' && !ISSPACE(env_args[length])) {
length++;
}

if (strncmp(env_args, "--mmtk-plan=", strlen("--mmtk-plan=")) == 0) {
mmtk_pre_arg_plan = strndup(env_args + strlen("--mmtk-plan="), length - strlen("--mmtk-plan="));
if (mmtk_pre_arg_plan == NULL) {
rb_bug("could not allocate space for argument");
}
}

env_args += length;
}
}
}
}

if (enable_rubyopt && mmtk_env_plan && mmtk_pre_arg_plan && strcmp(mmtk_env_plan, mmtk_pre_arg_plan) != 0) {
fputs("[FATAL] MMTK_PLAN and --mmtk-plan do not agree\n", stderr);
exit(EXIT_FAILURE);
}

if (enable_rubyopt && mmtk_env_plan) {
mmtk_chosen_plan = mmtk_env_plan;
}
else if (mmtk_pre_arg_plan) {
mmtk_chosen_plan = mmtk_pre_arg_plan;
}
else {
mmtk_chosen_plan = MMTK_DEFAULT_PLAN;
}
}

#define opt_match_noarg(s, l, name) \
opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --mmtk-" name " is ignored"), 1) : 1)
#define opt_match_arg(s, l, name) \
opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--mmtk-" name " needs an argument"), 0))

void rb_mmtk_post_process_opts(char *s) {
const size_t l = strlen(s);
if (l == 0) {
return;
}
if (opt_match_arg(s, l, "plan")) {
mmtk_post_arg_plan = s + 1;
}
else {
rb_raise(rb_eRuntimeError,
"invalid MMTk option `%s' (--help will show valid MMTk options)", s);
}
}

void rb_mmtk_post_process_opts_finish(void) {
if (strcmp(mmtk_pre_arg_plan ? mmtk_pre_arg_plan : "", mmtk_post_arg_plan ? mmtk_post_arg_plan : "") != 0) {
rb_raise(rb_eRuntimeError, "--mmtk-plan values disagree");
}
}

#endif
4 changes: 4 additions & 0 deletions gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ VALUE rb_gc_disable_no_rest(void);
struct rb_thread_struct;

#ifdef USE_THIRD_PARTY_HEAP
#define MMTK_DEFAULT_PLAN "MarkSweep"
void rb_gc_init_collection();
void rb_mmtk_pre_process_opts(int argc, char **argv);
void rb_mmtk_post_process_opts(char *arg);
void rb_mmtk_post_process_opts_finish(void);
#endif // USE_THIRD_PARTY_HEAP

RUBY_SYMBOL_EXPORT_BEGIN
Expand Down
7 changes: 7 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,17 @@
# undef RUBY_DEBUG_ENV
#endif

#ifdef USE_THIRD_PARTY_HEAP
#include "gc.h"
#endif

static int
rb_main(int argc, char **argv)
{
RUBY_INIT_STACK;
#ifdef USE_THIRD_PARTY_HEAP
rb_mmtk_pre_process_opts(argc, argv);
#endif
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
Expand Down
27 changes: 27 additions & 0 deletions ruby.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
#include "ruby/version.h"
#include "ruby/internal/error.h"

#ifdef USE_THIRD_PARTY_HEAP
#include "gc.h"
#endif

#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#endif
Expand Down Expand Up @@ -333,6 +337,11 @@ usage(const char *name, int help, int highlight, int columns)
M("--yjit-max-versions=num", "", "Maximum number of versions per basic block (default: 4)"),
M("--yjit-greedy-versioning", "", "Greedy versioning mode (default: disabled)"),
};
#endif
#ifdef USE_THIRD_PARTY_HEAP
static const struct ruby_opt_message mmtk_options[] = {
M("--mmtk-plan=name", "", "MMTk garbage collection plan to use (default: " MMTK_DEFAULT_PLAN ")"),
};
#endif
int i;
const char *sb = highlight ? esc_standout+1 : esc_none;
Expand Down Expand Up @@ -370,6 +379,11 @@ usage(const char *name, int help, int highlight, int columns)
for (i = 0; i < numberof(yjit_options); ++i)
SHOW(yjit_options[i]);
#endif
#ifdef USE_THIRD_PARTY_HEAP
printf("%s""MMTk options (experimental):%s\n", sb, se);
for (i = 0; i < numberof(mmtk_options); ++i)
SHOW(mmtk_options[i]);
#endif
}

#define rubylib_path_new rb_str_new
Expand Down Expand Up @@ -1439,6 +1453,15 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
setup_yjit_options(s);
#else
rb_warn("Ruby was built without YJIT support");
#endif
}
else if (is_option_with_optarg("mmtk", '-', true, false, false)) {
#ifdef USE_THIRD_PARTY_HEAP
rb_mmtk_post_process_opts(s);
#undef opt_match_noarg
#undef opt_match_arg
#else
rb_warn("Ruby was built without MMTk support");
#endif
}
else if (strcmp("yydebug", s) == 0) {
Expand Down Expand Up @@ -1805,6 +1828,10 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
FEATURE_SET_RESTORE(opt->warn, warn);
}

#ifdef USE_THIRD_PARTY_HEAP
rb_mmtk_post_process_opts_finish();
#endif

if (opt->src.enc.name)
/* cannot set deprecated category, as enabling deprecation warnings based on flags
* has not happened yet.
Expand Down
2 changes: 1 addition & 1 deletion test/lib/jit_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def eval_with_jit_without_retry(env = nil, script, verbose: 0, min_calls: 5, sav
end

def supported?
return false if RbConfig::CONFIG["CFLAGS"].include?("USE_THIRD_PARTY_HEAP")
return false if defined?(GC::MMTk)
return @supported if defined?(@supported)
@supported = RbConfig::CONFIG["MJIT_SUPPORT"] != 'no' && UNSUPPORTED_COMPILERS.all? do |regexp|
!regexp.match?(RbConfig::CONFIG['MJIT_CC'])
Expand Down
14 changes: 10 additions & 4 deletions version.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "yjit.h"
#include <stdio.h>

#ifdef USE_THIRD_PARTY_HEAP
#include "mmtk.h"
#endif

#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
Expand Down Expand Up @@ -48,7 +52,7 @@ const char ruby_copyright[] = RUBY_COPYRIGHT;
const char ruby_engine[] = "ruby";

// Enough space for any combination of option flags
static char ruby_dynamic_description_buffer[sizeof(ruby_description) + sizeof("+MJIT +YJIT +MMTk") - 1];
static char ruby_dynamic_description_buffer[sizeof(ruby_description) + sizeof("+MJIT +YJIT +MMTk(XXXXXXXXXXXXXXXX)") - 1];

// Might change after initialization
const char *rb_dynamic_description = ruby_description;
Expand Down Expand Up @@ -107,14 +111,16 @@ Init_version(void)
void
Init_ruby_description(void)
{
if (snprintf(ruby_dynamic_description_buffer, sizeof(ruby_dynamic_description_buffer), "%s%s%s%s%s",
if (snprintf(ruby_dynamic_description_buffer, sizeof(ruby_dynamic_description_buffer), "%s%s%s%s%s%s%s",
ruby_description_pre,
MJIT_OPTS_ON ? " +MJIT" : "",
rb_yjit_enabled_p() ? " +YJIT" : "",
#ifdef USE_THIRD_PARTY_HEAP
" +MMTk",
" +MMTk(",
mmtk_plan_name(),
")",
#else
"",
"", "", "",
#endif
ruby_description_post) < 0) {
rb_bug("could not format dynamic description string");
Expand Down
1 change: 1 addition & 0 deletions vm_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,7 @@ rb_vm_bugreport(const void *ctx)

#ifdef USE_THIRD_PARTY_HEAP
fprintf(stderr, "* MMTk:\n\n");
fprintf(stderr, " mmtk_plan_name: %s\n", mmtk_plan_name());
fprintf(stderr, " mmtk_free_bytes: %zu\n", mmtk_free_bytes());
fprintf(stderr, " mmtk_total_bytes: %zu\n", mmtk_total_bytes());
fprintf(stderr, " mmtk_used_bytes: %zu\n", mmtk_used_bytes());
Expand Down