1 /*
   2  * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
   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:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions                                         -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  33  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=aggressive   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  34  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=aggressive   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:+ShenandoahOOMDuringEvacALot ShenandoahStrDedupStress
  35  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=dynamic      -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  36  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=continuous   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  37  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=passive      -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  38  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=generational -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  39  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=LRU          -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  40  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=connected    -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats ShenandoahStrDedupStress
  41  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions                                         -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:ShenandoahUpdateRefsEarly=off ShenandoahStrDedupStress
  42  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=continuous   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:ShenandoahUpdateRefsEarly=off ShenandoahStrDedupStress
  43  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=aggressive   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:ShenandoahUpdateRefsEarly=off ShenandoahStrDedupStress
  44  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=dynamic      -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:ShenandoahUpdateRefsEarly=off ShenandoahStrDedupStress
  45  * @run main/othervm -XX:+UseShenandoahGC -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCHeuristics=aggressive   -XX:+UseStringDeduplication -Xmx2G -Xlog:gc+stats -XX:ShenandoahUpdateRefsEarly=off -XX:+ShenandoahOOMDuringEvacALot ShenandoahStrDedupStress
  46  */
  47 
  48 import java.lang.reflect.*;
  49 import java.util.*;
  50 import sun.misc.*;
  51 
  52 public class ShenandoahStrDedupStress {
  53   private static Field valueField;
  54   private static Unsafe unsafe;
  55 
  56   private static final int UniqueStrings = 20;
  57   static {
  58     try {
  59       Field field = Unsafe.class.getDeclaredField("theUnsafe");
  60       field.setAccessible(true);
  61       unsafe = (Unsafe)field.get(null);
  62 
  63       valueField = String.class.getDeclaredField("value");
  64       valueField.setAccessible(true);
  65     } catch (Exception e) {
  66       throw new RuntimeException(e);
  67     }
  68   }
  69 
  70   private static Object getValue(String string) {
  71     try {
  72       return valueField.get(string);
  73     } catch (Exception e) {
  74         throw new RuntimeException(e);
  75     }
  76   }
  77 
  78   static class StringAndId {
  79     private String str;
  80     private int    id;
  81     public StringAndId(String str, int id) {
  82       this.str = str;
  83       this.id = id;
  84     }
  85 
  86     public String str() { return str; }
  87     public int    id()  { return id;  }
  88   }
  89 
  90   private static void generateStrings(ArrayList<StringAndId> strs, int unique_strs) {
  91     Random rn = new Random();
  92     for (int u = 0; u < unique_strs; u ++) {
  93       int n = rn.nextInt() % 10;
  94       n = Math.max(n, 2);
  95       for (int index = 0; index < n; index ++) {
  96           strs.add(new StringAndId("Unique String " + u, u));
  97       }
  98     }
  99   }
 100 
 101   private static int verifyDedepString(ArrayList<StringAndId> strs) {
 102     HashMap<Object, StringAndId> seen = new HashMap<>();
 103     int total = 0;
 104     int dedup = 0;
 105 
 106     for (StringAndId item : strs) {
 107       total ++;
 108       StringAndId existing_item = seen.get(getValue(item.str()));
 109       if (existing_item == null) {
 110         seen.put(getValue(item.str()), item);
 111       } else {
 112         if (item.id() != existing_item.id() ||
 113             !item.str().equals(existing_item.str())) {
 114           System.out.println("StringDedup error:");
 115           System.out.println("String: " + item.str() + " != " + existing_item.str());
 116           throw new RuntimeException("StringDedup Test failed");
 117         } else {
 118           dedup ++;
 119         }
 120       }
 121     }
 122     System.out.println("Dedup: " + dedup + "/" + total + " unique: "  + (total - dedup));
 123     return (total - dedup);
 124   }
 125 
 126   static volatile ArrayList<StringAndId> astrs = new ArrayList<>();
 127   public static void main(String[] args) {
 128     Random rn = new Random();
 129 
 130     for(int index = 0; index < 100000; index ++) {
 131       generateStrings(astrs, UniqueStrings);
 132     }
 133 
 134     for (int loop = 1; loop < 10000; loop ++) {
 135       for (int index = 0; index < 10000; index ++) {
 136         StringAndId item = astrs.get(index);
 137         int n = rn.nextInt() % UniqueStrings;
 138         item.str = "Unique String " + n;
 139       }
 140     }
 141 
 142     verifyDedepString(astrs);
 143   }
 144 }