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 TestShenandoahStringDedup.java 26 * @summary Test Shenandoah string deduplication implementation 27 * @key gc 28 * @library /test/lib 29 * @modules java.base/jdk.internal.misc:open 30 * @modules java.base/java.lang:open 31 * java.management 32 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 33 * -DtargetStrings=3000000 34 * ShenandoahStrDedupStress 35 * 36 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 37 * -XX:ShenandoahGCHeuristics=aggressive -DtargetStrings=2000000 38 * ShenandoahStrDedupStress 39 * 40 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 41 * -XX:ShenandoahGCHeuristics=aggressive -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 42 * ShenandoahStrDedupStress 43 * 44 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 45 * -XX:ShenandoahGCHeuristics=static -DtargetStrings=4000000 46 * ShenandoahStrDedupStress 47 * 48 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 49 * -XX:ShenandoahGCHeuristics=compact 50 * ShenandoahStrDedupStress 51 * 52 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 53 * -XX:ShenandoahGCHeuristics=passive -XX:+ShenandoahDegeneratedGC -DtargetOverwrites=40000000 54 * ShenandoahStrDedupStress 55 * 56 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 57 * -XX:ShenandoahGCHeuristics=passive -XX:-ShenandoahDegeneratedGC -DtargetOverwrites=40000000 58 * ShenandoahStrDedupStress 59 * 60 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 61 * -XX:ShenandoahGCHeuristics=traversal 62 * ShenandoahStrDedupStress 63 * 64 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 65 * -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=3000000 66 * ShenandoahStrDedupStress 67 * 68 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 69 * -XX:ShenandoahGCHeuristics=compact -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=2000000 70 * ShenandoahStrDedupStress 71 * 72 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 73 * -XX:ShenandoahGCHeuristics=aggressive -XX:ShenandoahUpdateRefsEarly=off -DtargetStrings=2000000 74 * ShenandoahStrDedupStress 75 * 76 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 77 * -XX:ShenandoahGCHeuristics=static -XX:ShenandoahUpdateRefsEarly=off -DtargetOverwrites=4000000 78 * ShenandoahStrDedupStress 79 * 80 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 81 * -XX:ShenandoahGCHeuristics=aggressive -XX:ShenandoahUpdateRefsEarly=off -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 82 * ShenandoahStrDedupStress 83 * 84 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+UseStringDeduplication -Xmx512M -Xlog:gc+stats 85 * -XX:ShenandoahGCHeuristics=traversal -XX:+ShenandoahOOMDuringEvacALot -DtargetStrings=2000000 86 * ShenandoahStrDedupStress 87 */ 88 89 import java.lang.management.*; 90 import java.lang.reflect.*; 91 import java.util.*; 92 import sun.misc.*; 93 94 public class ShenandoahStrDedupStress { 95 private static Field valueField; 96 private static Unsafe unsafe; 97 98 private static long TARGET_STRINGS = Long.getLong("targetStrings", 2_500_000); 99 private static long TARGET_OVERWRITES = Long.getLong("targetOverwrites", 600_000); 100 private static final long MAX_REWRITE_GC_CYCLES = 6; 101 102 private static final int UNIQUE_STRINGS = 20; 103 static { 104 try { 105 Field field = Unsafe.class.getDeclaredField("theUnsafe"); 106 field.setAccessible(true); 107 unsafe = (Unsafe)field.get(null); 108 109 valueField = String.class.getDeclaredField("value"); 110 valueField.setAccessible(true); 111 } catch (Exception e) { 112 throw new RuntimeException(e); 113 } 114 } 115 116 private static Object getValue(String string) { 117 try { 118 return valueField.get(string); 119 } catch (Exception e) { 120 throw new RuntimeException(e); 121 } 122 } 123 124 static class StringAndId { 125 private String str; 126 private int id; 127 public StringAndId(String str, int id) { 128 this.str = str; 129 this.id = id; 130 } 131 132 public String str() { return str; } 133 public int id() { return id; } 134 } 135 136 // Generate uniqueStrings number of strings 137 private static void generateStrings(ArrayList<StringAndId> strs, int uniqueStrings) { 138 Random rn = new Random(); 139 for (int u = 0; u < uniqueStrings; u ++) { 140 int n = rn.nextInt(uniqueStrings); 141 strs.add(new StringAndId("Unique String " + n, n)); 142 } 143 } 144 145 private static int verifyDedepString(ArrayList<StringAndId> strs) { 146 HashMap<Object, StringAndId> seen = new HashMap<>(); 147 int total = 0; 148 int dedup = 0; 149 150 for (StringAndId item : strs) { 151 total ++; 152 StringAndId existingItem = seen.get(getValue(item.str())); 153 if (existingItem == null) { 154 seen.put(getValue(item.str()), item); 155 } else { 156 if (item.id() != existingItem.id() || 157 !item.str().equals(existingItem.str())) { 158 System.out.println("StringDedup error:"); 159 System.out.println("id: " + item.id() + " != " + existingItem.id()); 160 System.out.println("or String: " + item.str() + " != " + existingItem.str()); 161 throw new RuntimeException("StringDedup Test failed"); 162 } else { 163 dedup ++; 164 } 165 } 166 } 167 System.out.println("Dedup: " + dedup + "/" + total + " unique: " + (total - dedup)); 168 return (total - dedup); 169 } 170 171 static volatile ArrayList<StringAndId> astrs = new ArrayList<>(); 172 static GarbageCollectorMXBean gcCycleMBean; 173 174 public static void main(String[] args) { 175 Random rn = new Random(); 176 177 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 178 if ("Shenandoah Cycles".equals(bean.getName())) { 179 gcCycleMBean = bean; 180 break; 181 } 182 } 183 184 if (gcCycleMBean == null) { 185 throw new RuntimeException("Can not find Shenandoah GC cycle mbean"); 186 } 187 188 // Generate roughly TARGET_STRINGS strings, only UNIQUE_STRINGS are unique 189 long genIters = TARGET_STRINGS / UNIQUE_STRINGS; 190 for(long index = 0; index < genIters; index ++) { 191 generateStrings(astrs, UNIQUE_STRINGS); 192 } 193 194 long cycleBeforeRewrite = gcCycleMBean.getCollectionCount(); 195 196 for (long loop = 1; loop < TARGET_OVERWRITES; loop ++) { 197 int arrSize = astrs.size(); 198 int index = rn.nextInt(arrSize); 199 StringAndId item = astrs.get(index); 200 int n = rn.nextInt(UNIQUE_STRINGS); 201 item.str = "Unique String " + n; 202 item.id = n; 203 204 if (loop % 1000 == 0) { 205 // enough GC cycles for rewritten strings to be deduplicated 206 if (gcCycleMBean.getCollectionCount() - cycleBeforeRewrite >= MAX_REWRITE_GC_CYCLES) { 207 break; 208 } 209 } 210 } 211 verifyDedepString(astrs); 212 } 213 }