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