1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package org.openjdk.jmh.runner.options; 26 27 import joptsimple.OptionException; 28 import joptsimple.OptionParser; 29 import joptsimple.OptionSet; 30 import joptsimple.OptionSpec; 31 import org.openjdk.jmh.annotations.Mode; 32 import org.openjdk.jmh.annotations.Threads; 33 import org.openjdk.jmh.profile.Profiler; 34 import org.openjdk.jmh.profile.ProfilerFactory; 35 import org.openjdk.jmh.results.format.ResultFormatType; 36 import org.openjdk.jmh.util.HashMultimap; 37 import org.openjdk.jmh.util.Multimap; 38 import org.openjdk.jmh.util.Optional; 39 40 import java.io.IOException; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Collection; 44 import java.util.HashSet; 45 import java.util.List; 46 import java.util.Set; 47 import java.util.concurrent.TimeUnit; 48 49 /** 50 * Class that handles all the command line options. 51 */ 52 public class CommandLineOptions implements Options { 53 private static final long serialVersionUID = 5565183446360224399L; 54 55 private final Optional<Integer> iterations; 56 private final Optional<TimeValue> runTime; 57 private final Optional<Integer> batchSize; 58 private final Optional<Integer> warmupIterations; 59 private final Optional<TimeValue> warmupTime; 60 private final Optional<Integer> warmupBatchSize; 61 private final List<Mode> benchMode = new ArrayList<Mode>(); 62 private final Optional<Integer> threads; 63 private final List<Integer> threadGroups = new ArrayList<Integer>(); 64 private final Optional<Boolean> synchIterations; 65 private final Optional<Boolean> gcEachIteration; 66 private final Optional<VerboseMode> verbose; 67 private final Optional<Boolean> failOnError; 68 private final Set<Class<? extends Profiler>> profilers = new HashSet<Class<? extends Profiler>>(); 69 private final Optional<TimeUnit> timeUnit; 70 private final Optional<Integer> opsPerInvocation; 71 private final List<String> regexps = new ArrayList<String>(); 72 private final Optional<Integer> fork; 73 private final Optional<Integer> warmupFork; 74 private final Optional<String> output; 75 private final Optional<String> result; 76 private final Optional<ResultFormatType> resultFormat; 77 private final Optional<String> jvm; 78 private final Optional<Collection<String>> jvmArgs; 79 private final Optional<Collection<String>> jvmArgsAppend; 80 private final Optional<Collection<String>> jvmArgsPrepend; 81 private final List<String> excludes = new ArrayList<String>(); 82 private final Optional<WarmupMode> warmupMode; 83 private final List<String> warmupMicros = new ArrayList<String>(); 84 private final Multimap<String, String> params = new HashMultimap<String, String>(); 85 private final boolean list; 86 private final boolean listResultFormats; 87 private final boolean help; 88 private final boolean listProfilers; 89 90 private final transient OptionParser parser; 91 92 /** 93 * Parses the given command line. 94 * @param argv argument list 95 * @throws CommandLineOptionException if some options are misspelled 96 */ 97 public CommandLineOptions(String... argv) throws CommandLineOptionException { 98 parser = new OptionParser(); 99 parser.formatHelpWith(new OptionFormatter()); 100 101 OptionSpec<Integer> optMeasureCount = parser.accepts("i", "Number of measurement iterations to do.") 102 .withRequiredArg().ofType(Integer.class).describedAs("int"); 103 104 OptionSpec<Integer> optMeasureBatchSize = parser.accepts("bs", "Batch size: number of benchmark method calls per operation. " + 105 "(some benchmark modes can ignore this setting)") 106 .withRequiredArg().ofType(Integer.class).describedAs("int"); 107 108 OptionSpec<String> optMeasureTime = parser.accepts("r", "Time to spend at each measurement iteration.") 109 .withRequiredArg().ofType(String.class).describedAs("time"); 110 111 OptionSpec<Integer> optWarmupCount = parser.accepts("wi", "Number of warmup iterations to do.") 112 .withRequiredArg().ofType(Integer.class).describedAs("int"); 113 114 OptionSpec<Integer> optWarmupBatchSize = parser.accepts("wbs", "Warmup batch size: number of benchmark method calls per operation. " + 115 "(some benchmark modes can ignore this setting)") 116 .withRequiredArg().ofType(Integer.class).describedAs("int"); 117 118 OptionSpec<String> optWarmupTime = parser.accepts("w", "Time to spend at each warmup iteration.") 119 .withRequiredArg().ofType(String.class).describedAs("time"); 120 121 OptionSpec<String> optThreads = parser.accepts("t", "Number of worker threads to run with.") 122 .withRequiredArg().ofType(String.class).describedAs("int"); 123 124 OptionSpec<String> optBenchmarkMode = parser.accepts("bm", "Benchmark mode. Available modes are: " + Mode.getKnown()) 125 .withRequiredArg().ofType(String.class).withValuesSeparatedBy(',').describedAs("mode"); 126 127 OptionSpec<Boolean> optSyncIters = parser.accepts("si", "Synchronize iterations?") 128 .withOptionalArg().ofType(Boolean.class).describedAs("bool"); 129 130 OptionSpec<Boolean> optGC = parser.accepts("gc", "Should JMH force GC between iterations?") 131 .withOptionalArg().ofType(Boolean.class).describedAs("bool"); 132 133 OptionSpec<Boolean> optFOE = parser.accepts("foe", "Should JMH fail immediately if any benchmark had" + 134 " experienced the unrecoverable error?") 135 .withOptionalArg().ofType(Boolean.class).describedAs("bool"); 136 137 OptionSpec<String> optVerboseMode = parser.accepts("v", "Verbosity mode. Available modes are: " + Arrays.toString(VerboseMode.values())) 138 .withRequiredArg().ofType(String.class).describedAs("mode"); 139 140 OptionSpec<String> optArgs = parser.nonOptions("Benchmarks to run (regexp+).") 141 .describedAs("regexp+"); 142 143 OptionSpec<Integer> optForks = parser.accepts("f", "How many times to forks a single benchmark." + 144 " Use 0 to disable forking altogether (WARNING: disabling forking may have detrimental" + 145 " impact on benchmark and infrastructure reliability, you might want to use different" + 146 " warmup mode instead).") 147 .withOptionalArg().ofType(Integer.class).describedAs("int"); 148 149 OptionSpec<Integer> optWarmupForks = parser.accepts("wf", "How many warmup forks to make " + 150 "for a single benchmark. 0 to disable warmup forks.") 151 .withRequiredArg().ofType(Integer.class).describedAs("int"); 152 153 OptionSpec<String> optOutput = parser.accepts("o", "Redirect human-readable output to file.") 154 .withRequiredArg().ofType(String.class).describedAs("filename"); 155 156 OptionSpec<String> optOutputResults = parser.accepts("rff", "Write results to given file.") 157 .withRequiredArg().ofType(String.class).describedAs("filename"); 158 159 OptionSpec<String> optProfilers = parser.accepts("prof", "Use profilers to collect additional data." + 160 " See the list of available profilers first.") 161 .withRequiredArg().withValuesSeparatedBy(',').ofType(String.class).describedAs("profiler+"); 162 163 OptionSpec<Integer> optThreadGroups = parser.accepts("tg", "Override thread group distribution for asymmetric benchmarks.") 164 .withRequiredArg().withValuesSeparatedBy(',').ofType(Integer.class).describedAs("int+"); 165 166 OptionSpec<String> optJvm = parser.accepts("jvm", "Custom JVM to use when forking (path to JVM executable).") 167 .withRequiredArg().ofType(String.class).describedAs("string"); 168 169 OptionSpec<String> optJvmArgs = parser.accepts("jvmArgs", "Custom JVM args to use when forking.") 170 .withRequiredArg().ofType(String.class).describedAs("string"); 171 172 OptionSpec<String> optJvmArgsAppend = parser.accepts("jvmArgsAppend", "Custom JVM args to use when forking (append these)") 173 .withRequiredArg().ofType(String.class).describedAs("string"); 174 175 OptionSpec<String> optJvmArgsPrepend = parser.accepts("jvmArgsPrepend", "Custom JVM args to use when forking (prepend these)") 176 .withRequiredArg().ofType(String.class).describedAs("string"); 177 178 OptionSpec<String> optTU = parser.accepts("tu", "Output time unit. Available time units are: [m, s, ms, us, ns].") 179 .withRequiredArg().ofType(String.class).describedAs("TU"); 180 181 OptionSpec<Integer> optOPI = parser.accepts("opi", "Operations per invocation.") 182 .withRequiredArg().ofType(Integer.class).describedAs("int"); 183 184 OptionSpec<String> optResultFormat = parser.accepts("rf", "Result format type. See the list of available result formats first.") 185 .withRequiredArg().ofType(String.class).describedAs("type"); 186 187 OptionSpec<String> optWarmupMode = parser.accepts("wm", "Warmup mode for warming up selected benchmarks. Warmup modes are: " + Arrays.toString(WarmupMode.values()) + ".") 188 .withRequiredArg().ofType(String.class).describedAs("mode"); 189 190 OptionSpec<String> optExcludes = parser.accepts("e", "Benchmarks to exclude from the run.") 191 .withRequiredArg().withValuesSeparatedBy(',').ofType(String.class).describedAs("regexp+"); 192 193 OptionSpec<String> optParams = parser.accepts("p", "Benchmark parameters. This option is expected to be used once" + 194 " per parameter. Parameter name and parameter values should be separated with equals sign." + 195 " Parameter values should be separated with commas.") 196 .withRequiredArg().ofType(String.class).describedAs("param={v,}*"); 197 198 OptionSpec<String> optWarmupBenchmarks = parser.accepts("wmb", "Warmup benchmarks to include in the run " + 199 "in addition to already selected. JMH will not measure these benchmarks, but only use them" + 200 " for the warmup.") 201 .withRequiredArg().withValuesSeparatedBy(',').ofType(String.class).describedAs("regexp+"); 202 203 parser.accepts("l", "List matching benchmarks and exit."); 204 parser.accepts("lrf", "List result formats."); 205 parser.accepts("lprof", "List profilers."); 206 parser.accepts("h", "Display help."); 207 208 try { 209 OptionSet set = parser.parse(argv); 210 211 if (set.has(optExcludes)) { 212 excludes.addAll(optExcludes.values(set)); 213 } 214 215 if (set.has(optWarmupBenchmarks)) { 216 warmupMicros.addAll(optWarmupBenchmarks.values(set)); 217 } 218 219 if (set.has(optTU)) { 220 String va = optTU.value(set); 221 TimeUnit tu; 222 if (va.equalsIgnoreCase("ns")) { 223 tu = TimeUnit.NANOSECONDS; 224 } else if (va.equalsIgnoreCase("us")) { 225 tu = TimeUnit.MICROSECONDS; 226 } else if (va.equalsIgnoreCase("ms")) { 227 tu = TimeUnit.MILLISECONDS; 228 } else if (va.equalsIgnoreCase("s")) { 229 tu = TimeUnit.SECONDS; 230 } else if (va.equalsIgnoreCase("m")) { 231 tu = TimeUnit.MINUTES; 232 } else if (va.equalsIgnoreCase("h")) { 233 tu = TimeUnit.HOURS; 234 } else { 235 throw new CommandLineOptionException("Unknown time unit: " + va); 236 } 237 timeUnit = Optional.of(tu); 238 } else { 239 timeUnit = Optional.none(); 240 } 241 242 opsPerInvocation = Optional.eitherOf(optOPI.value(set)); 243 244 if (set.has(optWarmupMode)) { 245 try { 246 warmupMode = Optional.of(WarmupMode.valueOf(optWarmupMode.value(set))); 247 } catch (IllegalArgumentException iae) { 248 throw new CommandLineOptionException(iae.getMessage(), iae); 249 } 250 } else { 251 warmupMode = Optional.none(); 252 } 253 254 if (set.has(optResultFormat)) { 255 try { 256 resultFormat = Optional.of(ResultFormatType.valueOf(optResultFormat.value(set).toUpperCase())); 257 } catch (IllegalArgumentException iae) { 258 throw new CommandLineOptionException(iae.getMessage(), iae); 259 } 260 } else { 261 resultFormat = Optional.none(); 262 } 263 264 help = set.has("h"); 265 list = set.has("l"); 266 listResultFormats = set.has("lrf"); 267 listProfilers = set.has("lprof"); 268 269 iterations = Optional.eitherOf(optMeasureCount.value(set)); 270 271 batchSize = Optional.eitherOf(optMeasureBatchSize.value(set)); 272 273 if (set.has(optMeasureTime)) { 274 String value = optMeasureTime.value(set); 275 try { 276 runTime = Optional.of(TimeValue.fromString(value)); 277 } catch (IllegalArgumentException iae) { 278 throw new CommandLineOptionException(iae.getMessage(), iae); 279 } 280 } else { 281 runTime = Optional.none(); 282 } 283 284 warmupIterations = Optional.eitherOf(optWarmupCount.value(set)); 285 286 warmupBatchSize = Optional.eitherOf(optWarmupBatchSize.value(set)); 287 288 if (set.has(optWarmupTime)) { 289 String value = optWarmupTime.value(set); 290 try { 291 warmupTime = Optional.of(TimeValue.fromString(value)); 292 } catch (IllegalArgumentException iae) { 293 throw new CommandLineOptionException(iae.getMessage(), iae); 294 } 295 } else { 296 warmupTime = Optional.none(); 297 } 298 299 if (set.has(optThreads)) { 300 String v = optThreads.value(set); 301 if (v.equalsIgnoreCase("max")) { 302 threads = Optional.of(Threads.MAX); 303 } else { 304 try { 305 threads = Optional.of(Integer.valueOf(v)); 306 } catch (IllegalArgumentException iae) { 307 throw new CommandLineOptionException(iae.getMessage(), iae); 308 } 309 } 310 } else { 311 threads = Optional.none(); 312 } 313 314 if (set.has(optBenchmarkMode)) { 315 try { 316 List<Mode> modes = new ArrayList<Mode>(); 317 for (String m : optBenchmarkMode.values(set)) { 318 modes.add(Mode.deepValueOf(m)); 319 } 320 benchMode.addAll(modes); 321 } catch (IllegalArgumentException iae) { 322 throw new CommandLineOptionException(iae.getMessage(), iae); 323 } 324 } 325 326 if (set.has(optSyncIters)) { 327 if (set.hasArgument(optSyncIters)) { 328 synchIterations = Optional.of(optSyncIters.value(set)); 329 } else { 330 synchIterations = Optional.of(true); 331 } 332 } else { 333 synchIterations = Optional.none(); 334 } 335 336 if (set.has(optGC)) { 337 if (set.hasArgument(optGC)) { 338 gcEachIteration = Optional.of(optGC.value(set)); 339 } else { 340 gcEachIteration = Optional.of(true); 341 } 342 } else { 343 gcEachIteration = Optional.none(); 344 } 345 346 if (set.has(optFOE)) { 347 if (set.hasArgument(optFOE)) { 348 failOnError = Optional.of(optFOE.value(set)); 349 } else { 350 failOnError = Optional.of(true); 351 } 352 } else { 353 failOnError = Optional.none(); 354 } 355 356 if (set.has(optVerboseMode)) { 357 try { 358 if (set.hasArgument(optVerboseMode)) { 359 verbose = Optional.of(VerboseMode.valueOf(set.valueOf(optVerboseMode).toUpperCase())); 360 } else { 361 verbose = Optional.of(VerboseMode.EXTRA); 362 } 363 } catch (IllegalArgumentException iae) { 364 throw new CommandLineOptionException(iae.getMessage(), iae); 365 } 366 } else { 367 verbose = Optional.none(); 368 } 369 370 regexps.addAll(set.valuesOf(optArgs)); 371 372 if (set.has(optForks)) { 373 if (set.hasArgument(optForks)) { 374 fork = Optional.of(optForks.value(set)); 375 } else { 376 fork = Optional.of(1); 377 } 378 } else { 379 fork = Optional.none(); 380 } 381 382 warmupFork = Optional.eitherOf(optWarmupForks.value(set)); 383 output = Optional.eitherOf(optOutput.value(set)); 384 result = Optional.eitherOf(optOutputResults.value(set)); 385 386 if (set.has(optProfilers)) { 387 try { 388 for (String m : optProfilers.values(set)) { 389 Class<? extends Profiler> pClass = ProfilerFactory.getProfilerByName(m); 390 if (pClass == null) { 391 throw new CommandLineOptionException("Unable to find profiler: " + m); 392 } 393 profilers.add(pClass); 394 } 395 } catch (IllegalArgumentException iae) { 396 throw new CommandLineOptionException(iae.getMessage(), iae); 397 } 398 } 399 400 if (set.has(optThreadGroups)) { 401 threadGroups.addAll(set.valuesOf(optThreadGroups)); 402 } 403 404 jvm = Optional.eitherOf(optJvm.value(set)); 405 406 if (set.hasArgument(optJvmArgs)) { 407 jvmArgs = Optional.<Collection<String>>of(Arrays.asList(optJvmArgs.value(set).trim().split("[ ]+"))); 408 } else { 409 jvmArgs = Optional.none(); 410 } 411 412 if (set.hasArgument(optJvmArgsAppend)) { 413 jvmArgsAppend = Optional.<Collection<String>>of(Arrays.asList(optJvmArgsAppend.value(set).trim().split("[ ]+"))); 414 } else { 415 jvmArgsAppend = Optional.none(); 416 } 417 418 if (set.hasArgument(optJvmArgsPrepend)) { 419 jvmArgsPrepend = Optional.<Collection<String>>of(Arrays.asList(optJvmArgsPrepend.value(set).trim().split("[ ]+"))); 420 } else { 421 jvmArgsPrepend = Optional.none(); 422 } 423 424 if (set.hasArgument(optParams)) { 425 for (String p : optParams.values(set)) { 426 String[] keys = p.split("="); 427 if (keys.length != 2) { 428 throw new CommandLineOptionException("Unable to parse parameter string \"" + p + "\""); 429 } 430 params.putAll(keys[0], Arrays.asList(keys[1].split(","))); 431 } 432 } 433 434 } catch (OptionException e) { 435 throw new CommandLineOptionException(e.getMessage(), e); 436 } 437 } 438 439 public void showHelp() throws IOException { 440 parser.printHelpOn(System.err); 441 } 442 443 public void listProfilers() { 444 StringBuilder supported = new StringBuilder(); 445 StringBuilder unsupported = new StringBuilder(); 446 447 List<Class<? extends Profiler>> discoveredProfilers = ProfilerFactory.getDiscoveredProfilers(); 448 449 for (Class<? extends Profiler> s : ProfilerFactory.getAvailableProfilers()) { 450 List<String> initMessages = new ArrayList<String>(); 451 if (ProfilerFactory.checkSupport(s, initMessages)) { 452 supported.append(String.format("%20s: %s %s\n", 453 ProfilerFactory.getLabel(s), 454 ProfilerFactory.getDescription(s), 455 discoveredProfilers.contains(s) ? "(discovered)" : "")); 456 } else { 457 unsupported.append(String.format("%20s: %s %s\n", 458 ProfilerFactory.getLabel(s), 459 ProfilerFactory.getDescription(s), 460 discoveredProfilers.contains(s) ? "(discovered)" : "")); 461 for (String im : initMessages) { 462 unsupported.append(String.format("%20s %s\n", "", im)); 463 } 464 unsupported.append("\n"); 465 } 466 } 467 468 if (!supported.toString().isEmpty()) { 469 System.out.println("Supported profilers:\n" + supported.toString()); 470 } 471 472 if (!unsupported.toString().isEmpty()) { 473 System.out.println("Unsupported profilers:\n" + unsupported.toString()); 474 } 475 } 476 477 public void listResultFormats() { 478 StringBuilder sb = new StringBuilder(); 479 480 for (ResultFormatType f : ResultFormatType.values()) { 481 sb.append(f.toString().toLowerCase()); 482 sb.append(", "); 483 } 484 sb.setLength(sb.length() - 2); 485 486 System.out.println("Available formats: " + sb.toString()); 487 } 488 489 public boolean shouldList() { 490 return list; 491 } 492 493 public boolean shouldListResultFormats() { 494 return listResultFormats; 495 } 496 497 public boolean shouldHelp() { 498 return help; 499 } 500 501 public boolean shouldListProfilers() { 502 return listProfilers; 503 } 504 505 @Override 506 public Optional<WarmupMode> getWarmupMode() { 507 return warmupMode; 508 } 509 510 @Override 511 public List<String> getIncludes() { 512 return regexps; 513 } 514 515 @Override 516 public List<String> getExcludes() { 517 return excludes; 518 } 519 520 @Override 521 public List<String> getWarmupIncludes() { 522 return warmupMicros; 523 } 524 525 @Override 526 public Optional<String> getJvm() { 527 return jvm; 528 } 529 530 @Override 531 public Optional<Collection<String>> getJvmArgs() { 532 return jvmArgs; 533 } 534 535 @Override 536 public Optional<Collection<String>> getJvmArgsAppend() { 537 return jvmArgsAppend; 538 } 539 540 @Override 541 public Optional<Collection<String>> getJvmArgsPrepend() { 542 return jvmArgsPrepend; 543 } 544 545 @Override 546 public Optional<Collection<String>> getParameter(String name) { 547 Collection<String> list = params.get(name); 548 if (list == null || list.isEmpty()){ 549 return Optional.none(); 550 } else { 551 return Optional.of(list); 552 } 553 } 554 555 @Override 556 public Optional<Integer> getForkCount() { 557 return fork; 558 } 559 560 @Override 561 public Optional<Integer> getWarmupForkCount() { 562 return warmupFork; 563 } 564 565 @Override 566 public Optional<String> getOutput() { 567 return output; 568 } 569 570 @Override 571 public Optional<ResultFormatType> getResultFormat() { 572 return resultFormat; 573 } 574 575 @Override 576 public Optional<String> getResult() { 577 return result; 578 } 579 580 @Override 581 public Optional<Integer> getMeasurementIterations() { 582 return iterations; 583 } 584 585 @Override 586 public Optional<Integer> getMeasurementBatchSize() { 587 return batchSize; 588 } 589 590 @Override 591 public Optional<TimeValue> getMeasurementTime() { 592 return runTime; 593 } 594 595 @Override 596 public Optional<TimeValue> getWarmupTime() { 597 return warmupTime; 598 } 599 600 @Override 601 public Optional<Integer> getWarmupIterations() { 602 return warmupIterations; 603 } 604 605 @Override 606 public Optional<Integer> getWarmupBatchSize() { 607 return warmupBatchSize; 608 } 609 610 @Override 611 public Optional<Integer> getThreads() { 612 return threads; 613 } 614 615 @Override 616 public Optional<int[]> getThreadGroups() { 617 if (threadGroups.isEmpty()) { 618 return Optional.none(); 619 } else { 620 int[] r = new int[threadGroups.size()]; 621 for (int c = 0; c < r.length; c++) { 622 r[c] = threadGroups.get(c); 623 } 624 return Optional.of(r); 625 } 626 } 627 628 @Override 629 public Optional<Boolean> shouldDoGC() { 630 return gcEachIteration; 631 } 632 633 @Override 634 public Optional<Boolean> shouldSyncIterations() { 635 return synchIterations; 636 } 637 638 @Override 639 public Optional<VerboseMode> verbosity() { 640 return verbose; 641 } 642 643 @Override 644 public Optional<TimeUnit> getTimeUnit() { 645 return timeUnit; 646 } 647 648 @Override 649 public Optional<Integer> getOperationsPerInvocation() { 650 return opsPerInvocation; 651 } 652 653 @Override 654 public Optional<Boolean> shouldFailOnError() { 655 return failOnError; 656 } 657 658 @Override 659 public Set<Class<? extends Profiler>> getProfilers() { 660 return profilers; 661 } 662 663 @Override 664 public Collection<Mode> getBenchModes() { 665 return new HashSet<Mode>(benchMode); 666 } 667 668 }