Skip to content

Commit b9b78da

Browse files
authored
Support setting the MMTk plan as a flag (#7)
We can now select the MMTk plan using the `--mmtk-plan` command line option. The default plan is set to MarkSweep.
1 parent 7614cbe commit b9b78da

File tree

7 files changed

+158
-6
lines changed

7 files changed

+158
-6
lines changed

gc.c

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#error MMTk does not use transient heap.
4343
#endif // USE_TRANSIENT_HEAP
4444
#include "mmtk.h"
45+
#include "internal/cmdlineopt.h"
4546

4647
RubyUpcalls ruby_upcalls;
4748
#endif
@@ -156,6 +157,13 @@ RubyUpcalls ruby_upcalls;
156157
#define MAP_ANONYMOUS MAP_ANON
157158
#endif
158159

160+
#ifdef USE_THIRD_PARTY_HEAP
161+
static char *mmtk_env_plan = NULL;
162+
static char *mmtk_pre_arg_plan = NULL;
163+
static char *mmtk_post_arg_plan = NULL;
164+
static char *mmtk_chosen_plan = NULL;
165+
#endif
166+
159167
static inline struct rbimpl_size_mul_overflow_tag
160168
size_add_overflow(size_t x, size_t y)
161169
{
@@ -1442,7 +1450,7 @@ asan_poison_object_restore(VALUE obj, void *ptr)
14421450
#define FL_SET2(x,f) FL_CHECK2("FL_SET2", x, RBASIC(x)->flags |= (f))
14431451
#define FL_UNSET2(x,f) FL_CHECK2("FL_UNSET2", x, RBASIC(x)->flags &= ~(f))
14441452

1445-
// Comment for easy location
1453+
// Comment for easy location
14461454
#ifdef USE_THIRD_PARTY_HEAP
14471455
#define RVALUE_MARK_BITMAP(obj) 0
14481456
#define RVALUE_PIN_BITMAP(obj) 0
@@ -1863,10 +1871,20 @@ rb_objspace_alloc(void)
18631871
dont_gc_on();
18641872

18651873
#ifdef USE_THIRD_PARTY_HEAP
1874+
if (!mmtk_env_plan && setenv("MMTK_PLAN", mmtk_chosen_plan, 0) != 0) {
1875+
fputs("[FATAL] could not set MMTK_PLAN\n", stderr);
1876+
exit(EXIT_FAILURE);
1877+
}
1878+
18661879
// Note: the limit is currently broken for NoGC, but we still attempt to
18671880
// initialise it properly regardless.
18681881
// See https://github.com/mmtk/mmtk-core/issues/214
18691882
mmtk_init_binding(rb_mmtk_heap_limit(), &ruby_upcalls);
1883+
1884+
if (!mmtk_env_plan && unsetenv("MMTK_PLAN") != 0) {
1885+
fputs("[FATAL] could not unset MMTK_PLAN\n", stderr);
1886+
exit(EXIT_FAILURE);
1887+
}
18701888
#endif
18711889

18721890
return objspace;
@@ -15092,4 +15110,93 @@ size_t rb_mmtk_heap_limit(void) {
1509215110
}
1509315111
}
1509415112

15113+
void rb_mmtk_pre_process_opts(int argc, char **argv) {
15114+
bool enable_rubyopt = true;
15115+
15116+
mmtk_env_plan = getenv("MMTK_PLAN");
15117+
15118+
for (int n = 1; n < argc; n++) {
15119+
if (strcmp(argv[n], "--") == 0) {
15120+
break;
15121+
}
15122+
else if (strcmp(argv[n], "--enable-rubyopt") == 0
15123+
|| strcmp(argv[n], "--enable=rubyopt") == 0) {
15124+
enable_rubyopt = true;
15125+
}
15126+
else if (strcmp(argv[n], "--disable-rubyopt") == 0
15127+
|| strcmp(argv[n], "--disable=rubyopt") == 0) {
15128+
enable_rubyopt = false;
15129+
}
15130+
else if (strncmp(argv[n], "--mmtk-plan=", strlen("--mmtk-plan=")) == 0) {
15131+
mmtk_pre_arg_plan = argv[n] + strlen("--mmtk-plan=");
15132+
}
15133+
}
15134+
15135+
if (enable_rubyopt) {
15136+
char *env_args = getenv("RUBYOPT");
15137+
if (env_args != NULL) {
15138+
while (*env_args != '\0') {
15139+
if (ISSPACE(*env_args)) {
15140+
env_args++;
15141+
}
15142+
else {
15143+
size_t length = 0;
15144+
while (env_args[length] != '\0' && !ISSPACE(env_args[length])) {
15145+
length++;
15146+
}
15147+
15148+
if (strncmp(env_args, "--mmtk-plan=", strlen("--mmtk-plan=")) == 0) {
15149+
mmtk_pre_arg_plan = strndup(env_args + strlen("--mmtk-plan="), length - strlen("--mmtk-plan="));
15150+
if (mmtk_pre_arg_plan == NULL) {
15151+
rb_bug("could not allocate space for argument");
15152+
}
15153+
}
15154+
15155+
env_args += length;
15156+
}
15157+
}
15158+
}
15159+
}
15160+
15161+
if (enable_rubyopt && mmtk_env_plan && mmtk_pre_arg_plan && strcmp(mmtk_env_plan, mmtk_pre_arg_plan) != 0) {
15162+
fputs("[FATAL] MMTK_PLAN and --mmtk-plan do not agree\n", stderr);
15163+
exit(EXIT_FAILURE);
15164+
}
15165+
15166+
if (enable_rubyopt && mmtk_env_plan) {
15167+
mmtk_chosen_plan = mmtk_env_plan;
15168+
}
15169+
else if (mmtk_pre_arg_plan) {
15170+
mmtk_chosen_plan = mmtk_pre_arg_plan;
15171+
}
15172+
else {
15173+
mmtk_chosen_plan = MMTK_DEFAULT_PLAN;
15174+
}
15175+
}
15176+
15177+
#define opt_match_noarg(s, l, name) \
15178+
opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --mmtk-" name " is ignored"), 1) : 1)
15179+
#define opt_match_arg(s, l, name) \
15180+
opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--mmtk-" name " needs an argument"), 0))
15181+
15182+
void rb_mmtk_post_process_opts(char *s) {
15183+
const size_t l = strlen(s);
15184+
if (l == 0) {
15185+
return;
15186+
}
15187+
if (opt_match_arg(s, l, "plan")) {
15188+
mmtk_post_arg_plan = s + 1;
15189+
}
15190+
else {
15191+
rb_raise(rb_eRuntimeError,
15192+
"invalid MMTk option `%s' (--help will show valid MMTk options)", s);
15193+
}
15194+
}
15195+
15196+
void rb_mmtk_post_process_opts_finish(void) {
15197+
if (strcmp(mmtk_pre_arg_plan ? mmtk_pre_arg_plan : "", mmtk_post_arg_plan ? mmtk_post_arg_plan : "") != 0) {
15198+
rb_raise(rb_eRuntimeError, "--mmtk-plan values disagree");
15199+
}
15200+
}
15201+
1509515202
#endif

gc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ VALUE rb_gc_disable_no_rest(void);
119119
struct rb_thread_struct;
120120

121121
#ifdef USE_THIRD_PARTY_HEAP
122+
#define MMTK_DEFAULT_PLAN "MarkSweep"
122123
void rb_gc_init_collection();
124+
void rb_mmtk_pre_process_opts(int argc, char **argv);
125+
void rb_mmtk_post_process_opts(char *arg);
126+
void rb_mmtk_post_process_opts_finish(void);
123127
#endif // USE_THIRD_PARTY_HEAP
124128

125129
RUBY_SYMBOL_EXPORT_BEGIN

main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@
3030
# undef RUBY_DEBUG_ENV
3131
#endif
3232

33+
#ifdef USE_THIRD_PARTY_HEAP
34+
#include "gc.h"
35+
#endif
36+
3337
static int
3438
rb_main(int argc, char **argv)
3539
{
3640
RUBY_INIT_STACK;
41+
#ifdef USE_THIRD_PARTY_HEAP
42+
rb_mmtk_pre_process_opts(argc, argv);
43+
#endif
3744
ruby_init();
3845
return ruby_run_node(ruby_options(argc, argv));
3946
}

ruby.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@
6161
#include "ruby/version.h"
6262
#include "ruby/internal/error.h"
6363

64+
#ifdef USE_THIRD_PARTY_HEAP
65+
#include "gc.h"
66+
#endif
67+
6468
#ifndef MAXPATHLEN
6569
# define MAXPATHLEN 1024
6670
#endif
@@ -333,6 +337,11 @@ usage(const char *name, int help, int highlight, int columns)
333337
M("--yjit-max-versions=num", "", "Maximum number of versions per basic block (default: 4)"),
334338
M("--yjit-greedy-versioning", "", "Greedy versioning mode (default: disabled)"),
335339
};
340+
#endif
341+
#ifdef USE_THIRD_PARTY_HEAP
342+
static const struct ruby_opt_message mmtk_options[] = {
343+
M("--mmtk-plan=name", "", "MMTk garbage collection plan to use (default: " MMTK_DEFAULT_PLAN ")"),
344+
};
336345
#endif
337346
int i;
338347
const char *sb = highlight ? esc_standout+1 : esc_none;
@@ -370,6 +379,11 @@ usage(const char *name, int help, int highlight, int columns)
370379
for (i = 0; i < numberof(yjit_options); ++i)
371380
SHOW(yjit_options[i]);
372381
#endif
382+
#ifdef USE_THIRD_PARTY_HEAP
383+
printf("%s""MMTk options (experimental):%s\n", sb, se);
384+
for (i = 0; i < numberof(mmtk_options); ++i)
385+
SHOW(mmtk_options[i]);
386+
#endif
373387
}
374388

