Skip to content

Commit e90492d

Browse files
committed
[GR-15990] Add option to run a workload twice with a shared engine
PullRequest: truffleruby/2769
2 parents dcb76d1 + ae3d416 commit e90492d

File tree

5 files changed

+62
-24
lines changed

5 files changed

+62
-24
lines changed

src/launcher/java/org/truffleruby/launcher/RubyLauncher.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,34 @@ private int runRubyMain(Context.Builder contextBuilder, CommandLineOptions confi
201201
return 0;
202202
}
203203

204-
try (Context context = createContext(contextBuilder, config)) {
204+
if (config.isGemOrBundle() && getImplementationNameFromEngine().contains("Graal")) {
205+
// Apply options to run gem/bundle more efficiently
206+
contextBuilder.option("engine.Mode", "latency");
207+
if (Boolean.getBoolean("truffleruby.launcher.log")) {
208+
System.err.println("[ruby] CONFIG: detected gem or bundle command, using --engine.Mode=latency");
209+
}
210+
}
211+
212+
contextBuilder.options(config.getOptions());
213+
214+
contextBuilder.arguments(TruffleRuby.LANGUAGE_ID, config.getArguments());
215+
216+
int result = runContext(contextBuilder, config);
217+
218+
final boolean runTwice = config.getUnknownArguments().contains("--run-twice") ||
219+
config.getUnknownArguments().contains("--run-twice=true");
220+
if (runTwice) {
221+
final int secondResult = runContext(contextBuilder, config);
222+
if (secondResult != 0 && result == 0) {
223+
result = secondResult;
224+
}
225+
}
226+
227+
return result;
228+
}
229+
230+
private int runContext(Context.Builder builder, CommandLineOptions config) {
231+
try (Context context = builder.build()) {
205232
Metrics.printTime("before-run");
206233

207234
if (config.executionAction == ExecutionAction.PATH) {
@@ -244,22 +271,6 @@ private int runRubyMain(Context.Builder contextBuilder, CommandLineOptions confi
244271
}
245272
}
246273

247-
private Context createContext(Context.Builder builder, CommandLineOptions config) {
248-
if (config.isGemOrBundle() && getImplementationNameFromEngine().contains("Graal")) {
249-
// Apply options to run gem/bundle more efficiently
250-
builder.option("engine.Mode", "latency");
251-
if (Boolean.getBoolean("truffleruby.launcher.log")) {
252-
System.err.println("[ruby] CONFIG: detected gem or bundle command, using --engine.Mode=latency");
253-
}
254-
}
255-
256-
builder.options(config.getOptions());
257-
258-
builder.arguments(TruffleRuby.LANGUAGE_ID, config.getArguments());
259-
260-
return builder.build();
261-
}
262-
263274
private static List<String> getArgsFromEnvVariable(String name) {
264275
String value = System.getenv(name);
265276
if (value != null) {

src/main/java/org/truffleruby/RubyLanguage.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,11 +653,12 @@ private boolean checkAreOptionsCompatible(OptionValues firstOptions, OptionValue
653653
if (singleContext) {
654654
return false;
655655
}
656-
if (!firstOptions.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY) ||
657-
!newOptions.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY)) {
656+
657+
if (options.RUN_TWICE || options.EXPERIMENTAL_ENGINE_CACHING) {
658+
return LanguageOptions.areOptionsCompatible(firstOptions, newOptions);
659+
} else {
658660
return false;
659661
}
660-
return LanguageOptions.areOptionsCompatible(firstOptions, newOptions);
661662
}
662663

663664
/** {@link RubyLanguage#getSourcePath(Source)} should be used instead whenever possible (i.e., when we can access

src/main/java/org/truffleruby/options/LanguageOptions.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ public class LanguageOptions {
122122
public final boolean SHARED_OBJECTS_DEBUG;
123123
/** --shared-objects-force=false */
124124
public final boolean SHARED_OBJECTS_FORCE;
125-
/** --experimental-engine-caching=false */
125+
/** --run-twice=false */
126+
public final boolean RUN_TWICE;
127+
/** --experimental-engine-caching=RUN_TWICE */
126128
public final boolean EXPERIMENTAL_ENGINE_CACHING;
127129

128130
public LanguageOptions(Env env, OptionValues options, boolean singleContext) {
@@ -176,7 +178,8 @@ public LanguageOptions(Env env, OptionValues options, boolean singleContext) {
176178
SHARED_OBJECTS_ENABLED = options.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY);
177179
SHARED_OBJECTS_DEBUG = options.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY);
178180
SHARED_OBJECTS_FORCE = options.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY);
179-
EXPERIMENTAL_ENGINE_CACHING = options.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY);
181+
RUN_TWICE = options.get(OptionsCatalog.RUN_TWICE_KEY);
182+
EXPERIMENTAL_ENGINE_CACHING = options.hasBeenSet(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY) ? options.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY) : RUN_TWICE;
180183
}
181184

