1 /*
   2  * Copyright (c) 2011, 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/StringInternSyncWithGC.
  29  * VM Testbase keywords: [gc, stress, stressopt, feature_perm_removal_jdk7, nonconcurrent]
  30  * VM Testbase readme:
  31  * The test verifies that String.intern is correctly synchronized with GC.
  32  * Test interns and drop the same strings in different threads and provokes GC.
  33  * Additionally test creates weak/soft references to interned strings.
  34  * Test fails if any string object is inaccessible.
  35  *
  36  * @library /vmTestbase
  37  *          /test/lib
  38  * @run driver jdk.test.lib.FileInstaller . .
  39  * @run main/othervm
  40  *      -Xlog:gc:gc.log
  41  *      gc.gctests.StringInternSyncWithGC.StringInternSyncWithGC
  42  *      -ms low
  43  *      -memUsage 3
  44  *      -appTimeout 30
  45  *      -capacityVerPart 2
  46  */
  47 
  48 package gc.gctests.StringInternSyncWithGC;
  49 
  50 import java.util.ArrayList;
  51 import java.util.List;
  52 
  53 import nsk.share.gc.*;
  54 import nsk.share.gc.gp.MemoryStrategy;
  55 import nsk.share.gc.gp.MemoryStrategyAware;
  56 import nsk.share.gc.gp.string.RandomStringProducer;
  57 import nsk.share.test.ExecutionController;
  58 
  59 public class StringInternSyncWithGC extends ThreadedGCTest implements MemoryStrategyAware {
  60 
  61     // Maximum size of one string
  62     // Depends from all size and memory strategy
  63     private int maxStringSize;
  64     private MemoryStrategy memoryStrategy;
  65     private final int memUsageFactor;
  66     private final long endTimeCapacityVer;
  67 
  68     // The list of strings which are interned during iteration
  69     private final List<String> stringsToIntern = new ArrayList();
  70     private final RandomStringProducer gp = new RandomStringProducer();
  71 
  72     public StringInternSyncWithGC(int memUsage, long endTimeCapVer) {
  73         memUsageFactor = memUsage;
  74         endTimeCapacityVer = endTimeCapVer;
  75     }
  76 
  77     @Override
  78     public void setMemoryStrategy(MemoryStrategy memoryStrategy) {
  79         this.memoryStrategy = memoryStrategy;
  80     }
  81 
  82     /**
  83      * Verify that we could use certain amount of memory.
  84      */
  85     private boolean verifyInternedStringCapacity(long initialSize) {
  86         long currentSize = 0;
  87         final int STEP = 1000;
  88         int iter = 0;
  89         char[] template = new char[(int) (initialSize / STEP)];
  90 
  91         List<String> tmpList = new ArrayList<>(STEP);
  92         try {
  93             while (currentSize <= initialSize) {
  94                 if (endTimeCapacityVer < System.currentTimeMillis()) {
  95                     log.debug("Too long to verify interned string capacity");
  96                     log.debug("Silently pass.");
  97                     return false;
  98                 }
  99                 template[iter]++;
 100                 if (++iter == template.length) {
 101                     iter = 0;
 102                 }
 103                 String str = new String(template);
 104                 tmpList.add(str.intern());
 105                 currentSize += str.length() * 2; //each char costs 2 bytes
 106             }
 107         } catch (OutOfMemoryError oome) {
 108             log.debug("It is not possible to allocate " + initialSize + " size of interned string.");
 109             log.debug("Silently pass.");
 110             return false;
 111         }
 112         return true;
 113     }
 114 
 115     @Override
 116     public void run() {
 117         long size = runParams.getTestMemory() / memUsageFactor;
 118         if (!verifyInternedStringCapacity(size)) {
 119             return;
 120         }
 121         // Approximate size occupied by all interned strings
 122         long sizeOfAllInternedStrings = size / 2;
 123         maxStringSize = (int) (sizeOfAllInternedStrings / memoryStrategy.getSize(sizeOfAllInternedStrings, Memory.getObjectExtraSize()));
 124         // Each thread keeps reference to each created string.
 125         long extraConsumption = runParams.getNumberOfThreads() * Memory.getReferenceSize();
 126         log.debug("The overall size of interned strings  : " + sizeOfAllInternedStrings / (1024 * 1024) + "M");
 127         log.debug("The count of interned strings : " + sizeOfAllInternedStrings / (maxStringSize + extraConsumption));
 128         for (long currentSize = 0; currentSize <= sizeOfAllInternedStrings;
 129                 currentSize += maxStringSize + extraConsumption) {
 130             stringsToIntern.add(gp.create(maxStringSize));
 131         }
 132         super.run();
 133     }
 134 
 135     @Override
 136     protected Runnable createRunnable(int threadId) {
 137         return new StringGenerator(threadId, this);
 138     }
 139 
 140     public static void main(String[] args) {
 141         int appTimeout = -1;
 142         int memUsageFactor = 1;
 143         // Part of time that function verifyInternedStringCapacity can take. Time = Application_Timeout / capacityVerTimePart
 144         double capacityVerPart = 2;
 145         for (int i = 0; i < args.length; ++i) {
 146             switch (args[i]) {
 147                 case "-memUsage":
 148                     memUsageFactor = Integer.parseInt(args[i + 1]);
 149                     break;
 150                 case "-capacityVerPart":
 151                     capacityVerPart = Double.parseDouble(args[i + 1]);
 152                     break;
 153                 case "-appTimeout":
 154                     appTimeout = Integer.parseInt(args[i + 1]);
 155                     break;
 156                 default:
 157             }
 158         }
 159         if (appTimeout == -1) {
 160             throw new IllegalArgumentException("Specify -appTimeout.");
 161         }
 162         long endTimeCapacityVer = System.currentTimeMillis() + (long) (appTimeout / capacityVerPart * 60000);
 163         GC.runTest(new StringInternSyncWithGC(memUsageFactor, endTimeCapacityVer), args);
 164     }
 165 
 166     protected List<String> getStringsToIntern() {
 167         return stringsToIntern;
 168     }
 169 
 170     protected int getNumberOfThreads() {
 171         return runParams.getNumberOfThreads();
 172     }
 173 
 174     protected RandomStringProducer getGarbageProducer() {
 175         return gp;
 176     }
 177 
 178     protected int getMaxStringSize() {
 179         return maxStringSize;
 180     }
 181 
 182     protected ExecutionController getExecController() {
 183         return getExecutionController();
 184     }
 185 }