test/gc/g1/TestStringDeduplicationTools.java

Tue, 18 Mar 2014 19:07:22 +0100

author
pliden
date
Tue, 18 Mar 2014 19:07:22 +0100
changeset 6413
595c0f60d50d
child 6548
fd8ddf2d2f6b
permissions
-rw-r--r--

8029075: String deduplication in G1
Summary: Implementation of JEP 192, http://openjdk.java.net/jeps/192
Reviewed-by: brutisso, tschatzl, coleenp

pliden@6413 1 /*
pliden@6413 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
pliden@6413 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
pliden@6413 4 *
pliden@6413 5 * This code is free software; you can redistribute it and/or modify it
pliden@6413 6 * under the terms of the GNU General Public License version 2 only, as
pliden@6413 7 * published by the Free Software Foundation.
pliden@6413 8 *
pliden@6413 9 * This code is distributed in the hope that it will be useful, but WITHOUT
pliden@6413 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
pliden@6413 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
pliden@6413 12 * version 2 for more details (a copy is included in the LICENSE file that
pliden@6413 13 * accompanied this code).
pliden@6413 14 *
pliden@6413 15 * You should have received a copy of the GNU General Public License version
pliden@6413 16 * 2 along with this work; if not, write to the Free Software Foundation,
pliden@6413 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
pliden@6413 18 *
pliden@6413 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
pliden@6413 20 * or visit www.oracle.com if you need additional information or have any
pliden@6413 21 * questions.
pliden@6413 22 */
pliden@6413 23
pliden@6413 24 /*
pliden@6413 25 * Common code for string deduplication tests
pliden@6413 26 */
pliden@6413 27
pliden@6413 28 import java.lang.management.*;
pliden@6413 29 import java.lang.reflect.*;
pliden@6413 30 import java.security.*;
pliden@6413 31 import java.util.*;
pliden@6413 32 import com.oracle.java.testlibrary.*;
pliden@6413 33 import sun.misc.*;
pliden@6413 34
pliden@6413 35 class TestStringDeduplicationTools {
pliden@6413 36 private static final String YoungGC = "YoungGC";
pliden@6413 37 private static final String FullGC = "FullGC";
pliden@6413 38
pliden@6413 39 private static final int Xmn = 50; // MB
pliden@6413 40 private static final int Xms = 100; // MB
pliden@6413 41 private static final int Xmx = 100; // MB
pliden@6413 42 private static final int MB = 1024 * 1024;
pliden@6413 43 private static final int StringLength = 50;
pliden@6413 44
pliden@6413 45 private static Field valueField;
pliden@6413 46 private static Unsafe unsafe;
pliden@6413 47 private static byte[] dummy;
pliden@6413 48
pliden@6413 49 static {
pliden@6413 50 try {
pliden@6413 51 Field field = Unsafe.class.getDeclaredField("theUnsafe");
pliden@6413 52 field.setAccessible(true);
pliden@6413 53 unsafe = (Unsafe)field.get(null);
pliden@6413 54
pliden@6413 55 valueField = String.class.getDeclaredField("value");
pliden@6413 56 valueField.setAccessible(true);
pliden@6413 57 } catch (Exception e) {
pliden@6413 58 throw new RuntimeException(e);
pliden@6413 59 }
pliden@6413 60 }
pliden@6413 61
pliden@6413 62 private static Object getValue(String string) {
pliden@6413 63 try {
pliden@6413 64 return valueField.get(string);
pliden@6413 65 } catch (Exception e) {
pliden@6413 66 throw new RuntimeException(e);
pliden@6413 67 }
pliden@6413 68 }
pliden@6413 69
pliden@6413 70 private static void doFullGc(int numberOfTimes) {
pliden@6413 71 for (int i = 0; i < numberOfTimes; i++) {
pliden@6413 72 System.out.println("Begin: Full GC " + (i + 1) + "/" + numberOfTimes);
pliden@6413 73 System.gc();
pliden@6413 74 System.out.println("End: Full GC " + (i + 1) + "/" + numberOfTimes);
pliden@6413 75 }
pliden@6413 76 }
pliden@6413 77
pliden@6413 78 private static void doYoungGc(int numberOfTimes) {
pliden@6413 79 // Provoke at least numberOfTimes young GCs
pliden@6413 80 final int objectSize = 128;
pliden@6413 81 final int maxObjectInYoung = (Xmn * MB) / objectSize;
pliden@6413 82 for (int i = 0; i < numberOfTimes; i++) {
pliden@6413 83 System.out.println("Begin: Young GC " + (i + 1) + "/" + numberOfTimes);
pliden@6413 84 for (int j = 0; j < maxObjectInYoung + 1; j++) {
pliden@6413 85 dummy = new byte[objectSize];
pliden@6413 86 }
pliden@6413 87 System.out.println("End: Young GC " + (i + 1) + "/" + numberOfTimes);
pliden@6413 88 }
pliden@6413 89 }
pliden@6413 90
pliden@6413 91 private static void forceDeduplication(int ageThreshold, String gcType) {
pliden@6413 92 // Force deduplication to happen by either causing a FullGC or a YoungGC.
pliden@6413 93 // We do several collections to also provoke a situation where the the
pliden@6413 94 // deduplication thread needs to yield while processing the queue. This
pliden@6413 95 // also tests that the references in the deduplication queue are adjusted
pliden@6413 96 // accordingly.
pliden@6413 97 if (gcType.equals(FullGC)) {
pliden@6413 98 doFullGc(3);
pliden@6413 99 } else {
pliden@6413 100 doYoungGc(ageThreshold + 3);
pliden@6413 101 }
pliden@6413 102 }
pliden@6413 103
pliden@6413 104 private static String generateString(int id) {
pliden@6413 105 StringBuilder builder = new StringBuilder(StringLength);
pliden@6413 106
pliden@6413 107 builder.append("DeduplicationTestString:" + id + ":");
pliden@6413 108
pliden@6413 109 while (builder.length() < StringLength) {
pliden@6413 110 builder.append('X');
pliden@6413 111 }
pliden@6413 112
pliden@6413 113 return builder.toString();
pliden@6413 114 }
pliden@6413 115
pliden@6413 116 private static ArrayList<String> createStrings(int total, int unique) {
pliden@6413 117 System.out.println("Creating strings: total=" + total + ", unique=" + unique);
pliden@6413 118 if (total % unique != 0) {
pliden@6413 119 throw new RuntimeException("Total must be divisible by unique");
pliden@6413 120 }
pliden@6413 121
pliden@6413 122 ArrayList<String> list = new ArrayList<String>(total);
pliden@6413 123 for (int j = 0; j < total / unique; j++) {
pliden@6413 124 for (int i = 0; i < unique; i++) {
pliden@6413 125 list.add(generateString(i));
pliden@6413 126 }
pliden@6413 127 }
pliden@6413 128
pliden@6413 129 return list;
pliden@6413 130 }
pliden@6413 131
pliden@6413 132 private static void verifyStrings(ArrayList<String> list, int uniqueExpected) {
pliden@6413 133 for (;;) {
pliden@6413 134 // Check number of deduplicated strings
pliden@6413 135 ArrayList<Object> unique = new ArrayList<Object>(uniqueExpected);
pliden@6413 136 for (String string: list) {
pliden@6413 137 Object value = getValue(string);
pliden@6413 138 boolean uniqueValue = true;
pliden@6413 139 for (Object obj: unique) {
pliden@6413 140 if (obj == value) {
pliden@6413 141 uniqueValue = false;
pliden@6413 142 break;
pliden@6413 143 }
pliden@6413 144 }
pliden@6413 145
pliden@6413 146 if (uniqueValue) {
pliden@6413 147 unique.add(value);
pliden@6413 148 }
pliden@6413 149 }
pliden@6413 150
pliden@6413 151 System.out.println("Verifying strings: total=" + list.size() +
pliden@6413 152 ", uniqueFound=" + unique.size() +
pliden@6413 153 ", uniqueExpected=" + uniqueExpected);
pliden@6413 154
pliden@6413 155 if (unique.size() == uniqueExpected) {
pliden@6413 156 System.out.println("Deduplication completed");
pliden@6413 157 break;
pliden@6413 158 } else {
pliden@6413 159 System.out.println("Deduplication not completed, waiting...");
pliden@6413 160
pliden@6413 161 // Give the deduplication thread time to complete
pliden@6413 162 try {
pliden@6413 163 Thread.sleep(1000);
pliden@6413 164 } catch (Exception e) {
pliden@6413 165 throw new RuntimeException(e);
pliden@6413 166 }
pliden@6413 167 }
pliden@6413 168 }
pliden@6413 169 }
pliden@6413 170
pliden@6413 171 private static OutputAnalyzer runTest(String... extraArgs) throws Exception {
pliden@6413 172 String[] defaultArgs = new String[] {
pliden@6413 173 "-Xmn" + Xmn + "m",
pliden@6413 174 "-Xms" + Xms + "m",
pliden@6413 175 "-Xmx" + Xmx + "m",
pliden@6413 176 "-XX:+UseG1GC",
pliden@6413 177 "-XX:+UnlockDiagnosticVMOptions",
pliden@6413 178 "-XX:+VerifyAfterGC" // Always verify after GC
pliden@6413 179 };
pliden@6413 180
pliden@6413 181 ArrayList<String> args = new ArrayList<String>();
pliden@6413 182 args.addAll(Arrays.asList(defaultArgs));
pliden@6413 183 args.addAll(Arrays.asList(extraArgs));
pliden@6413 184
pliden@6413 185 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()]));
pliden@6413 186 OutputAnalyzer output = new OutputAnalyzer(pb.start());
pliden@6413 187 System.err.println(output.getStderr());
pliden@6413 188 System.out.println(output.getStdout());
pliden@6413 189 return output;
pliden@6413 190 }
pliden@6413 191
pliden@6413 192 private static class DeduplicationTest {
pliden@6413 193 public static void main(String[] args) {
pliden@6413 194 System.out.println("Begin: DeduplicationTest");
pliden@6413 195
pliden@6413 196 final int numberOfStrings = Integer.parseUnsignedInt(args[0]);
pliden@6413 197 final int numberOfUniqueStrings = Integer.parseUnsignedInt(args[1]);
pliden@6413 198 final int ageThreshold = Integer.parseUnsignedInt(args[2]);
pliden@6413 199 final String gcType = args[3];
pliden@6413 200
pliden@6413 201 ArrayList<String> list = createStrings(numberOfStrings, numberOfUniqueStrings);
pliden@6413 202 forceDeduplication(ageThreshold, gcType);
pliden@6413 203 verifyStrings(list, numberOfUniqueStrings);
pliden@6413 204
pliden@6413 205 System.out.println("End: DeduplicationTest");
pliden@6413 206 }
pliden@6413 207
pliden@6413 208 public static OutputAnalyzer run(int numberOfStrings, int ageThreshold, String gcType, String... extraArgs) throws Exception {
pliden@6413 209 String[] defaultArgs = new String[] {
pliden@6413 210 "-XX:+UseStringDeduplication",
pliden@6413 211 "-XX:StringDeduplicationAgeThreshold=" + ageThreshold,
pliden@6413 212 DeduplicationTest.class.getName(),
pliden@6413 213 "" + numberOfStrings,
pliden@6413 214 "" + numberOfStrings / 2,
pliden@6413 215 "" + ageThreshold,
pliden@6413 216 gcType
pliden@6413 217 };
pliden@6413 218
pliden@6413 219 ArrayList<String> args = new ArrayList<String>();
pliden@6413 220 args.addAll(Arrays.asList(extraArgs));
pliden@6413 221 args.addAll(Arrays.asList(defaultArgs));
pliden@6413 222
pliden@6413 223 return runTest(args.toArray(new String[args.size()]));
pliden@6413 224 }
pliden@6413 225 }
pliden@6413 226
pliden@6413 227 private static class InternedTest {
pliden@6413 228 public static void main(String[] args) {
pliden@6413 229 // This test verifies that interned strings are always
pliden@6413 230 // deduplicated when being interned, and never after
pliden@6413 231 // being interned.
pliden@6413 232
pliden@6413 233 System.out.println("Begin: InternedTest");
pliden@6413 234
pliden@6413 235 final int ageThreshold = Integer.parseUnsignedInt(args[0]);
pliden@6413 236 final String baseString = "DeduplicationTestString:" + InternedTest.class.getName();
pliden@6413 237
pliden@6413 238 // Create duplicate of baseString
pliden@6413 239 StringBuilder sb1 = new StringBuilder(baseString);
pliden@6413 240 String dupString1 = sb1.toString();
pliden@6413 241 if (getValue(dupString1) == getValue(baseString)) {
pliden@6413 242 throw new RuntimeException("Values should not match");
pliden@6413 243 }
pliden@6413 244
pliden@6413 245 // Force baseString to be inspected for deduplication
pliden@6413 246 // and be inserted into the deduplication hashtable.
pliden@6413 247 forceDeduplication(ageThreshold, FullGC);
pliden@6413 248
pliden@6413 249 // Wait for deduplication to occur
pliden@6413 250 while (getValue(dupString1) != getValue(baseString)) {
pliden@6413 251 System.out.println("Waiting...");
pliden@6413 252 try {
pliden@6413 253 Thread.sleep(100);
pliden@6413 254 } catch (Exception e) {
pliden@6413 255 throw new RuntimeException(e);
pliden@6413 256 }
pliden@6413 257 }
pliden@6413 258
pliden@6413 259 // Create a new duplicate of baseString
pliden@6413 260 StringBuilder sb2 = new StringBuilder(baseString);
pliden@6413 261 String dupString2 = sb2.toString();
pliden@6413 262 if (getValue(dupString2) == getValue(baseString)) {
pliden@6413 263 throw new RuntimeException("Values should not match");
pliden@6413 264 }
pliden@6413 265
pliden@6413 266 // Intern the new duplicate
pliden@6413 267 Object beforeInternedValue = getValue(dupString2);
pliden@6413 268 String internedString = dupString2.intern();
pliden@6413 269 if (internedString != dupString2) {
pliden@6413 270 throw new RuntimeException("String should match");
pliden@6413 271 }
pliden@6413 272 if (getValue(internedString) != getValue(baseString)) {
pliden@6413 273 throw new RuntimeException("Values should match");
pliden@6413 274 }
pliden@6413 275
pliden@6413 276 // Check original value of interned string, to make sure
pliden@6413 277 // deduplication happened on the interned string and not
pliden@6413 278 // on the base string
pliden@6413 279 if (beforeInternedValue == getValue(baseString)) {
pliden@6413 280 throw new RuntimeException("Values should not match");
pliden@6413 281 }
pliden@6413 282
pliden@6413 283 System.out.println("End: InternedTest");
pliden@6413 284 }
pliden@6413 285
pliden@6413 286 public static OutputAnalyzer run() throws Exception {
pliden@6413 287 return runTest("-XX:+PrintGC",
pliden@6413 288 "-XX:+PrintGCDetails",
pliden@6413 289 "-XX:+UseStringDeduplication",
pliden@6413 290 "-XX:+PrintStringDeduplicationStatistics",
pliden@6413 291 "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold,
pliden@6413 292 InternedTest.class.getName(),
pliden@6413 293 "" + DefaultAgeThreshold);
pliden@6413 294 }
pliden@6413 295 }
pliden@6413 296
pliden@6413 297 private static class MemoryUsageTest {
pliden@6413 298 public static void main(String[] args) {
pliden@6413 299 System.out.println("Begin: MemoryUsageTest");
pliden@6413 300
pliden@6413 301 final boolean useStringDeduplication = Boolean.parseBoolean(args[0]);
pliden@6413 302 final int numberOfStrings = LargeNumberOfStrings;
pliden@6413 303 final int numberOfUniqueStrings = 1;
pliden@6413 304
pliden@6413 305 ArrayList<String> list = createStrings(numberOfStrings, numberOfUniqueStrings);
pliden@6413 306 forceDeduplication(DefaultAgeThreshold, FullGC);
pliden@6413 307
pliden@6413 308 if (useStringDeduplication) {
pliden@6413 309 verifyStrings(list, numberOfUniqueStrings);
pliden@6413 310 }
pliden@6413 311
pliden@6413 312 System.gc();
pliden@6413 313 System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed());
pliden@6413 314
pliden@6413 315 System.out.println("End: MemoryUsageTest");
pliden@6413 316 }
pliden@6413 317
pliden@6413 318 public static OutputAnalyzer run(boolean useStringDeduplication) throws Exception {
pliden@6413 319 String[] extraArgs = new String[0];
pliden@6413 320
pliden@6413 321 if (useStringDeduplication) {
pliden@6413 322 extraArgs = new String[] {
pliden@6413 323 "-XX:+UseStringDeduplication",
pliden@6413 324 "-XX:+PrintStringDeduplicationStatistics",
pliden@6413 325 "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold
pliden@6413 326 };
pliden@6413 327 }
pliden@6413 328
pliden@6413 329 String[] defaultArgs = new String[] {
pliden@6413 330 "-XX:+PrintGC",
pliden@6413 331 "-XX:+PrintGCDetails",
pliden@6413 332 MemoryUsageTest.class.getName(),
pliden@6413 333 "" + useStringDeduplication
pliden@6413 334 };
pliden@6413 335
pliden@6413 336 ArrayList<String> args = new ArrayList<String>();
pliden@6413 337 args.addAll(Arrays.asList(extraArgs));
pliden@6413 338 args.addAll(Arrays.asList(defaultArgs));
pliden@6413 339
pliden@6413 340 return runTest(args.toArray(new String[args.size()]));
pliden@6413 341 }
pliden@6413 342 }
pliden@6413 343
pliden@6413 344 /*
pliden@6413 345 * Tests
pliden@6413 346 */
pliden@6413 347
pliden@6413 348 private static final int LargeNumberOfStrings = 10000;
pliden@6413 349 private static final int SmallNumberOfStrings = 10;
pliden@6413 350
pliden@6413 351 private static final int MaxAgeThreshold = 15;
pliden@6413 352 private static final int DefaultAgeThreshold = 3;
pliden@6413 353 private static final int MinAgeThreshold = 1;
pliden@6413 354
pliden@6413 355 private static final int TooLowAgeThreshold = MinAgeThreshold - 1;
pliden@6413 356 private static final int TooHighAgeThreshold = MaxAgeThreshold + 1;
pliden@6413 357
pliden@6413 358 public static void testYoungGC() throws Exception {
pliden@6413 359 // Do young GC to age strings to provoke deduplication
pliden@6413 360 OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
pliden@6413 361 DefaultAgeThreshold,
pliden@6413 362 YoungGC,
pliden@6413 363 "-XX:+PrintGC",
pliden@6413 364 "-XX:+PrintStringDeduplicationStatistics");
pliden@6413 365 output.shouldNotContain("Full GC");
pliden@6413 366 output.shouldContain("GC pause (G1 Evacuation Pause) (young)");
pliden@6413 367 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 368 output.shouldContain("Deduplicated:");
pliden@6413 369 output.shouldHaveExitValue(0);
pliden@6413 370 }
pliden@6413 371
pliden@6413 372 public static void testFullGC() throws Exception {
pliden@6413 373 // Do full GC to age strings to provoke deduplication
pliden@6413 374 OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
pliden@6413 375 DefaultAgeThreshold,
pliden@6413 376 FullGC,
pliden@6413 377 "-XX:+PrintGC",
pliden@6413 378 "-XX:+PrintStringDeduplicationStatistics");
pliden@6413 379 output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)");
pliden@6413 380 output.shouldContain("Full GC");
pliden@6413 381 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 382 output.shouldContain("Deduplicated:");
pliden@6413 383 output.shouldHaveExitValue(0);
pliden@6413 384 }
pliden@6413 385
pliden@6413 386 public static void testTableResize() throws Exception {
pliden@6413 387 // Test with StringDeduplicationResizeALot
pliden@6413 388 OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
pliden@6413 389 DefaultAgeThreshold,
pliden@6413 390 YoungGC,
pliden@6413 391 "-XX:+PrintGC",
pliden@6413 392 "-XX:+PrintStringDeduplicationStatistics",
pliden@6413 393 "-XX:+StringDeduplicationResizeALot");
pliden@6413 394 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 395 output.shouldContain("Deduplicated:");
pliden@6413 396 output.shouldNotContain("Resize Count: 0");
pliden@6413 397 output.shouldHaveExitValue(0);
pliden@6413 398 }
pliden@6413 399
pliden@6413 400 public static void testTableRehash() throws Exception {
pliden@6413 401 // Test with StringDeduplicationRehashALot
pliden@6413 402 OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
pliden@6413 403 DefaultAgeThreshold,
pliden@6413 404 YoungGC,
pliden@6413 405 "-XX:+PrintGC",
pliden@6413 406 "-XX:+PrintStringDeduplicationStatistics",
pliden@6413 407 "-XX:+StringDeduplicationRehashALot");
pliden@6413 408 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 409 output.shouldContain("Deduplicated:");
pliden@6413 410 output.shouldNotContain("Rehash Count: 0");
pliden@6413 411 output.shouldNotContain("Hash Seed: 0x0");
pliden@6413 412 output.shouldHaveExitValue(0);
pliden@6413 413 }
pliden@6413 414
pliden@6413 415 public static void testAgeThreshold() throws Exception {
pliden@6413 416 OutputAnalyzer output;
pliden@6413 417
pliden@6413 418 // Test with max age theshold
pliden@6413 419 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 420 MaxAgeThreshold,
pliden@6413 421 YoungGC,
pliden@6413 422 "-XX:+PrintGC",
pliden@6413 423 "-XX:+PrintStringDeduplicationStatistics");
pliden@6413 424 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 425 output.shouldContain("Deduplicated:");
pliden@6413 426 output.shouldHaveExitValue(0);
pliden@6413 427
pliden@6413 428 // Test with min age theshold
pliden@6413 429 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 430 MinAgeThreshold,
pliden@6413 431 YoungGC,
pliden@6413 432 "-XX:+PrintGC",
pliden@6413 433 "-XX:+PrintStringDeduplicationStatistics");
pliden@6413 434 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 435 output.shouldContain("Deduplicated:");
pliden@6413 436 output.shouldHaveExitValue(0);
pliden@6413 437
pliden@6413 438 // Test with too low age threshold
pliden@6413 439 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 440 TooLowAgeThreshold,
pliden@6413 441 YoungGC);
pliden@6413 442 output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold +
pliden@6413 443 " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
pliden@6413 444 output.shouldHaveExitValue(1);
pliden@6413 445
pliden@6413 446 // Test with too high age threshold
pliden@6413 447 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 448 TooHighAgeThreshold,
pliden@6413 449 YoungGC);
pliden@6413 450 output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold +
pliden@6413 451 " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
pliden@6413 452 output.shouldHaveExitValue(1);
pliden@6413 453 }
pliden@6413 454
pliden@6413 455 public static void testPrintOptions() throws Exception {
pliden@6413 456 OutputAnalyzer output;
pliden@6413 457
pliden@6413 458 // Test without PrintGC and without PrintStringDeduplicationStatistics
pliden@6413 459 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 460 DefaultAgeThreshold,
pliden@6413 461 YoungGC);
pliden@6413 462 output.shouldNotContain("GC concurrent-string-deduplication");
pliden@6413 463 output.shouldNotContain("Deduplicated:");
pliden@6413 464 output.shouldHaveExitValue(0);
pliden@6413 465
pliden@6413 466 // Test with PrintGC but without PrintStringDeduplicationStatistics
pliden@6413 467 output = DeduplicationTest.run(SmallNumberOfStrings,
pliden@6413 468 DefaultAgeThreshold,
pliden@6413 469 YoungGC,
pliden@6413 470 "-XX:+PrintGC");
pliden@6413 471 output.shouldContain("GC concurrent-string-deduplication");
pliden@6413 472 output.shouldNotContain("Deduplicated:");
pliden@6413 473 output.shouldHaveExitValue(0);
pliden@6413 474 }
pliden@6413 475
pliden@6413 476 public static void testInterned() throws Exception {
pliden@6413 477 // Test that interned strings are deduplicated before being interned
pliden@6413 478 OutputAnalyzer output = InternedTest.run();
pliden@6413 479 output.shouldHaveExitValue(0);
pliden@6413 480 }
pliden@6413 481
pliden@6413 482 public static void testMemoryUsage() throws Exception {
pliden@6413 483 // Test that memory usage is reduced after deduplication
pliden@6413 484 OutputAnalyzer output;
pliden@6413 485 final String usagePattern = "Heap Memory Usage: (\\d+)";
pliden@6413 486
pliden@6413 487 // Run without deduplication
pliden@6413 488 output = MemoryUsageTest.run(false);
pliden@6413 489 output.shouldHaveExitValue(0);
pliden@6413 490 final long memoryUsageWithoutDedup = Long.parseLong(output.firstMatch(usagePattern, 1));
pliden@6413 491
pliden@6413 492 // Run with deduplication
pliden@6413 493 output = MemoryUsageTest.run(true);
pliden@6413 494 output.shouldHaveExitValue(0);
pliden@6413 495 final long memoryUsageWithDedup = Long.parseLong(output.firstMatch(usagePattern, 1));
pliden@6413 496
pliden@6413 497 // Calculate expected memory usage with deduplication enabled. This calculation does
pliden@6413 498 // not take alignment and padding into account, so it's a conservative estimate.
pliden@6413 499 final long sizeOfChar = 2; // bytes
pliden@6413 500 final long bytesSaved = (LargeNumberOfStrings - 1) * (StringLength * sizeOfChar + unsafe.ARRAY_CHAR_BASE_OFFSET);
pliden@6413 501 final long memoryUsageWithDedupExpected = memoryUsageWithoutDedup - bytesSaved;
pliden@6413 502
pliden@6413 503 System.out.println("Memory usage summary:");
pliden@6413 504 System.out.println(" memoryUsageWithoutDedup: " + memoryUsageWithoutDedup);
pliden@6413 505 System.out.println(" memoryUsageWithDedup: " + memoryUsageWithDedup);
pliden@6413 506 System.out.println(" memoryUsageWithDedupExpected: " + memoryUsageWithDedupExpected);
pliden@6413 507
pliden@6413 508 if (memoryUsageWithDedup > memoryUsageWithDedupExpected) {
pliden@6413 509 throw new Exception("Unexpected memory usage, memoryUsageWithDedup should less or equal to memoryUsageWithDedupExpected");
pliden@6413 510 }
pliden@6413 511 }
pliden@6413 512 }

mercurial