182185
public Object fromDescriptor(OptionDescriptor descriptor) {
@@ -281,6 +284,8 @@ public Object fromDescriptor(OptionDescriptor descriptor) {
281284
return SHARED_OBJECTS_DEBUG;
282285
case "ruby.shared-objects-force":
283286
return SHARED_OBJECTS_FORCE;
287+
case "ruby.run-twice":
288+
return RUN_TWICE;
284289
case "ruby.experimental-engine-caching":
285290
return EXPERIMENTAL_ENGINE_CACHING;
286291
default:
@@ -339,6 +344,7 @@ public static boolean areOptionsCompatible(OptionValues one, OptionValues two) {
339344
one.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY)) &&
340345
one.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY)) &&
341346
one.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY)) &&
347+
one.get(OptionsCatalog.RUN_TWICE_KEY).equals(two.get(OptionsCatalog.RUN_TWICE_KEY)) &&
342348
one.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY).equals(two.get(OptionsCatalog.EXPERIMENTAL_ENGINE_CACHING_KEY));
343349
}
344350

@@ -696,6 +702,13 @@ public static boolean areOptionsCompatibleOrLog(TruffleLogger logger, LanguageOp
696702
return false;
697703
}
698704

705+
oldValue = oldOptions.RUN_TWICE;
706+
newValue = newOptions.RUN_TWICE;
707+
if (!newValue.equals(oldValue)) {
708+
logger.fine("not reusing pre-initialized context: --run-twice differs, was: " + oldValue + " and is now: " + newValue);
709+
return false;
710+
}
711+
699712
oldValue = oldOptions.EXPERIMENTAL_ENGINE_CACHING;
700713
newValue = newOptions.EXPERIMENTAL_ENGINE_CACHING;
701714
if (!newValue.equals(oldValue)) {

src/options.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ LANGUAGE_OPTIONS:
5151
- ARRAY_DUP_CACHE
5252
- ARRAY_STRATEGY_CACHE
5353
- EXPERIMENTAL_ENGINE_CACHING
54+
- RUN_TWICE
5455

5556
USER:
5657
STABLE:
@@ -248,7 +249,8 @@ INTERNAL: # Options for debugging the TruffleRuby implementation
248249

249250
# Options for testing
250251
TESTING_RUBYGEMS: [testing-rubygems, boolean, false, 'Indicates rubygems is being tested']
251-
EXPERIMENTAL_ENGINE_CACHING: [experimental-engine-caching, boolean, false, 'Enables experimental support for engine caching for TruffleRuby']
252+
RUN_TWICE: [run-twice, boolean, false, 'Run a workload twice using a shared engine in the same process']
253+
EXPERIMENTAL_ENGINE_CACHING: [experimental-engine-caching, boolean, RUN_TWICE, 'Enables experimental support for engine caching for TruffleRuby']
252254

253255
# Options for the regular expression engines
254256
COMPARE_REGEX_ENGINES: [compare-regex-engines, boolean, false, 'Uses both Joni and the TRegex engine and compares their results']

src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ public class OptionsCatalog {
157157
public static final OptionKey<Boolean> SHARED_OBJECTS_DEBUG_KEY = new OptionKey<>(false);
158158
public static final OptionKey<Boolean> SHARED_OBJECTS_FORCE_KEY = new OptionKey<>(false);
159159
public static final OptionKey<Boolean> TESTING_RUBYGEMS_KEY = new OptionKey<>(false);
160-
public static final OptionKey<Boolean> EXPERIMENTAL_ENGINE_CACHING_KEY = new OptionKey<>(false);
160+
public static final OptionKey<Boolean> RUN_TWICE_KEY = new OptionKey<>(false);
161+
public static final OptionKey<Boolean> EXPERIMENTAL_ENGINE_CACHING_KEY = new OptionKey<>(RUN_TWICE_KEY.getDefaultValue());
161162
public static final OptionKey<Boolean> COMPARE_REGEX_ENGINES_KEY = new OptionKey<>(false);
162163

163164
public static final OptionDescriptor LOAD_PATHS = OptionDescriptor
@@ -1119,6 +1120,13 @@ public class OptionsCatalog {
11191120
.stability(OptionStability.EXPERIMENTAL)
11201121
.build();
11211122

1123+
public static final OptionDescriptor RUN_TWICE = OptionDescriptor
1124+
.newBuilder(RUN_TWICE_KEY, "ruby.run-twice")
1125+
.help("Run a workload twice using a shared engine in the same process")
1126+
.category(OptionCategory.INTERNAL)
1127+
.stability(OptionStability.EXPERIMENTAL)
1128+
.build();
1129+
11221130
public static final OptionDescriptor EXPERIMENTAL_ENGINE_CACHING = OptionDescriptor
11231131
.newBuilder(EXPERIMENTAL_ENGINE_CACHING_KEY, "ruby.experimental-engine-caching")
11241132
.help("Enables experimental support for engine caching for TruffleRuby")
@@ -1409,6 +1417,8 @@ public static OptionDescriptor fromName(String name) {
14091417
return SHARED_OBJECTS_FORCE;
14101418
case "ruby.testing-rubygems":
14111419
return TESTING_RUBYGEMS;
1420+
case "ruby.run-twice":
1421+
return RUN_TWICE;
14121422
case "ruby.experimental-engine-caching":
14131423
return EXPERIMENTAL_ENGINE_CACHING;
14141424
case "ruby.compare-regex-engines":
@@ -1557,6 +1567,7 @@ public static OptionDescriptor[] allDescriptors() {
15571567
SHARED_OBJECTS_DEBUG,
15581568
SHARED_OBJECTS_FORCE,
15591569
TESTING_RUBYGEMS,
1570+
RUN_TWICE,
15601571
EXPERIMENTAL_ENGINE_CACHING,
15611572
COMPARE_REGEX_ENGINES,
15621573
};

0 commit comments

Comments
 (0)