375389
#define rubylib_path_new rb_str_new
@@ -1439,6 +1453,15 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
14391453
setup_yjit_options(s);
14401454
#else
14411455
rb_warn("Ruby was built without YJIT support");
1456+
#endif
1457+
}
1458+
else if (is_option_with_optarg("mmtk", '-', true, false, false)) {
1459+
#ifdef USE_THIRD_PARTY_HEAP
1460+
rb_mmtk_post_process_opts(s);
1461+
#undef opt_match_noarg
1462+
#undef opt_match_arg
1463+
#else
1464+
rb_warn("Ruby was built without MMTk support");
14421465
#endif
14431466
}
14441467
else if (strcmp("yydebug", s) == 0) {
@@ -1805,6 +1828,10 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
18051828
FEATURE_SET_RESTORE(opt->warn, warn);
18061829
}
18071830

1831+
#ifdef USE_THIRD_PARTY_HEAP
1832+
rb_mmtk_post_process_opts_finish();
1833+
#endif
1834+
18081835
if (opt->src.enc.name)
18091836
/* cannot set deprecated category, as enabling deprecation warnings based on flags
18101837
* has not happened yet.

test/lib/jit_support.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def eval_with_jit_without_retry(env = nil, script, verbose: 0, min_calls: 5, sav
5656
end
5757

5858
def supported?
59-
return false if RbConfig::CONFIG["CFLAGS"].include?("USE_THIRD_PARTY_HEAP")
59+
return false if defined?(GC::MMTk)
6060
return @supported if defined?(@supported)
6161
@supported = RbConfig::CONFIG["MJIT_SUPPORT"] != 'no' && UNSUPPORTED_COMPILERS.all? do |regexp|
6262
!regexp.match?(RbConfig::CONFIG['MJIT_CC'])

version.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
#include "yjit.h"
1717
#include <stdio.h>
1818

19+
#ifdef USE_THIRD_PARTY_HEAP
20+
#include "mmtk.h"
21+
#endif
22+
1923
#ifndef EXIT_SUCCESS
2024
#define EXIT_SUCCESS 0
2125
#endif
@@ -48,7 +52,7 @@ const char ruby_copyright[] = RUBY_COPYRIGHT;
4852
const char ruby_engine[] = "ruby";
4953

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

5357
// Might change after initialization
5458
const char *rb_dynamic_description = ruby_description;
@@ -107,14 +111,16 @@ Init_version(void)
107111
void
108112
Init_ruby_description(void)
109113
{
110-
if (snprintf(ruby_dynamic_description_buffer, sizeof(ruby_dynamic_description_buffer), "%s%s%s%s%s",
114+
if (snprintf(ruby_dynamic_description_buffer, sizeof(ruby_dynamic_description_buffer), "%s%s%s%s%s%s%s",
111115
ruby_description_pre,
112116
MJIT_OPTS_ON ? " +MJIT" : "",
113117
rb_yjit_enabled_p() ? " +YJIT" : "",
114118
#ifdef USE_THIRD_PARTY_HEAP
115-
" +MMTk",
119+
" +MMTk(",
120+
mmtk_plan_name(),
121+
")",
116122
#else
117-
"",
123+
"", "", "",
118124
#endif
119125
ruby_description_post) < 0) {
120126
rb_bug("could not format dynamic description string");

vm_dump.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,7 @@ rb_vm_bugreport(const void *ctx)
11961196

11971197
#ifdef USE_THIRD_PARTY_HEAP
11981198
fprintf(stderr, "* MMTk:\n\n");
1199+
fprintf(stderr, " mmtk_plan_name: %s\n", mmtk_plan_name());
11991200
fprintf(stderr, " mmtk_free_bytes: %zu\n", mmtk_free_bytes());
12001201
fprintf(stderr, " mmtk_total_bytes: %zu\n", mmtk_total_bytes());
12011202
fprintf(stderr, " mmtk_used_bytes: %zu\n", mmtk_used_bytes());

0 commit comments

Comments
 (0)