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