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