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 }