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 
  24 /*
  25  * @test
  26  * @key stress gc randomness
  27  *
  28  * @summary converted from VM Testbase gc/gctests/ReferencesGC.
  29  * VM Testbase keywords: [gc, stress, stressopt, nonconcurrent, quick]
  30  *
  31  * @library /vmTestbase
  32  *          /test/lib
  33  * @run driver jdk.test.lib.FileInstaller . .
  34  * @run main/othervm
  35  *      -XX:-UseGCOverheadLimit
  36  *      gc.gctests.ReferencesGC.ReferencesGC
  37  *      -range 200
  38  *      -ratio 0.9
  39  *      -t 1
  40  */
  41 
  42 package gc.gctests.ReferencesGC;
  43 
  44 import java.lang.ref.*;
  45 import nsk.share.TestFailure;
  46 import nsk.share.gc.Algorithms;
  47 import nsk.share.gc.GC;
  48 import nsk.share.gc.ThreadedGCTest;
  49 import nsk.share.gc.gp.GarbageProducer;
  50 import nsk.share.gc.gp.GarbageUtils;
  51 import nsk.share.test.ExecutionController;
  52 
  53 public class ReferencesGC extends ThreadedGCTest {
  54 
  55     static int RANGE = 256;
  56     static float RATIO = (float) 1.0;
  57 
  58     public static void main(String[] args) {
  59         parseArgs(args);
  60         GC.runTest(new ReferencesGC(), args);
  61     }
  62 
  63     public static void parseArgs(String[] args) {
  64         for (int i = 0; i < args.length; i++) {
  65             if (args[i].compareTo("-range") == 0) {
  66                 RANGE = new Integer(args[++i]).intValue();
  67             } else if (args[i].compareTo("-ratio") == 0) {
  68                 RATIO = new Float(args[++i]).floatValue();
  69             }
  70         }
  71     }
  72 
  73     private class Worker implements Runnable {
  74 
  75         static final int WEAK = 0;
  76         static final int SOFT = 1;
  77         static final int PHANTOM = 2;
  78         private ExecutionController stresser;
  79         int finalizationMaxTime = 1000 * 60 * runParams.getNumberOfThreads();
  80         int[] alive = new int[3];
  81         int[] enqued = new int[3];
  82         CircularLinkedList holder[] = new CircularLinkedList[RANGE];
  83         WeakReference wr[] = new WeakReference[RANGE];
  84         SoftReference sr[] = new SoftReference[RANGE];
  85         PhantomReference phr[] = new PhantomReference[RANGE];
  86         ReferenceQueue refq = new ReferenceQueue();
  87         GarbageProducer gp = GarbageUtils.getArrayProducers().get(0);
  88         int iter = 0;
  89 
  90         @Override
  91         public void run() {
  92             if (stresser == null) {
  93                 stresser = getExecutionController();
  94             }
  95 
  96             while (stresser.continueExecution()) {
  97                 int totalQ = 0;
  98                 try {
  99                     refq = new ReferenceQueue();
 100                     alive = new int[3];
 101                     enqued = new int[3];
 102                     for (int j = 0; j < RANGE; j++) {
 103                         holder[j] = new CircularLinkedList();
 104                         holder[j].addNelements(300);
 105                         wr[j] = new WeakReference(holder[j], refq);
 106                         sr[j] = new SoftReference(holder[j], refq);
 107                         phr[j] = new PhantomReference(holder[j], refq);
 108                     }
 109                 } catch (OutOfMemoryError oome) {
 110                     // we should just skip the test
 111                     // the other thread could eat all memory
 112                     continue;
 113                 }
 114 
 115                 for (int i = 0; i < RANGE; i++) {
 116                     if (wr[i].isEnqueued()) {
 117                         ++totalQ;
 118                     }
 119                     if (sr[i].isEnqueued()) {
 120                         ++totalQ;
 121                     }
 122                     if (phr[i].isEnqueued()) {
 123                         ++totalQ;
 124                     }
 125                 }
 126                 if (totalQ != 0) {
 127                     throw new TestFailure("There are " + totalQ + " references in the queue instead 0 before null-assigment.");
 128                 }
 129 
 130                 for (int i = 0; i < (int) (RANGE * RATIO); i++) {
 131                     holder[i] = null;
 132                 }
 133 
 134                 Algorithms.eatMemory(stresser);
 135                 if (!stresser.continueExecution()) {
 136                     break;
 137                 }
 138                 // At this point OOME was thrown and accordingly to spec
 139                 // all weak refs should be processed
 140 
 141                 alive = new int[3];
 142                 enqued = new int[3];
 143                 for (int i = 0; i < RANGE; i++) {
 144                     if (wr[i].get() != null) {
 145                         ++alive[WEAK];
 146                     }
 147                     if (wr[i].isEnqueued()) {
 148                         ++enqued[WEAK];
 149                     }
 150                     if (sr[i].get() != null) {
 151                         ++alive[SOFT];
 152                     }
 153                     if (sr[i].isEnqueued()) {
 154                         ++enqued[SOFT];
 155                     }
 156                     if (phr[i].isEnqueued()) {
 157                         ++enqued[PHANTOM];
 158                     }
 159                 }
 160 
 161                 long waitTime = System.currentTimeMillis() + finalizationMaxTime;
 162                 while (totalQ < (RANGE * RATIO * 3 * 0.9) && (System.currentTimeMillis() < waitTime)) {
 163                     alive = new int[3];
 164                     enqued = new int[3];
 165                     for (int i = 0; i < RANGE; i++) {
 166                         if (wr[i].get() != null) {
 167                             ++alive[WEAK];
 168                         }
 169                         if (wr[i].isEnqueued()) {
 170                             ++enqued[WEAK];
 171                         }
 172                         if (sr[i].get() != null) {
 173                             ++alive[SOFT];
 174                         }
 175                         if (sr[i].isEnqueued()) {
 176                             ++enqued[SOFT];
 177                         }
 178                         if (phr[i].isEnqueued()) {
 179                             ++enqued[PHANTOM];
 180                         }
 181                     }
 182                     totalQ = (enqued[WEAK] + enqued[SOFT] + enqued[PHANTOM]);
 183                     if (totalQ < (int) (3 * RANGE * RATIO * 0.9)) {
 184                         log.debug("After null-assignment to " + (int) (RANGE * RATIO) +
 185                                 //" elements from " + lower + " to " + (upper - 1) +
 186                                 " and provoking gc found:\n\t" +
 187                                 enqued[WEAK] + " weak\n\t" +
 188                                 enqued[SOFT] + " soft\n\t" +
 189                                 enqued[PHANTOM] + " phantom " +
 190                                 " queuened refs and \n\t" +
 191                                 alive[WEAK] + " weak\n\t" +
 192                                 alive[SOFT] + " soft\n\t" +
 193                                 "alive refs.");
 194                         try {
 195                             log.debug("sleeping to give gc one more chance ......");
 196                             Thread.sleep(1000);
 197                         } catch (InterruptedException ie) {
 198                         }
 199                     }
 200                 }
 201                 log.debug("iteration.... " + iter++);
 202                 if (totalQ < (int) (3 * RANGE * RATIO * 0.9) || totalQ > (int) (3 * RANGE * RATIO)) {
 203                     throw new TestFailure("Test failed");
 204                 }
 205             }
 206         }
 207     }
 208 
 209     @Override
 210     protected Runnable createRunnable(int i) {
 211         return new Worker();
 212     }
 213 }