1 /*
   2  * Copyright (c) 2002, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 //gctest02.java
  24 
  25 
  26 /*
  27  * @test
  28  * @key gc
  29  *
  30  * @summary converted from VM Testbase gc/gctests/gctest02.
  31  * VM Testbase keywords: [gc]
  32  *
  33  * @library /vmTestbase
  34  *          /test/lib
  35  * @run driver jdk.test.lib.FileInstaller . .
  36  * @run main/othervm gc.gctests.gctest02.gctest02 100
  37  */
  38 
  39 package gc.gctests.gctest02;
  40 
  41 import nsk.share.TestFailure;
  42 import nsk.share.TestBug;
  43 /*  stress testing
  44  create 16 memory evil threads requesting to allocate
  45  the object of sizes from 8 to ( 2 ^ 19).
  46  The live time of objects is random (0 ~ 1000).
  47  Here we let the threads that reference the objects
  48  to simulate the object life time.
  49 */
  50 
  51 import java.util.Random;
  52 
  53 class PopulationException extends Exception {
  54     //this exception is used to signal that we've
  55     //reached the end of the test
  56 }
  57 
  58 //the LocalRandom class is used to isolate the pseudo-random
  59 //number generator from other parts of the system which might
  60 //silently be using it.
  61 //This is to make sure the tests are repeatable
  62 
  63 class LocalRandom {
  64     public static Random rGen = null;
  65 
  66     public static double random() {
  67         //should fail if rGen is not initialized
  68         return rGen.nextDouble();
  69     }
  70 }
  71 
  72 class ThreadCount {
  73     static int count= 0;
  74     static synchronized void inc() { count++; }
  75     static synchronized void dec() { count --; }
  76     static synchronized int get() { return count; }
  77 }
  78 
  79 class Person {
  80         String name;
  81         int     ssid;
  82         int     age;
  83         int     buf[];
  84         int     bufsz;
  85         static int populationCount = 0;
  86         static int populationLimit = 0;
  87 
  88         Person(String n, int ssid, int age, int bufsz)
  89         throws PopulationException {
  90                 name = n;
  91                 this.ssid = ssid;
  92                 this.age = age;
  93                 if ( bufsz > 0 ) {
  94                         this.bufsz = bufsz;
  95                         this.buf = new int[bufsz];
  96                 }
  97                 incPopulation();
  98                 if (getPopulation() > getPopulationLimit()) {
  99                         throw new PopulationException();
 100                 }
 101         }
 102         public static synchronized int getPopulationLimit() {
 103                 return populationLimit;
 104         }
 105         public static synchronized void setPopulationLimit(int newLimit) {
 106                 populationLimit = newLimit;
 107         }
 108         public static synchronized int getPopulation() {
 109                 return populationCount;
 110         }
 111         public static synchronized void incPopulation() {
 112                 populationCount ++;
 113         }
 114 
 115 }
 116 
 117 // hr (humane resource) dept is using objects.
 118 // Put the hr thread to sleep to keep the reference to objects
 119 class hr extends Thread {
 120         Person pp;
 121         int lifetime;
 122 
 123         hr(Person p, int l) {
 124                 pp = p;
 125                 lifetime = l;
 126         }
 127 
 128         public void run() {
 129                 // just sleep to emulate the life time of object referenced by p
 130                 try { sleep(lifetime); }
 131                 catch (InterruptedException e) {}
 132         }
 133 }
 134 
 135 class Memevil extends Thread {
 136         int sum;
 137         int bufsz = 64;
 138         boolean debug = false;
 139 
 140         Memevil(int bufsz) {
 141                 sum = 0;
 142                 this.bufsz = bufsz;
 143         }
 144         /*      Person object is live short, it will be garbage after
 145          *      control returns
 146          */
 147         private boolean doit() {
 148                 try {
 149                         Person p = new Person("Duke", 100, 100, bufsz);
 150                         hr useit = new hr(p, (int)(100*LocalRandom.random()));
 151                         useit.start();
 152                         return true;
 153                 }
 154                 catch (PopulationException e) {
 155                         return false;
 156                 }
 157                 catch (OutOfMemoryError e ) {
 158                         System.err.println(getName() + ": Out of Memory");
 159                         return false;
 160                 }
 161         }
 162         public void run() {
 163                 while ( doit() ) {
 164                         if ( LocalRandom.random() > 0.6668) {
 165                                 try {
 166                                         sleep(10);   // to be nice
 167                                 }
 168                                 catch (InterruptedException e) {
 169                                 }
 170                         }
 171                         Thread.yield();
 172                 }
 173                 //we've reached the population limit, so we're exiting the thread
 174                 ThreadCount.dec();
 175         }
 176 }
 177 
 178 class Escaper extends Thread {
 179         public void run() {
 180                 while ( ThreadCount.get() > 0 ) {
 181                         int buf[] = new int[32];
 182                         {
 183                                                 Thread.yield();
 184                         }
 185                 }
 186         }
 187 }
 188 
 189 public class gctest02 {
 190         public static void main(String args[] ) {
 191                 int bufsz = 8;
 192                 int peopleLimit = 1000;
 193                 long randomSeed = System.currentTimeMillis();
 194                 Memevil me=null;
 195                 if (args.length > 0)
 196                 {
 197                         try
 198                         {
 199                                 peopleLimit = new Integer(args[0]).intValue();
 200                         }
 201                         catch (NumberFormatException e)
 202                         {
 203                                 throw new TestBug(
 204                                         "Bad input to gctest02. Expected integer, got: ->"
 205                                         + args[0] + "<-", e);
 206                         }
 207                 }
 208 
 209                 if (args.length == 2)
 210                 {
 211                         try
 212                         {
 213                                 randomSeed = new Long(args[1]).longValue();
 214                         }
 215                         catch (NumberFormatException e)
 216                         {
 217                                 throw new TestBug(
 218                                         "Bad input to gctest02. Expected long, got: ->"
 219                                         + args[0] + "<-", e);
 220                         }
 221                 }
 222                 Person.setPopulationLimit(peopleLimit);
 223                 System.out.println("Seed value: " + randomSeed);
 224                 for (int ii=0; ii<40; ii++) {
 225                         bufsz = 8;
 226                         LocalRandom.rGen = new Random(randomSeed);
 227                         Person.populationCount = 0;
 228                         Escaper you = new Escaper();
 229                         you.setName("Escaper");
 230                         ThreadCount.inc();
 231                         you.start();
 232                         me = new Memevil(bufsz);
 233                         me.setName("Memevil" + bufsz);
 234                         bufsz = 2*bufsz;
 235                         me.start();
 236                         Thread.yield();
 237                         for (int i=1; i<11; i++) {
 238                                 ThreadCount.inc();
 239                                 me = new Memevil(bufsz);
 240                                 me.setName("Memevil" + bufsz);
 241                                 bufsz = 2*bufsz;
 242                                 me.start();
 243                                 Thread.yield();
 244                         }
 245                         try {
 246                                 you.join();
 247                         }
 248                         catch (InterruptedException e) {
 249                                 throw new TestFailure("InterruptedException in gctest2.main()");
 250                         }
 251                         for (int i=1; i<11; i++) {
 252                                 try { me.join(); }
 253                                 catch (InterruptedException e) {
 254                                         throw new TestFailure("InterruptedException in gctest2.main()");
 255                                 }
 256                         }
 257                 }
 258                 System.out.println("Test passed.");
 259         }
 260 }