1 /* 2 * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 /* 25 * @test TestStringDedupStress 26 * @summary Test Shenandoah string deduplication implementation 27 * @key gc 28 * @requires vm.gc.Shenandoah 29 * @library /test/lib 30 * @modules java.base/jdk.internal.misc:open 31 * @modules java.base/java.lang:open 32 * java.management 33 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 34 * -DtargetStrings=3000000 35 * TestStringDedupStress 36 * 37 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 38 * -XX:ShenandoahGCHeuristics=aggressive -DtargetStrings=2000000 39 * TestStringDedupStress 40 * 41 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 42 * -XX:ShenandoahGCHeuristics=aggressive -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 43 * TestStringDedupStress 44 * 45 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 46 * -XX:ShenandoahGCHeuristics=static -DtargetStrings=4000000 47 * TestStringDedupStress 48 * 49 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 50 * -XX:ShenandoahGCHeuristics=compact 51 * TestStringDedupStress 52 * 53 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 54 * -XX:ShenandoahGCHeuristics=passive -XX:+ShenandoahDegeneratedGC -DtargetOverwrites=40000000 55 * TestStringDedupStress 56 * 57 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 58 * -XX:ShenandoahGCHeuristics=passive -XX:-ShenandoahDegeneratedGC -DtargetOverwrites=40000000 59 * TestStringDedupStress 60 * 61 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 62 * -XX:ShenandoahGCHeuristics=traversal 63 * TestStringDedupStress 64 * 65 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 66 * -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=3000000 67 * TestStringDedupStress 68 * 69 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 70 * -XX:ShenandoahGCHeuristics=compact -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=2000000 71 * TestStringDedupStress 72 * 73 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 74 * -XX:ShenandoahGCHeuristics=aggressive -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=2000000 75 * TestStringDedupStress 76 * 77 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 78 * -XX:ShenandoahGCHeuristics=static -XX:ShenandoahUpdateRefsEarly=off -DtargetOverwrites=4000000 79 * TestStringDedupStress 80 * 81 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 82 * -XX:ShenandoahGCHeuristics=aggressive -XX:ShenandoahUpdateRefsEarly=off -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 83 * TestStringDedupStress 84 * 85 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 86 * -XX:ShenandoahGCHeuristics=traversal -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 87 * TestStringDedupStress 88 */ 89 90 import java.lang.management.*; 91 import java.lang.reflect.*; 92 import java.util.*; 93 94 import sun.misc.*; 95 96 public class TestStringDedupStress { 97 private static Field valueField; 98 private static Unsafe unsafe; 99 100 private static long TARGET_STRINGS = Long.getLong("targetStrings", 2_500_000); 101 private static long TARGET_OVERWRITES = Long.getLong("targetOverwrites", 600_000); 102 private static final long MAX_REWRITE_GC_CYCLES = 6; 103 104 private static final int UNIQUE_STRINGS = 20; 105 106 static { 107 try { 108 Field field = Unsafe.class.getDeclaredField("theUnsafe"); 109 field.setAccessible(true); 110 unsafe = (Unsafe) field.get(null); 111 112 valueField = String.class.getDeclaredField("value"); 113 valueField.setAccessible(true); 114 } catch (Exception e) { 115 throw new RuntimeException(e); 116 } 117 } 118 119 private static Object getValue(String string) { 120 try { 121 return valueField.get(string); 122 } catch (Exception e) { 123 throw new RuntimeException(e); 124 } 125 } 126 127 static class StringAndId { 128 private String str; 129 private int id; 130 131 public StringAndId(String str, int id) { 132 this.str = str; 133 this.id = id; 134 } 135 136 public String str() { 137 return str; 138 } 139 140 public int id() { 141 return id; 142 } 143 } 144 145 // Generate uniqueStrings number of strings 146 private static void generateStrings(ArrayList<StringAndId> strs, int uniqueStrings) { 147 Random rn = new Random(); 148 for (int u = 0; u < uniqueStrings; u++) { 149 int n = rn.nextInt(uniqueStrings); 150 strs.add(new StringAndId("Unique String " + n, n)); 151 } 152 } 153 154 private static int verifyDedepString(ArrayList<StringAndId> strs) { 155 HashMap<Object, StringAndId> seen = new HashMap<>(); 156 int total = 0; 157 int dedup = 0; 158 159 for (StringAndId item : strs) { 160 total++; 161 StringAndId existingItem = seen.get(getValue(item.str())); 162 if (existingItem == null) { 163 seen.put(getValue(item.str()), item); 164 } else { 165 if (item.id() != existingItem.id() || 166 !item.str().equals(existingItem.str())) { 167 System.out.println("StringDedup error:"); 168 System.out.println("id: " + item.id() + " != " + existingItem.id()); 169 System.out.println("or String: " + item.str() + " != " + existingItem.str()); 170 throw new RuntimeException("StringDedup Test failed"); 171 } else { 172 dedup++; 173 } 174 } 175 } 176 System.out.println("Dedup: " + dedup + "/" + total + " unique: " + (total - dedup)); 177 return (total - dedup); 178 } 179 180 static volatile ArrayList<StringAndId> astrs = new ArrayList<>(); 181 static GarbageCollectorMXBean gcCycleMBean; 182 183 public static void main(String[] args) { 184 Random rn = new Random(); 185 186 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 187 if ("Shenandoah Cycles".equals(bean.getName())) { 188 gcCycleMBean = bean; 189 break; 190 } 191 } 192 193 if (gcCycleMBean == null) { 194 throw new RuntimeException("Can not find Shenandoah GC cycle mbean"); 195 } 196 197 // Generate roughly TARGET_STRINGS strings, only UNIQUE_STRINGS are unique 198 long genIters = TARGET_STRINGS / UNIQUE_STRINGS; 199 for (long index = 0; index < genIters; index++) { 200 generateStrings(astrs, UNIQUE_STRINGS); 201 } 202 203 long cycleBeforeRewrite = gcCycleMBean.getCollectionCount(); 204 205 for (long loop = 1; loop < TARGET_OVERWRITES; loop++) { 206 int arrSize = astrs.size(); 207 int index = rn.nextInt(arrSize); 208 StringAndId item = astrs.get(index); 209 int n = rn.nextInt(UNIQUE_STRINGS); 210 item.str = "Unique String " + n; 211 item.id = n; 212 213 if (loop % 1000 == 0) { 214 // enough GC cycles for rewritten strings to be deduplicated 215 if (gcCycleMBean.getCollectionCount() - cycleBeforeRewrite >= MAX_REWRITE_GC_CYCLES) { 216 break; 217 } 218 } 219 } 220 verifyDedepString(astrs); 221 } 222 }