1 /*
   2  * Copyright (c) 2002, 2020, 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 /*
  26  * @test
  27  * @key gc randomness
  28  *
  29  * @summary converted from VM Testbase gc/gctests/WeakReferenceGC.
  30  * VM Testbase keywords: [gc, nonconcurrent]
  31  * VM Testbase readme:
  32  * *******************************************
  33  * set timeout = 25 when running this test
  34  * *******************************************
  35  * This tests checks to see if the garbage collector enqueues
  36  * a weak reference when referrent has been turned to garbage.
  37  * Weak references are enqueued in  a non-deterministic way
  38  * by the garbage collector, so the test uses a heuristic to
  39  * determine whether the references are being enqueued in a timely
  40  * manner which in turn determines whether outcome of the test.
  41  * IF the user invokes the test with the following command line
  42  * parameters :
  43  *   java WeakReferenceGC -qFactor 0.9 -gcCount 5
  44  * the test expects that 90% of all objects with only weak references
  45  * pointing to them will be enqueued within 5 calls to the garbage collector.
  46  * When I ran the test, I consistently got figures of 98% enqueueing
  47  * with just 1 call to the garbage collector. So if this test fails,
  48  * at its current settings, the garbage collector is not performing as well
  49  * as it used to.
  50  * The test creates circular linked lists of size 0.1Meg each. The number
  51  * of lists created can be set via the -numLists flag. The default
  52  * value is 50.
  53  * The circular linked lists have both strong and weak references pointing
  54  * to them. The strong and weak references are kept in arrays.
  55  * The strong references are all nulled out and System.gc() is called
  56  * explicitly and the heuristic is applied. If the test does not
  57  * satisfy the heuristic or an OutOfMemory exception is thrown,
  58  * the test fails.
  59  * Array containing    Each circular linked list        Array containing
  60  * weak references     is 0.1 Meg each and has          strong references
  61  * to linked lists.    a weak reference, W<n> and a     to linked lists.
  62  *                     strong reference, x<n>
  63  *                     pointing to it.
  64  *  ----      ----------------------------        -----
  65  * |    |     |   ----             ---- <-|      |     |
  66  * | W1 |-->  -->|    |---.......>|    |   <---- |  x1 |
  67  * |    |     -->|    |<---.......|    |<--      |     |
  68  *  ----      |   ----       1000  ---   |        -----
  69  *            ---------------------------
  70  *   .                                              .
  71  *   .                                              .
  72  *   .                                              .
  73  *   .                                              .
  74  *   .                                              .  10
  75  *   .                                              .
  76  *  ----      ----------------------------        -----
  77  * |    |     |   ----             ---- <-|      |     |
  78  * | Wn |-->  -->|    |---.......>|    |   <---- |  xn |
  79  * |    |     -->|    |<---.......|    |<--      |     |
  80  *  ----      |   ----       1000  ---   |        -----
  81  *            ---------------------------
  82  *
  83  * @library /vmTestbase
  84  *          /test/lib
  85  * @run driver jdk.test.lib.FileInstaller . .
  86  * @run main/othervm
  87  *      gc.gctests.WeakReferenceGC.WeakReferenceGC
  88  *      -numList 50
  89  *      -qFactor 0.9
  90  *      -gcCount 5
  91  *      -iter 100
  92  */
  93 
  94 package gc.gctests.WeakReferenceGC;
  95 
  96 import java.util.*;
  97 import java.lang.ref.*;
  98 import nsk.share.TestFailure;
  99 import nsk.share.gc.GC;
 100 import nsk.share.gc.ThreadedGCTest;
 101 import nsk.share.gc.gp.GarbageUtils;
 102 
 103 public class WeakReferenceGC extends ThreadedGCTest {
 104 
 105         // A heuristic is used to determine the outcome(pass/fail
 106         // status) of a test. If 90% of all objects that have
 107         // _only_ weak references pointing to them are garbage
 108         // collected with 5 explicit calls to the garbage collector
 109         // the test is deemed a pass. The following two variables
 110         // are used to define this heuristic: gcCount, qFactor
 111 
 112         static String args[];
 113 
 114         CircularLinkedList holder[];
 115 
 116         int loopCount = 100; // # of times test is performed
 117 
 118         int memory_reserve[];
 119         int gcCount = 5;
 120         int numLists = 50; // number of linked lists
 121         float qFactor = (float) 0.9;
 122         ReferenceQueue refQueue;
 123         Vector results;
 124         WeakReference wholder[];
 125 
 126         public static void main(String[] args) {
 127                 WeakReferenceGC.args = args;
 128                 GC.runTest(new WeakReferenceGC(), args);
 129         }
 130 
 131         WeakReferenceGC() {
 132                 holder = new CircularLinkedList[numLists];
 133                 wholder = new WeakReference[numLists];
 134                 refQueue = new ReferenceQueue();
 135                 results = new Vector();
 136         }
 137 
 138         protected Runnable createRunnable(int i) {
 139                 return i > 0 ? null : new Worker();
 140         }
 141 
 142         private void dumpTestResults() {
 143                 double objectsRecovered;
 144 
 145                 System.out.println("Percentage of Objects" + "  # of GC's");
 146                 System.out.println("    Recovered         " + " Required");
 147                 for (int i = 0; i < results.size(); i++) {
 148                         Statistic s = (Statistic) results.elementAt(i);
 149                         objectsRecovered = Math.rint((float) (s.numEnqueued)
 150                                         / (float) (numLists) * 100.0);
 151                         System.out.println("        " + objectsRecovered
 152                                         + " %             " + s.iterations);
 153                 }
 154         }
 155 
 156         private boolean hasPassed() {
 157                 boolean passed;
 158                 passed = true; // assume passed till proven otherwise
 159 
 160                 for (int i = 0; i < results.size(); i++) {
 161                         Statistic s = (Statistic) results.elementAt(i);
 162                         if ((s.iterations > gcCount)
 163                                         || (s.numEnqueued < (int) (numLists * qFactor))) {
 164                                 passed = false;
 165                                 break; // test failed
 166                         }
 167                 }
 168                 return passed;
 169         }
 170 
 171         private void parseTestParams(String args[]) {
 172                 for (int i = 0; i < args.length; i++) {
 173                         if (args[i].compareTo("-numList") == 0) {
 174                                 numLists = new Integer(args[++i]).intValue();
 175                         } else if (args[i].compareTo("-qFactor") == 0) {
 176                                 qFactor = new Float(args[++i]).floatValue();
 177                         } else if (args[i].compareTo("-gcCount") == 0) {
 178                                 gcCount = new Integer(args[++i]).intValue();
 179                         } else if (args[i].compareTo("-iter") == 0) {
 180                                 loopCount = new Integer(args[++i]).intValue();
 181                                 // } else {
 182                                 // System.err.println("usage : " +
 183                                 // "java WeakReferenceGC [-numList <n>] " +
 184                                 // "[-qFactor <0.x>] [-gcCount <n>] [-iter <n>]");
 185                                 // throw new TestBug("Invalid arguments");
 186                         }
 187                 }
 188         }
 189 
 190         private void persistentGC() {
 191                 int numEnqueued, iter, qCriterion;
 192 
 193                 numEnqueued = 0; // number of weakReference enqueued
 194                 iter = 0;
 195                 qCriterion = (int) (numLists * qFactor);
 196 
 197                 while ((numEnqueued < qCriterion) && (iter <= gcCount)) {
 198                         iter++;
 199                         if (!getExecutionController().continueExecution()) {
 200                                 return;
 201                         }
 202                         if (GarbageUtils.eatMemory(getExecutionController()) == 0) {
 203                                 return; // We were unable to provoke OOME before timeout is over
 204                         }
 205                         numEnqueued = 0; // We set counter to zero to avoid counting references twice
 206                         for (int i = 0; i < numLists; i++) {
 207                                 if (wholder[i].isEnqueued()) {
 208                                         numEnqueued++;
 209                                 }
 210                         }
 211                 }
 212                 results.addElement((new Statistic(iter, numEnqueued)));
 213         }
 214 
 215         private void runTest() {
 216                 int iter;
 217                 iter = 1;
 218                 try {
 219                         do {
 220                                 for (int i = 0; i < numLists; i++) {
 221                                         holder[i] = new CircularLinkedList();
 222                                         holder[i].addNelements(1000);
 223                                         wholder[i] = new WeakReference(holder[i], refQueue);
 224                                 }
 225 
 226                                 for (int i = 0; i < numLists; i++) {
 227                                         holder[i] = null;
 228                                 }
 229 
 230                                 if (!getExecutionController().continueExecution()) {
 231                                         return;
 232                                 }
 233                                 persistentGC();
 234 
 235                                 iter++;
 236                         } while (iter <= loopCount);
 237                 } catch (OutOfMemoryError e) {
 238                         memory_reserve = null;
 239                         System.gc();
 240                         throw new TestFailure("Failed at iteration=" + loopCount);
 241                 }
 242         }
 243 
 244         //We can't override run() method in WeakReferenceGC, so we are carrying out it to Worker
 245         private class Worker implements Runnable {
 246                 @Override
 247                 public void run() {
 248                         parseTestParams(args);
 249                         runTest();
 250                         dumpTestResults();
 251                         boolean passed = hasPassed();
 252                         if (passed == true) {
 253                                 log.info("Test passed.");
 254                         } else {
 255                                 log.error("Test failed.");
 256                                 setFailed(true);
 257                         }
 258                 }
 259         }
 260 }
 261 
 262 class Statistic {
 263         int iterations;
 264         int numEnqueued;
 265 
 266         Statistic(int i, int num) {
 267                 iterations = i;
 268                 numEnqueued = num;
 269         }
 270 
 271 }