1 /*
   2  * Copyright (c) 2016, 2019, 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 
  26 package jdk.jfr.startupargs;
  27 
  28 import java.lang.reflect.Field;
  29 import java.util.List;
  30 import java.util.ArrayList;
  31 
  32 import jdk.jfr.internal.Options;
  33 import jdk.testlibrary.OutputAnalyzer;
  34 import jdk.testlibrary.ProcessTools;
  35 import sun.misc.Unsafe;
  36 import jdk.testlibrary.jfr.StartupHelper;
  37 
  38 /*
  39  * @test
  40  * @key jfr
  41  * @library /lib/testlibrary
  42  * @modules jdk.jfr/jdk.jfr.internal
  43  *                 java.base/jdk.internal.misc
  44  * @run main/timeout=900 jdk.jfr.startupargs.TestMemoryOptions
  45  */
  46 public class TestMemoryOptions {
  47 
  48     public enum Unit {
  49         b('b'), k('k'), m('m'), g('g');
  50 
  51         private char unit;
  52 
  53         Unit(char unit) {
  54             this.unit = unit;
  55         }
  56 
  57         char getUnit() {
  58             return unit;
  59         }
  60     };
  61 
  62     private static synchronized Unsafe getUnsafe() {
  63         try {
  64             Field f = Unsafe.class.getDeclaredField("theUnsafe");
  65             f.setAccessible(true);
  66             return (Unsafe) f.get(null);
  67         } catch (NoSuchFieldException | IllegalAccessException e) {
  68             throw new RuntimeException("Unable to get Unsafe instance.", e);
  69         }
  70     }
  71 
  72     static class Option implements Comparable<Option> {
  73         static final long MIN_GLOBAL_BUFFER_COUNT = 2;
  74         static final long DEFAULT_GLOBAL_BUFFER_COUNT = 20;
  75         static final long MIN_GLOBAL_BUFFER_SIZE = 64 * 1024;
  76         static long DEFAULT_GLOBAL_BUFFER_SIZE = 524288;
  77         static final long MIN_MEMORY_SIZE = 1024 * 1024;
  78         static final long DEFAULT_MEMORY_SIZE = DEFAULT_GLOBAL_BUFFER_COUNT * DEFAULT_GLOBAL_BUFFER_SIZE;
  79         static final long MIN_THREAD_BUFFER_SIZE = 4 * 1024;
  80         static long DEFAULT_THREAD_BUFFER_SIZE;
  81         static final long PAGE_SIZE;
  82         static final long UNDEFINED = -1;
  83 
  84         static {
  85             PAGE_SIZE = getUnsafe().pageSize();
  86             if (PAGE_SIZE == MIN_THREAD_BUFFER_SIZE) {
  87                 DEFAULT_THREAD_BUFFER_SIZE = PAGE_SIZE * 2;
  88             } else {
  89                 DEFAULT_THREAD_BUFFER_SIZE = PAGE_SIZE;
  90             }
  91             if (PAGE_SIZE > DEFAULT_GLOBAL_BUFFER_SIZE) {
  92                 DEFAULT_GLOBAL_BUFFER_SIZE = PAGE_SIZE;
  93             }
  94         }
  95 
  96         final private long min;
  97         final private long max;
  98         final private String paramName;
  99 
 100         private long input;
 101         private Unit inputUnit;
 102         private long result;
 103         private Unit resultUnit;
 104 
 105         private long getValueAsUnit(long value, Unit unit) {
 106             switch (unit) {
 107                 case b:
 108                     return value;
 109                 case k:
 110                     return value / 1024;
 111                 case m:
 112                     return value / (1024 * 1024);
 113                 case g:
 114                     return value / (1024 * 1024 * 1024);
 115             }
 116             return value;
 117         }
 118 
 119         private long getRawValue(long value, Unit unit) {
 120             switch (unit) {
 121                 case b:
 122                     return value;
 123                 case k:
 124                     return value * 1024;
 125                 case m:
 126                     return value * (1024 * 1024);
 127                 case g:
 128                     return value * (1024 * 1024 * 1024);
 129             }
 130             return value;
 131         }
 132 
 133         private long parseValue(String valueString, char unit) {
 134             if (Character.isLetter(unit)) {
 135                 unit = Character.toLowerCase(unit);
 136                 return getRawValue(Long.parseLong(valueString.substring(0, valueString.length() - 1), 10),
 137                                                   Unit.valueOf(String.valueOf(unit)));
 138             }
 139             // does not have a unit, default is bytes
 140             return Long.parseLong(valueString.substring(0, valueString.length()), 10);
 141         }
 142 
 143         public Option(String minString, String maxString, String paramName) {
 144             if (minString == null) {
 145                 this.min = UNDEFINED;
 146             } else {
 147                 char unit = minString.charAt(minString.length() - 1);
 148                 this.min = parseValue(minString, unit);
 149             }
 150             if (maxString == null) {
 151                 this.max = UNDEFINED;
 152             } else {
 153                 char unit = maxString.charAt(maxString.length() - 1);
 154                 this.max = parseValue(maxString, unit);
 155             }
 156             this.input = UNDEFINED;
 157             this.result = UNDEFINED;
 158             this.paramName = paramName;
 159         }
 160 
 161         private Option(long value, char unit) {
 162             this.resultUnit = Unit.valueOf(String.valueOf(unit));
 163             this.result = getRawValue(value, this.resultUnit);
 164             this.min = UNDEFINED;
 165             this.max = UNDEFINED;
 166             this.paramName = "";
 167         }
 168 
 169         public void setInput(long value, char unit) {
 170             this.inputUnit = Unit.valueOf(String.valueOf(unit));
 171             this.input = getRawValue(value, this.inputUnit);
 172         }
 173 
 174         public long getInput() {
 175             return input;
 176         }
 177 
 178         public void setResult(long value, char unit) {
 179             this.resultUnit = Unit.valueOf(String.valueOf(unit));
 180             this.result = getRawValue(value, this.resultUnit);
 181         }
 182 
 183         public long getResult() {
 184             return result;
 185         }
 186 
 187         public long getResultAs(Unit unit) {
 188             return getValueAsUnit(this.result, unit);
 189         }
 190 
 191         public String getOptionParamName() {
 192             return paramName;
 193         }
 194 
 195         public String getOptionParamString() {
 196             if (input == UNDEFINED) {
 197                 return null;
 198             }
 199             char unit = inputUnit.getUnit();
 200             String unitString = Character.compare(unit, 'b') == 0 ? "" : String.valueOf(unit);
 201             return getOptionParamName() + "=" + Long.toString(getValueAsUnit(input, inputUnit)) + unitString;
 202         }
 203 
 204         public boolean predictedToStartVM() {
 205             if (input == UNDEFINED) {
 206                 // option not set
 207                 return true;
 208             }
 209             if (input >= 0) {
 210                 if (min != UNDEFINED) {
 211                     if (max != UNDEFINED) {
 212                         return input >= min && input <= max;
 213                     }
 214                     return input >= min;
 215                 }
 216                 if (max != UNDEFINED) {
 217                     if (min != UNDEFINED) {
 218                         return input <= max && input >= min;
 219                     }
 220                 }
 221                 return true;
 222             }
 223             return false;
 224         }
 225 
 226         public boolean isSet() {
 227             return input != UNDEFINED;
 228         }
 229 
 230         public boolean validate() throws IllegalArgumentException {
 231             // a result memory options should be page aligned
 232             if (getResult() > PAGE_SIZE) {
 233                 if (getResult() % PAGE_SIZE != 0) {
 234                     throw new IllegalArgumentException("Result value: "
 235                     + getResult() + " for option " + getOptionParamName() + " is not aligned to page size " + PAGE_SIZE);
 236                 }
 237             }
 238             // if min is defined, the result value should be gteq
 239             if (min != UNDEFINED) {
 240                 if (getResult() < min) {
 241                     throw new IllegalArgumentException("Result value: "
 242                     + getResult() + " for option " + getOptionParamName() + " is less than min: " + min);
 243                 }
 244             }
 245             // if max is defined, the result values should be lteq
 246             if (max != UNDEFINED) {
 247                 if (getResult() > max) {
 248                     throw new IllegalArgumentException("Result value: "
 249                     + getResult() + " for option " + getOptionParamName() + " is greater than max: " + max);
 250                 }
 251             }
 252             return true;
 253         }
 254 
 255         @Override
 256         public int compareTo(Option obj) {
 257             if (getResult() == obj.getResult()) {
 258                 return 0;
 259             }
 260             return getResult() > obj.getResult() ? 1 : -1;
 261         }
 262 
 263         @Override
 264         public boolean equals(Object obj) {
 265             if (obj == null) {
 266                 return false;
 267             }
 268             if (!Option.class.isAssignableFrom(obj.getClass())) {
 269                 return false;
 270             }
 271             final Option other = (Option) obj;
 272 
 273             return getResult() == other.getResult();
 274         }
 275 
 276         @Override
 277         public int hashCode() {
 278             long hash = 3;
 279             hash = 53 * hash * getResult();
 280             return (int)hash;
 281         }
 282 
 283         @Override
 284         public String toString() {
 285             return Long.toString(getResult());
 286         }
 287 
 288         public Option multiply(Option rhsFactor) {
 289             return new Option(getResult() * rhsFactor.getResult(), 'b');
 290         }
 291 
 292         public Option divide(Option rhsDivisor) {
 293             long divisor = rhsDivisor.getResult();
 294             if (divisor == 0) {
 295                 return new Option(0, 'b');
 296             }
 297             return new Option(getResult() / divisor, 'b');
 298         }
 299 
 300         boolean isLessThanOrEqual(Option rhs) {
 301             return getResult() <= rhs.getResult();
 302         }
 303 
 304         boolean isGreaterThanOrEqual(Option rhs) {
 305             return getResult() >= rhs.getResult();
 306         }
 307     }
 308 
 309     private static class TestCase {
 310         private static final int MEMORYSIZE = 0;
 311         private static final int GLOBALBUFFERSIZE = 1;
 312         private static final int GLOBALBUFFERCOUNT = 2;
 313         private static final int THREADBUFFERSIZE = 3;
 314 
 315         final private List<Option> optionList = new ArrayList<Option>();
 316         final private String testName;
 317 
 318         public TestCase(String testName, boolean runTest) {
 319             this.testName = testName;
 320             Option memorySize = new Option(Long.toString(Option.MIN_MEMORY_SIZE), null, "memorysize");
 321             optionList.add(memorySize);
 322 
 323             Option globalBufferSize = new Option(Long.toString(Option.MIN_GLOBAL_BUFFER_SIZE),
 324                                                  null, "globalbuffersize");
 325             optionList.add(globalBufferSize);
 326 
 327             Option globalBufferCount = new Option(Long.toString(Option.MIN_GLOBAL_BUFFER_COUNT), null, "numglobalbuffers");
 328             optionList.add(globalBufferCount);
 329 
 330             Option threadBufferSize = new Option(Long.toString(Option.MIN_THREAD_BUFFER_SIZE), null, "threadbuffersize");
 331             optionList.add(threadBufferSize);
 332 
 333             if (runTest) {
 334                 populateResults();
 335                 validateNodes();
 336                 validateEdges();
 337             }
 338         }
 339 
 340         public String getTestString() {
 341             String optionString = "-XX:FlightRecorderOptions=";
 342             for (Option o : optionList) {
 343                 String optionParamString = o.getOptionParamString();
 344                 if (optionParamString == null) {
 345                     continue;
 346                 }
 347                 optionString = optionString.concat(optionParamString);
 348                 optionString = optionString.concat(",");
 349             }
 350             if (optionString.equals("-XX:FlightRecorderOptions=")) {
 351                 return null;
 352             }
 353             // strip last ","
 354             optionString = optionString.substring(0, optionString.length() - 1);
 355             return optionString;
 356         }
 357 
 358         public String getTestName() {
 359             return this.testName;
 360         }
 361 
 362         private void setInputForIndex(int index, long size, char unit) {
 363             optionList.get(index).setInput(size, unit);
 364         }
 365 
 366         private void setResultForIndex(int index, long size, char unit) {
 367             optionList.get(index).setResult(size, unit);
 368         }
 369 
 370         public void setMemorySizeTestParam(long size, char unit) {
 371             setInputForIndex(MEMORYSIZE, size, unit);
 372         }
 373 
 374         public void setMemorySizeTestResult(long size, char unit) {
 375             setResultForIndex(MEMORYSIZE, size, unit);
 376         }
 377 
 378         public void setGlobalBufferSizeTestParam(long size, char unit) {
 379             setInputForIndex(GLOBALBUFFERSIZE, size, unit);
 380         }
 381 
 382         public void setGlobalBufferSizeTestResult(long size, char unit) {
 383             setResultForIndex(GLOBALBUFFERSIZE, size, unit);
 384         }
 385 
 386         public void setGlobalBufferCountTestParam(long size, char unit) {
 387             setInputForIndex(GLOBALBUFFERCOUNT, size, unit);
 388         }
 389 
 390         public void setGlobalBufferCountTestResult(long size, char unit) {
 391             setResultForIndex(GLOBALBUFFERCOUNT, size, unit);
 392         }
 393 
 394         public void setThreadBufferSizeTestParam(long size, char unit) {
 395             setInputForIndex(THREADBUFFERSIZE, size, unit);
 396         }
 397 
 398         public void setThreadBufferSizeTestResult(long size, char unit) {
 399             setResultForIndex(THREADBUFFERSIZE, size, unit);
 400         }
 401 
 402         public void validateNodes() {
 403             for (Option o : optionList) {
 404                 o.validate();
 405             }
 406         }
 407 
 408         public void validateEdges() {
 409             final Option memorySize = optionList.get(MEMORYSIZE);
 410             final Option globalBufferSize = optionList.get(GLOBALBUFFERSIZE);
 411             final Option globalBufferCount = optionList.get(GLOBALBUFFERCOUNT);
 412             final Option threadBufferSize = optionList.get(THREADBUFFERSIZE);
 413 
 414             if (!memorySize.divide(globalBufferCount).equals(globalBufferSize)) {
 415                 throw new IllegalArgumentException(getTestName() + " failure: " + memorySize.getOptionParamName() + " (" + memorySize.getResult() + ") / " +
 416                                                    globalBufferCount.getOptionParamName() + " (" + globalBufferCount.getResult() +
 417                                                    ") (" + memorySize.divide(globalBufferCount).getResult() + ") != " +
 418                                                    globalBufferSize.getOptionParamName() + " (" + globalBufferSize.getResult() + ")");
 419             }
 420 
 421             if (!globalBufferSize.multiply(globalBufferCount).equals(memorySize)) {
 422                 throw new IllegalArgumentException(getTestName() + " failure: " + globalBufferSize.getOptionParamName() + ": " +
 423                                                    globalBufferSize.getResult() +
 424                                                    " * " + globalBufferCount.getOptionParamName() + ": " + globalBufferCount.getResult() +
 425                                                    " != " + memorySize.getOptionParamName() + ": " + memorySize.getResult());
 426             }
 427 
 428             if (!threadBufferSize.isLessThanOrEqual(globalBufferSize)) {
 429                 throw new IllegalArgumentException(getTestName() + " failure: " + threadBufferSize.getOptionParamName() + ": " + threadBufferSize.getResult() +
 430                                                    " is larger than " + globalBufferSize.getOptionParamName() + ": " + globalBufferSize.getResult());
 431             }
 432         }
 433 
 434         public void print() {
 435             System.out.println("Printing information for testcase : " + getTestName());
 436             for (Option o : optionList) {
 437                 System.out.println("Parameter name: " + o.getOptionParamName());
 438                 System.out.println("Parameter test value : " + o.getOptionParamString() != null ?  o.getOptionParamString() : "not enabled for input testing");
 439                 String inputString = o.getInput() == Option.UNDEFINED ? "N/A" : Long.toString(o.getInput());
 440                 System.out.println("Input value: " + inputString);
 441                 System.out.println("Predicted to start VM: " + (o.predictedToStartVM() ? "true" : "false"));
 442             }
 443         }
 444 
 445         private void populateResults() {
 446             optionList.get(MEMORYSIZE).setResult(Options.getMemorySize(), 'b');
 447             optionList.get(GLOBALBUFFERSIZE).setResult(Options.getGlobalBufferSize(), 'b');
 448             optionList.get(GLOBALBUFFERCOUNT).setResult(Options.getGlobalBufferCount(), 'b');
 449             optionList.get(THREADBUFFERSIZE).setResult(Options.getThreadBufferSize(), 'b');
 450         }
 451 
 452         public boolean predictedToStartVM() {
 453             // check each individual option
 454             for (Option o : optionList) {
 455                 if (!o.predictedToStartVM()) {
 456                     return false;
 457                 }
 458             }
 459 
 460             // check known invalid combinations that will not allow the VM to start
 461 
 462             // GLOBALBUFFERSIZE * GLOBALBUFFERCOUNT == MEMORYSIZE
 463             if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(GLOBALBUFFERCOUNT).isSet()
 464                && optionList.get(MEMORYSIZE).isSet()) {
 465                long calculatedMemorySize = optionList.get(GLOBALBUFFERSIZE).getInput() * optionList.get(GLOBALBUFFERCOUNT).getInput();
 466                if (optionList.get(MEMORYSIZE).getInput() != calculatedMemorySize) {
 467                    return false;
 468                }
 469             }
 470             // GLOBALBUFFERSIZE * GLOBALBUFFERCOUNT >= MIN_MEMORY_SIZE
 471             if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(GLOBALBUFFERCOUNT).isSet()
 472                 && !optionList.get(MEMORYSIZE).isSet()) {
 473                 long calculatedMemorySize = optionList.get(GLOBALBUFFERSIZE).getInput() * optionList.get(GLOBALBUFFERCOUNT).getInput();
 474                 if (Option.MIN_MEMORY_SIZE > calculatedMemorySize) {
 475                     return false;
 476                 }
 477             }
 478             // GLOBALBUFFERSIZE >= THREADBUFFERSIZE
 479             if (optionList.get(GLOBALBUFFERSIZE).isSet() && optionList.get(THREADBUFFERSIZE).isSet()) {
 480                 if (optionList.get(GLOBALBUFFERSIZE).getInput() < optionList.get(THREADBUFFERSIZE).getInput()) {
 481                     return false;
 482                 }
 483             }
 484             return true;
 485         }
 486     }
 487 
 488     public static class SUT {
 489         public static void main(String[] args) {
 490             TestCase tc = new TestCase(args[0], true);
 491         }
 492     }
 493 
 494     private static class Driver {
 495         private static void launchTestVM(TestCase tc) throws Exception {
 496             final String flightRecorderOptions = tc.getTestString();
 497             ProcessBuilder pb;
 498             if (flightRecorderOptions != null) {
 499                 pb = ProcessTools.createJavaProcessBuilder(true,
 500                                                            flightRecorderOptions,
 501                                                            "-XX:+FlightRecorder",
 502                                                            SUT.class.getName(),
 503                                                            tc.getTestName());
 504             } else {
 505                 // default, no FlightRecorderOptions passed
 506                 pb = ProcessTools.createJavaProcessBuilder(true,
 507                                                            "-XX:+FlightRecorder",
 508                                                            SUT.class.getName(),
 509                                                            tc.getTestName());
 510             }
 511 
 512             System.out.println("Driver launching SUT with string: " + flightRecorderOptions != null ? flightRecorderOptions : "default");
 513             System.out.println("SUT VM " + (tc.predictedToStartVM() ? "is" : "is not") + " expected to start");
 514             tc.print();
 515 
 516             OutputAnalyzer out = null;
 517             try {
 518                 out = ProcessTools.executeProcess(pb);
 519             } catch (Throwable e) {
 520                 e.printStackTrace();
 521             }
 522 
 523             if (tc.predictedToStartVM()) {
 524                 out.shouldHaveExitValue(0);
 525             } else {
 526                 out.shouldContain("Failed to start tracing backend.");
 527                 out.shouldHaveExitValue(1);
 528             }
 529         }
 530 
 531         public static void runTestCase(TestCase tc) throws Exception {
 532             launchTestVM(tc);
 533         }
 534     }
 535 
 536     static private List<TestCase> testCases = new ArrayList<TestCase>();
 537 
 538     static {
 539         // positive example-based tests
 540         TestCase tc = new TestCase("DefaultOptionsPositive", false);
 541         // defaults, no options explicitly set
 542         testCases.add(tc);
 543 
 544         // explicit defaults passed as parameters
 545         tc = new TestCase("MemorySizePositive", false);
 546         tc.setMemorySizeTestParam(10, 'm');
 547         testCases.add(tc);
 548 
 549         tc = new TestCase("GlobalBufferSizePositive", false);
 550         tc.setGlobalBufferSizeTestParam(512, 'k');
 551         testCases.add(tc);
 552 
 553         tc = new TestCase("BufferCountPositive", false);
 554         tc.setGlobalBufferCountTestParam(20, 'b');
 555         testCases.add(tc);
 556 
 557         tc = new TestCase("ThreadBufferSizePositive", false);
 558         tc.setThreadBufferSizeTestParam(Option.DEFAULT_THREAD_BUFFER_SIZE, 'b');
 559         testCases.add(tc);
 560 
 561         // negative example-based tests, each individual option below minimum size
 562         tc = new TestCase("MemorySizeBelowMinNegative", false);
 563         tc.setMemorySizeTestParam(Option.MIN_MEMORY_SIZE - 1, 'b');
 564         testCases.add(tc);
 565 
 566         tc = new TestCase("GlobalBufferSizeBelowMinNegative", false);
 567         tc.setGlobalBufferSizeTestParam(Option.MIN_GLOBAL_BUFFER_SIZE - 1, 'b');
 568         testCases.add(tc);
 569 
 570         tc = new TestCase("BufferCountBelowMinNegative", false);
 571         tc.setGlobalBufferCountTestParam(Option.MIN_GLOBAL_BUFFER_COUNT - 1, 'b');
 572         testCases.add(tc);
 573 
 574         tc = new TestCase("ThreadBufferSizeBelowMinNegative", false);
 575         tc.setThreadBufferSizeTestParam(Option.MIN_THREAD_BUFFER_SIZE - 1, 'b');
 576         testCases.add(tc);
 577 
 578         // Memory size permutations
 579         // a few single memorysize option for deduction
 580         tc = new TestCase("MemorySizeValue1Positive", false);
 581         tc.setMemorySizeTestParam(48128, 'k'); // 47mb
 582         testCases.add(tc);
 583 
 584         tc = new TestCase("MemorySizeValue2Positive", false);
 585         tc.setMemorySizeTestParam(17391, 'k'); // 17808384 bytes
 586         testCases.add(tc);
 587 
 588         tc = new TestCase("MemorySizeValue3Positive", false);
 589         tc.setMemorySizeTestParam(Option.MIN_MEMORY_SIZE + 17, 'b');
 590         testCases.add(tc);
 591 
 592         // positive example-based-tests, memory size combined with other options
 593         tc = new TestCase("MemorySizeGlobalBufferSizePositive", false);
 594         tc.setMemorySizeTestParam(14680064, 'b'); // 14mb
 595         tc.setGlobalBufferSizeTestParam(720, 'k');
 596         testCases.add(tc);
 597 
 598         tc = new TestCase("MemorySizeGlobalBufferCountPositive", false);
 599         tc.setMemorySizeTestParam(14674581, 'b'); // 14mb - 5483 bytes
 600         tc.setGlobalBufferCountTestParam(17, 'b');
 601         testCases.add(tc);
 602 
 603         tc = new TestCase("MemorySizeThreadBufferSizePositive", false);
 604         tc.setMemorySizeTestParam(14586853, 'b'); // 14mb - 93211 bytes
 605         tc.setThreadBufferSizeTestParam(Option.DEFAULT_THREAD_BUFFER_SIZE, 'b');
 606         testCases.add(tc);
 607 
 608         tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountPositive", false);
 609         tc.setMemorySizeTestParam(12240, 'k');
 610         tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 17 == 12240 k
 611         tc.setGlobalBufferCountTestParam(17, 'b');
 612         testCases.add(tc);
 613 
 614         tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountThreadBufferSizePositive", false);
 615         tc.setMemorySizeTestParam(12240, 'k');
 616         tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 17 == 12240 k
 617         tc.setGlobalBufferCountTestParam(17, 'b');
 618         tc.setThreadBufferSizeTestParam(600, 'k');
 619         testCases.add(tc);
 620 
 621         // negative example-based test, create an ambiguous situtation
 622         tc = new TestCase("MemorySizeGlobalBufferSizeBufferCountAmbiguousNegative", false);
 623         tc.setMemorySizeTestParam(12240, 'k');
 624         tc.setGlobalBufferSizeTestParam(720, 'k'); // 720 k * 19 != 12240 k
 625         tc.setGlobalBufferCountTestParam(19, 'b');
 626         testCases.add(tc);
 627 
 628         // Global buffer size permutations
 629         tc = new TestCase("GlobalBufferSizeBufferCountPositive", false);
 630         tc.setGlobalBufferSizeTestParam(917, 'k');
 631         tc.setGlobalBufferCountTestParam(31, 'b');
 632         testCases.add(tc);
 633 
 634         tc = new TestCase("GlobalBufferSizeBufferCountThreadBufferSizePositive", false);
 635         tc.setGlobalBufferSizeTestParam(917, 'k');
 636         tc.setGlobalBufferCountTestParam(31, 'b');
 637         tc.setThreadBufferSizeTestParam(760832, 'b'); // 743 k
 638         testCases.add(tc);
 639 
 640         // negative example-based test, let thread buffer size > global buffer size
 641         tc = new TestCase("GlobalBufferSizeLessThanThreadBufferSizeNegative", false);
 642         tc.setGlobalBufferSizeTestParam(917, 'k');
 643         tc.setThreadBufferSizeTestParam(1317, 'k');
 644         testCases.add(tc);
 645 
 646         // explicitly specifying global buffer size and global buffer count must be gteq min memorysize
 647         tc = new TestCase("GlobalBufferSizeTimesGlobalBufferCountLessThanMinMemorySizeNegative", false);
 648         tc.setGlobalBufferSizeTestParam(67857, 'b');
 649         tc.setGlobalBufferCountTestParam(3, 'b');
 650         testCases.add(tc);
 651 
 652         // absolute minimum size
 653         tc = new TestCase("GlobalBufferSizeTimesGlobalBufferCountEqualToMinMemorySizePositive", false);
 654         tc.setGlobalBufferSizeTestParam(64, 'k');
 655         tc.setGlobalBufferCountTestParam(16, 'b');
 656         testCases.add(tc);
 657     }
 658 
 659     public static void main(String[] args) throws Exception {
 660         System.out.println("Testing " + testCases.size() + " number of testcases");
 661         for (TestCase tc : testCases) {
 662             Driver.runTestCase(tc);
 663         }
 664     }
 665 }