changeset 10903:979558bf4503

8153222: [TESTBUG] Move tests in stress/gc to gc/stress Reviewed-by: dfazunen, jwilhelm
author mchernov
date Thu, 14 Apr 2016 15:45:38 +0300
parents 0b5d8a269e28
children 654c99d25e59
files test/TEST.groups test/gc/stress/TestGCOld.java test/gc/stress/TestMultiThreadStressRSet.java test/gc/stress/TestStressIHOPMultiThread.java test/gc/stress/TestStressRSetCoarsening.java test/stress/gc/TestGCOld.java test/stress/gc/TestMultiThreadStressRSet.java test/stress/gc/TestStressIHOPMultiThread.java test/stress/gc/TestStressRSetCoarsening.java
diffstat 9 files changed, 1282 insertions(+), 1281 deletions(-) [+]
line wrap: on
line diff
--- a/test/TEST.groups	Wed Apr 13 19:55:40 2016 +0400
+++ b/test/TEST.groups	Thu Apr 14 15:45:38 2016 +0300
@@ -338,6 +338,7 @@
   sanity/ExecuteInternalVMTests.java \
   gc/ \
   -gc/g1/ \
+  -gc/stress \
   -gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java \
   -gc/cms/TestMBeanCMS.java \
   -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java
@@ -346,7 +347,7 @@
   sanity/ExecuteInternalVMTests.java
 
 hotspot_fast_gc_gcold = \
-  stress/gc/TestGCOld.java
+  gc/stress/TestGCOld.java
 
 hotspot_fast_runtime = \
   runtime/ \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestGCOld.java	Thu Apr 14 15:45:38 2016 +0300
@@ -0,0 +1,417 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+/*
+ * @test TestGCOld
+ * @key gc
+ * @key stress
+ * @requires vm.gc=="null"
+ * @summary Stress the GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm -Xmx384M -XX:+UseSerialGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC -XX:-UseParallelOldGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseConcMarkSweepGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseG1GC TestGCOld 50 1 20 10 10000
+ */
+
+import java.text.*;
+import java.util.Random;
+
+class TreeNode {
+    public TreeNode left, right;
+    public int val;                // will always be the height of the tree
+}
+
+
+/* Args:
+   live-data-size: in megabytes (approximate, will be rounded down).
+   work: units of mutator non-allocation work per byte allocated,
+     (in unspecified units.  This will affect the promotion rate
+      printed at the end of the run: more mutator work per step implies
+      fewer steps per second implies fewer bytes promoted per second.)
+   short/long ratio: ratio of short-lived bytes allocated to long-lived
+      bytes allocated.
+   pointer mutation rate: number of pointer mutations per step.
+   steps: number of steps to do.
+*/
+
+public class TestGCOld {
+
+  // Command-line parameters.
+
+  private static int size, workUnits, promoteRate, ptrMutRate, steps;
+
+  // Constants.
+
+  private static final int MEG = 1000000;
+  private static final int INSIGNIFICANT = 999; // this many bytes don't matter
+  private static final int BYTES_PER_WORD = 4;
+  private static final int BYTES_PER_NODE = 20; // bytes per TreeNode
+  private static final int WORDS_DEAD = 100;    // size of young garbage object
+
+  private final static int treeHeight = 14;
+  private final static long treeSize = heightToBytes(treeHeight);
+
+  private static final String msg1
+    = "Usage: java TestGCOld <size> <work> <ratio> <mutation> <steps>";
+  private static final String msg2
+    = "  where <size> is the live storage in megabytes";
+  private static final String msg3
+    = "        <work> is the mutator work per step (arbitrary units)";
+  private static final String msg4
+    = "        <ratio> is the ratio of short-lived to long-lived allocation";
+  private static final String msg5
+    = "        <mutation> is the mutations per step";
+  private static final String msg6
+    = "        <steps> is the number of steps";
+
+  // Counters (and global variables that discourage optimization)
+
+  private static long youngBytes = 0;    // total young bytes allocated
+  private static long nodes = 0;         // total tree nodes allocated
+  private static long actuallyMut = 0;   // pointer mutations in old trees
+  private static long mutatorSum = 0;    // checksum to discourage optimization
+  public static int[] aexport;           // exported array to discourage opt
+
+  // Global variables.
+
+  private static TreeNode[] trees;
+  private static int where = 0;               // roving index into trees
+  private static Random rnd = new Random();
+
+  // Returns the height of the given tree.
+
+  private static int height (TreeNode t) {
+    if (t == null) {
+      return 0;
+    }
+    else {
+      return 1 + Math.max (height (t.left), height (t.right));
+    }
+  }
+
+  // Returns the length of the shortest path in the given tree.
+
+  private static int shortestPath (TreeNode t) {
+    if (t == null) {
+      return 0;
+    }
+    else {
+      return 1 + Math.min (shortestPath (t.left), shortestPath (t.right));
+    }
+  }
+
+  // Returns the number of nodes in a balanced tree of the given height.
+
+  private static long heightToNodes (int h) {
+    if (h == 0) {
+      return 0;
+    }
+    else {
+      long n = 1;
+      while (h > 1) {
+        n = n + n;
+        h = h - 1;
+      }
+      return n + n - 1;
+    }
+  }
+
+  // Returns the number of bytes in a balanced tree of the given height.
+
+  private static long heightToBytes (int h) {
+    return BYTES_PER_NODE * heightToNodes (h);
+  }
+
+  // Returns the height of the largest balanced tree
+  // that has no more than the given number of nodes.
+
+  private static int nodesToHeight (long nodes) {
+    int h = 1;
+    long n = 1;
+    while (n + n - 1 <= nodes) {
+      n = n + n;
+      h = h + 1;
+    }
+    return h - 1;
+  }
+
+  // Returns the height of the largest balanced tree
+  // that occupies no more than the given number of bytes.
+
+  private static int bytesToHeight (long bytes) {
+    return nodesToHeight (bytes / BYTES_PER_NODE);
+  }
+
+  // Returns a newly allocated balanced binary tree of height h.
+
+  private static TreeNode makeTree(int h) {
+    if (h == 0) return null;
+    else {
+      TreeNode res = new TreeNode();
+      nodes++;
+      res.left = makeTree(h-1);
+      res.right = makeTree(h-1);
+      res.val = h;
+      return res;
+    }
+  }
+
+  // Allocates approximately size megabytes of trees and stores
+  // them into a global array.
+
+  private static void init() {
+    int ntrees = (int) ((size * MEG) / treeSize);
+    trees = new TreeNode[ntrees];
+
+    System.err.println("Allocating " + ntrees + " trees.");
+    System.err.println("  (" + (ntrees * treeSize) + " bytes)");
+    for (int i = 0; i < ntrees; i++) {
+      trees[i] = makeTree(treeHeight);
+      // doYoungGenAlloc(promoteRate*ntrees*treeSize, WORDS_DEAD);
+    }
+    System.err.println("  (" + nodes + " nodes)");
+
+    /* Allow any in-progress GC to catch up... */
+    // try { Thread.sleep(20000); } catch (InterruptedException x) {}
+  }
+
+  // Confirms that all trees are balanced and have the correct height.
+
+  private static void checkTrees() {
+    int ntrees = trees.length;
+    for (int i = 0; i < ntrees; i++) {
+      TreeNode t = trees[i];
+      int h1 = height(t);
+      int h2 = shortestPath(t);
+      if ((h1 != treeHeight) || (h2 != treeHeight)) {
+        System.err.println("*****BUG: " + h1 + " " + h2);
+      }
+    }
+  }
+
+  // Called only by replaceTree (below) and by itself.
+
+  private static void replaceTreeWork(TreeNode full, TreeNode partial, boolean dir) {
+    boolean canGoLeft = full.left != null && full.left.val > partial.val;
+    boolean canGoRight = full.right != null && full.right.val > partial.val;
+    if (canGoLeft && canGoRight) {
+      if (dir)
+        replaceTreeWork(full.left, partial, !dir);
+      else
+        replaceTreeWork(full.right, partial, !dir);
+    } else if (!canGoLeft && !canGoRight) {
+      if (dir)
+        full.left = partial;
+      else
+        full.right = partial;
+    } else if (!canGoLeft) {
+      full.left = partial;
+    } else {
+      full.right = partial;
+    }
+  }
+
+  // Given a balanced tree full and a smaller balanced tree partial,
+  // replaces an appropriate subtree of full by partial, taking care
+  // to preserve the shape of the full tree.
+
+  private static void replaceTree(TreeNode full, TreeNode partial) {
+    boolean dir = (partial.val % 2) == 0;
+    actuallyMut++;
+    replaceTreeWork(full, partial, dir);
+  }
+
+  // Allocates approximately n bytes of long-lived storage,
+  // replacing oldest existing long-lived storage.
+
+  private static void oldGenAlloc(long n) {
+    int full = (int) (n / treeSize);
+    long partial = n % treeSize;
+    // System.out.println("In oldGenAlloc, doing " + full + " full trees "
+    // + "and one partial tree of size " + partial);
+    for (int i = 0; i < full; i++) {
+      trees[where++] = makeTree(treeHeight);
+      if (where == trees.length) where = 0;
+    }
+    while (partial > INSIGNIFICANT) {
+      int h = bytesToHeight(partial);
+      TreeNode newTree = makeTree(h);
+      replaceTree(trees[where++], newTree);
+      if (where == trees.length) where = 0;
+      partial = partial - heightToBytes(h);
+    }
+  }
+
+  // Interchanges two randomly selected subtrees (of same size and depth).
+
+  private static void oldGenSwapSubtrees() {
+    // Randomly pick:
+    //   * two tree indices
+    //   * A depth
+    //   * A path to that depth.
+    int index1 = rnd.nextInt(trees.length);
+    int index2 = rnd.nextInt(trees.length);
+    int depth = rnd.nextInt(treeHeight);
+    int path = rnd.nextInt();
+    TreeNode tn1 = trees[index1];
+    TreeNode tn2 = trees[index2];
+    for (int i = 0; i < depth; i++) {
+      if ((path & 1) == 0) {
+        tn1 = tn1.left;
+        tn2 = tn2.left;
+      } else {
+        tn1 = tn1.right;
+        tn2 = tn2.right;
+      }
+      path >>= 1;
+    }
+    TreeNode tmp;
+    if ((path & 1) == 0) {
+      tmp = tn1.left;
+      tn1.left = tn2.left;
+      tn2.left = tmp;
+    } else {
+      tmp = tn1.right;
+      tn1.right = tn2.right;
+      tn2.right = tmp;
+    }
+    actuallyMut += 2;
+  }
+
+  // Update "n" old-generation pointers.
+
+  private static void oldGenMut(long n) {
+    for (int i = 0; i < n/2; i++) {
+      oldGenSwapSubtrees();
+    }
+  }
+
+  // Does the amount of mutator work appropriate for n bytes of young-gen
+  // garbage allocation.
+
+  private static void doMutWork(long n) {
+    int sum = 0;
+    long limit = workUnits*n/10;
+    for (long k = 0; k < limit; k++) sum++;
+    // We don't want dead code elimination to eliminate the loop above.
+    mutatorSum = mutatorSum + sum;
+  }
+
+  // Allocate n bytes of young-gen garbage, in units of "nwords"
+  // words.
+
+  private static void doYoungGenAlloc(long n, int nwords) {
+    final int nbytes = nwords*BYTES_PER_WORD;
+    int allocated = 0;
+    while (allocated < n) {
+      aexport = new int[nwords];
+      /* System.err.println("Step"); */
+      allocated += nbytes;
+    }
+    youngBytes = youngBytes + allocated;
+  }
+
+  // Allocate "n" bytes of young-gen data; and do the
+  // corresponding amount of old-gen allocation and pointer
+  // mutation.
+
+  // oldGenAlloc may perform some mutations, so this code
+  // takes those mutations into account.
+
+  private static void doStep(long n) {
+    long mutations = actuallyMut;
+
+    doYoungGenAlloc(n, WORDS_DEAD);
+    doMutWork(n);
+    oldGenAlloc(n / promoteRate);
+    oldGenMut(Math.max(0L, (mutations + ptrMutRate) - actuallyMut));
+  }
+
+  public static void main(String[] args) {
+    if (args.length != 5) {
+      System.err.println(msg1);
+      System.err.println(msg2);
+      System.err.println(msg3);
+      System.err.println(msg4);
+      System.err.println(msg5);
+      System.err.println(msg6);
+      return;
+    }
+
+    size = Integer.parseInt(args[0]);
+    workUnits = Integer.parseInt(args[1]);
+    promoteRate = Integer.parseInt(args[2]);
+    ptrMutRate = Integer.parseInt(args[3]);
+    steps = Integer.parseInt(args[4]);
+
+    System.out.println(size + " megabytes of live storage");
+    System.out.println(workUnits + " work units per step");
+    System.out.println("promotion ratio is 1:" + promoteRate);
+    System.out.println("pointer mutation rate is " + ptrMutRate);
+    System.out.println(steps + " steps");
+
+    init();
+//  checkTrees();
+    youngBytes = 0;
+    nodes = 0;
+
+    System.err.println("Initialization complete...");
+
+    long start = System.currentTimeMillis();
+
+    for (int step = 0; step < steps; step++) {
+      doStep(MEG);
+    }
+
+    long end = System.currentTimeMillis();
+    float secs = ((float)(end-start))/1000.0F;
+
+//  checkTrees();
+
+    NumberFormat nf = NumberFormat.getInstance();
+    nf.setMaximumFractionDigits(1);
+    System.out.println("\nTook " + nf.format(secs) + " sec in steady state.");
+    nf.setMaximumFractionDigits(2);
+    System.out.println("Allocated " + steps + " Mb of young gen garbage"
+                       + " (= " + nf.format(((float)steps)/secs) +
+                       " Mb/sec)");
+    System.out.println("    (actually allocated " +
+                       nf.format(((float) youngBytes)/MEG) + " megabytes)");
+    float promoted = ((float)steps) / (float)promoteRate;
+    System.out.println("Promoted " + promoted +
+                       " Mb (= " + nf.format(promoted/secs) + " Mb/sec)");
+    System.out.println("    (actually promoted " +
+                       nf.format(((float) (nodes * BYTES_PER_NODE))/MEG) +
+                       " megabytes)");
+    if (ptrMutRate != 0) {
+      System.out.println("Mutated " + actuallyMut +
+                         " pointers (= " +
+                         nf.format(actuallyMut/secs) + " ptrs/sec)");
+
+    }
+    // This output serves mainly to discourage optimization.
+    System.out.println("Checksum = " + (mutatorSum + aexport.length));
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestMultiThreadStressRSet.java	Thu Apr 14 15:45:38 2016 +0300
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestMultiThreadStressRSet.java
+ * @key stress
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 2G
+ *
+ * @summary Stress G1 Remembered Set using multiple threads
+ * @library /test/lib /testlibrary
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc
+ *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ *   -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16
+ *
+ * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32
+ */
+public class TestMultiThreadStressRSet {
+
+    private static final Random RND = new Random(2015 * 2016);
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+    private static final int REF_SIZE = WB.getHeapOopSize();
+    private static final int REGION_SIZE = WB.g1RegionSize();
+
+    // How many regions to use for the storage
+    private static final int STORAGE_REGIONS = 20;
+
+    // Size a single obj in the storage
+    private static final int OBJ_SIZE = 1024;
+
+    // How many regions of young/old gen to use in the BUFFER
+    private static final int BUFFER_YOUNG_REGIONS = 60;
+    private static final int BUFFER_OLD_REGIONS = 40;
+
+    // Total number of objects in the storage.
+    private final int N;
+
+    // The storage of byte[]
+    private final List<Object> STORAGE;
+
+    // Where references to the Storage will be stored
+    private final List<Object[]> BUFFER;
+
+    // The length of a buffer element.
+    // RSet deals with "cards" (areas of 512 bytes), not with single refs
+    // So, to affect the RSet the BUFFER refs should be allocated in different
+    // memory cards.
+    private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE);
+
+    // Total number of objects in the young/old buffers
+    private final int YOUNG;
+    private final int OLD;
+
+    // To cause Remembered Sets change their coarse level the test uses a window
+    // within STORAGE. All the BUFFER elements refer to only STORAGE objects
+    // from the current window. The window is defined by a range.
+    // The first element has got the index: 'windowStart',
+    // the last one: 'windowStart + windowSize - 1'
+    // The window is shifting periodically.
+    private int windowStart;
+    private final int windowSize;
+
+    // Counter of created worker threads
+    private int counter = 0;
+
+    private volatile String errorMessage = null;
+    private volatile boolean isEnough = false;
+
+    public static void main(String args[]) {
+        if (args.length != 2) {
+            throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length);
+        }
+        long time = Long.parseLong(args[0]);
+        int threads = Integer.parseInt(args[1]);
+        new TestMultiThreadStressRSet().test(time * 1000, threads);
+    }
+
+    /**
+     * Initiates test parameters, fills out the STORAGE and BUFFER.
+     */
+    public TestMultiThreadStressRSet() {
+
+        N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1;
+        STORAGE = new ArrayList<>(N);
+        int bytes = OBJ_SIZE - 20;
+        for (int i = 0; i < N - 1; i++) {
+            STORAGE.add(new byte[bytes]);
+        }
+        STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous
+        windowStart = 0;
+        windowSize = REGION_SIZE / OBJ_SIZE;
+
+        BUFFER = new ArrayList<>();
+        int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN;
+        OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject;
+        YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject;
+        for (int i = 0; i < OLD + YOUNG; i++) {
+            BUFFER.add(new Object[BUF_ARR_LEN]);
+        }
+    }
+
+    /**
+     * Does the testing. Steps:
+     * <ul>
+     * <li> starts the Shifter thread
+     * <li> during the given time starts new Worker threads, keeping the number
+     * of live thread under limit.
+     * <li> stops the Shifter thread
+     * </ul>
+     *
+     * @param timeInMillis how long to stress
+     * @param maxThreads the maximum number of Worker thread working together.
+     */
+    public void test(long timeInMillis, int maxThreads) {
+        if (timeInMillis <= 0 || maxThreads <= 0) {
+            throw new IllegalArgumentException("TEST BUG: be positive!");
+        }
+        System.out.println("%% Time to work: " + timeInMillis / 1000 + "s");
+        System.out.println("%% Number of threads: " + maxThreads);
+        long finish = System.currentTimeMillis() + timeInMillis;
+        Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9));
+        shift.start();
+        for (int i = 0; i < maxThreads; i++) {
+            new Worker(this, 100).start();
+        }
+        try {
+            while (System.currentTimeMillis() < finish && errorMessage == null) {
+                Thread.sleep(100);
+            }
+        } catch (Throwable t) {
+            printAllStackTraces(System.err);
+            t.printStackTrace(System.err);
+            this.errorMessage = t.getMessage();
+        } finally {
+            isEnough = true;
+        }
+        System.out.println("%% Total work cycles: " + counter);
+        if (errorMessage != null) {
+            throw new RuntimeException(errorMessage);
+        }
+    }
+
+    /**
+     * Returns an element from from the BUFFER (an object array) to keep
+     * references to the storage.
+     *
+     * @return an Object[] from buffer.
+     */
+    private Object[] getFromBuffer() {
+        int index = counter % (OLD + YOUNG);
+        synchronized (BUFFER) {
+            if (index < OLD) {
+                if (counter % 100 == (counter / 100) % 100) {
+                    // need to generate garbage in the old gen to provoke mixed GC
+                    return replaceInBuffer(index);
+                } else {
+                    return BUFFER.get(index);
+                }
+            } else {
+                return replaceInBuffer(index);
+            }
+        }
+    }
+
+    private Object[] replaceInBuffer(int index) {
+        Object[] objs = new Object[BUF_ARR_LEN];
+        BUFFER.set(index, objs);
+        return objs;
+    }
+
+    /**
+     * Returns a random object from the current window within the storage.
+     * A storage element with index from windowStart to windowStart+windowSize.
+     *
+     * @return a random element from the current window within the storage.
+     */
+    private Object getRandomObject() {
+        int index = (windowStart + RND.nextInt(windowSize)) % N;
+        return STORAGE.get(index);
+    }
+
+    private static void printAllStackTraces(PrintStream ps) {
+        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+        for (Thread t : traces.keySet()) {
+            ps.println(t.toString() + " " + t.getState());
+            for (StackTraceElement traceElement : traces.get(t)) {
+                ps.println("\tat " + traceElement);
+            }
+        }
+    }
+
+    /**
+     * Thread to create a number of references from BUFFER to STORAGE.
+     */
+    private static class Worker extends Thread {
+
+        final TestMultiThreadStressRSet boss;
+        final int refs; // number of refs to OldGen
+
+        /**
+         * @param boss the tests
+         * @param refsToOldGen how many references to the OldGen to create
+         */
+        Worker(TestMultiThreadStressRSet boss, int refsToOldGen) {
+            this.boss = boss;
+            this.refs = refsToOldGen;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!boss.isEnough) {
+                    Object[] objs = boss.getFromBuffer();
+                    int step = objs.length / refs;
+                    for (int i = 0; i < refs; i += step) {
+                        objs[i] = boss.getRandomObject();
+                    }
+                    boss.counter++;
+                }
+            } catch (Throwable t) {
+                t.printStackTrace(System.out);
+                boss.errorMessage = t.getMessage();
+            }
+        }
+    }
+
+    /**
+     * Periodically shifts the current STORAGE window, removing references
+     * in BUFFER that refer to objects outside the window.
+     */
+    private static class Shifter extends Thread {
+
+        final TestMultiThreadStressRSet boss;
+        final int sleepTime;
+        final int shift;
+
+        Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) {
+            this.boss = boss;
+            this.sleepTime = sleepTime;
+            this.shift = shift;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!boss.isEnough) {
+                    Thread.sleep(sleepTime);
+                    boss.windowStart += shift;
+                    for (int i = 0; i < boss.OLD; i++) {
+                        Object[] objs = boss.BUFFER.get(i);
+                        for (int j = 0; j < objs.length; j++) {
+                            objs[j] = null;
+                        }
+                    }
+                    if (!WB.g1InConcurrentMark()) {
+                        System.out.println("%% start CMC");
+                        WB.g1StartConcMarkCycle();
+                    } else {
+                        System.out.println("%% CMC is already in progress");
+                    }
+                }
+            } catch (Throwable t) {
+                t.printStackTrace(System.out);
+                boss.errorMessage = t.getMessage();
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestStressIHOPMultiThread.java	Thu Apr 14 15:45:38 2016 +0300
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test TestStressIHOPMultiThread
+ * @bug 8148397
+ * @key stress
+ * @summary Stress test for IHOP
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
+ *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
+ *              -Dthreads=2 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
+ *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
+ *              -Dthreads=3 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
+ *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
+ *              -Dthreads=5 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
+ *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
+ *              -Dthreads=10 TestStressIHOPMultiThread
+ * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
+ *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
+ *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
+ *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
+ *              -Dthreads=17 TestStressIHOPMultiThread
+ */
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
+ * specified amount of memory. Tests work with enabled IHOP logging.
+ *
+ */
+public class TestStressIHOPMultiThread {
+
+    public final static List<Object> GARBAGE = new LinkedList<>();
+
+    private final long HEAP_SIZE;
+    // Amount of memory to be allocated before iterations start
+    private final long HEAP_PREALLOC_SIZE;
+    // Amount of memory to be allocated and freed during iterations
+    private final long HEAP_ALLOC_SIZE;
+    private final int CHUNK_SIZE = 100000;
+
+    private final int TIMEOUT;
+    private final int THREADS;
+    private final int HEAP_LOW_BOUND;
+    private final int HEAP_HIGH_BOUND;
+
+    private volatile boolean running = true;
+    private final List<AllocationThread> threads;
+
+    public static void main(String[] args) throws InterruptedException {
+        new TestStressIHOPMultiThread().start();
+
+    }
+
+    TestStressIHOPMultiThread() {
+
+        TIMEOUT = Integer.getInteger("timeout") * 60;
+        THREADS = Integer.getInteger("threads");
+        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
+        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
+        HEAP_SIZE = Runtime.getRuntime().maxMemory();
+
+        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
+        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;
+
+        threads = new ArrayList<>(THREADS);
+    }
+
+    public void start() throws InterruptedException {
+        fill();
+        createThreads();
+        waitForStress();
+        stressDone();
+        waitForFinish();
+    }
+
+    /**
+     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
+     */
+    private void fill() {
+        long allocated = 0;
+        while (allocated < HEAP_PREALLOC_SIZE) {
+            GARBAGE.add(new byte[CHUNK_SIZE]);
+            allocated += CHUNK_SIZE;
+        }
+    }
+
+    /**
+     * Creates a number of threads which will fill and free amount of memory.
+     */
+    private void createThreads() {
+        for (int i = 0; i < THREADS; ++i) {
+            System.out.println("Create thread " + i);
+            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
+            // Put reference to thread garbage into common garbage for avoiding possible optimization.
+            GARBAGE.add(thread.getList());
+            threads.add(thread);
+        }
+        threads.forEach(t -> t.start());
+    }
+
+    /**
+     * Wait each thread for finishing
+     */
+    private void waitForFinish() {
+        threads.forEach(thread -> {
+            thread.silentJoin();
+        });
+    }
+
+    private boolean isRunning() {
+        return running;
+    }
+
+    private void stressDone() {
+        running = false;
+    }
+
+    private void waitForStress() throws InterruptedException {
+        Thread.sleep(TIMEOUT * 1000);
+    }
+
+    private class AllocationThread extends Thread {
+
+        private final List<Object> garbage;
+
+        private final long amountOfGarbage;
+        private final int threadId;
+
+        public AllocationThread(int id, long amount) {
+            super("Thread " + id);
+            threadId = id;
+            amountOfGarbage = amount;
+            garbage = new LinkedList<>();
+        }
+
+        /**
+         * Returns list of garbage.
+         * @return List with thread garbage.
+         */
+        public List<Object> getList(){
+            return garbage;
+        }
+
+        @Override
+        public void run() {
+            System.out.println("Start the thread " + threadId);
+            while (TestStressIHOPMultiThread.this.isRunning()) {
+                allocate(amountOfGarbage);
+                free();
+            }
+        }
+
+        private void silentJoin() {
+            System.out.println("Join the thread " + threadId);
+            try {
+                join();
+            } catch (InterruptedException ie) {
+                throw new RuntimeException(ie);
+            }
+        }
+
+        /**
+         * Allocates thread local garbage
+         */
+        private void allocate(long amount) {
+            long allocated = 0;
+            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
+                garbage.add(new byte[CHUNK_SIZE]);
+                allocated += CHUNK_SIZE;
+            }
+        }
+
+        /**
+         * Frees thread local garbage
+         */
+        private void free() {
+            garbage.clear();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/stress/TestStressRSetCoarsening.java	Thu Apr 14 15:45:38 2016 +0300
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.concurrent.TimeoutException;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestStressRSetCoarsening.java
+ * @key stress
+ * @bug 8146984 8147087
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 3G
+ *
+ * @summary Stress G1 Remembered Set by creating a lot of cross region links
+ * @modules java.base/sun.misc
+ * @library /testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  1  0 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=8m TestStressRSetCoarsening  1 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=32m TestStressRSetCoarsening 42 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  2 0 300
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 500 0  1800
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
+ *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 10  10 1800
+ */
+
+/**
+ * What the test does.
+ * Preparation stage:
+ *   Fill out ~90% of the heap with objects, each object is an object array.
+ *   If we want to allocate K objects per region, we calculate N to meet:
+ *      sizeOf(Object[N]) ~= regionSize / K
+ * Stress stage:
+ *   No more allocation, so no more GC.
+ *   We will perform a number of  iterations. On each iteration i,
+ *   for each pair of regions Rx and Ry we will set c[i] references
+ *   from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
+ *   concurrent mark cycle will be initiated (to recalculate remembered sets).
+ *   As the result RSet will be growing up and down, up and down many times.
+ *
+ * The test expects: no crash and no timeouts.
+ *
+ * Test Parameters:
+ *   args[0] - number of objects per Heap Region (1 - means humongous)
+ *   args[1] - number of regions to refresh to provoke GC at the end of cycle.
+ *             (0 - means no GC, i.e. no reading from RSet)
+ *   args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
+ */
+public class TestStressRSetCoarsening {
+
+    public static void main(String... args) throws InterruptedException {
+        if (args.length != 3) {
+            throw new IllegalArgumentException("Wrong number of arguments " + args.length);
+        }
+        int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
+        int regsToRefresh = Integer.parseInt(args[1]);  // 0 means no regions to refresh at the end of cycle
+        int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
+        new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
+    }
+
+    private static final long KB = 1024;
+    private static final long MB = 1024 * KB;
+
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    public final Object[][] storage;
+
+    /**
+     * Number of objects per region. This is a test parameter.
+     */
+    public final int K;
+
+    /**
+     * Length of object array: sizeOf(Object[N]) ~= regionSize / K
+     * N will be calculated as function of K.
+     */
+    public final int N;
+
+    /**
+     * How many regions involved into testing.
+     * Will be calculated as heapFractionToAllocate * freeRegionCount.
+     */
+    public final int regionCount;
+
+    /**
+     * How much heap to use.
+     */
+    public final float heapFractionToAllocate = 0.9f;
+
+    /**
+     * How many regions to be refreshed at the end of cycle.
+     * This is a test parameter.
+     */
+    public final int regsToRefresh;
+
+    /**
+     * Initial time.
+     */
+    public final long start;
+
+    /**
+     * Time when the test should stop working.
+     */
+    public final long finishAt;
+
+    /**
+     * Does pre-calculation and allocate necessary objects.
+     *
+     * @param objPerRegions how many objects per G1 heap region
+     */
+    TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
+        this.K = objPerRegions;
+        this.regsToRefresh = regsToRefresh;
+        this.start = System.currentTimeMillis();
+        this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
+
+        long regionSize = WB.g1RegionSize();
+
+        // How many free regions
+        Runtime rt = Runtime.getRuntime();
+        long used = rt.totalMemory() - rt.freeMemory();
+        long totalFree = rt.maxMemory() - used;
+        regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
+        long toAllocate = regionCount * regionSize;
+        System.out.println("%% Test parameters");
+        System.out.println("%%   Objects per region              : " + K);
+        System.out.println("%%   Heap fraction to allocate       : " + (int) (heapFractionToAllocate * 100) + "%");
+        System.out.println("%%   Regions to refresh to provoke GC: " + regsToRefresh);
+
+        System.out.println("%% Memory");
+        System.out.println("%%   used          :        " + used / MB + "M");
+        System.out.println("%%   available     :        " + totalFree / MB + "M");
+        System.out.println("%%   to allocate   :        " + toAllocate / MB + "M");
+        System.out.println("%%     (in regs)   :        " + regionCount);
+        System.out.println("%%   G1 Region Size:        " + regionSize / MB + "M");
+
+        int refSize = WB.getHeapOopSize();
+
+        // Calculate N:    K*sizeOf(Object[N]) ~= regionSize
+        //                 sizeOf(Object[N]) ~=  (N+4)*refSize
+        // ==>
+        //                 N = regionSize / K / refSize - 4;
+        int n = (int) ((regionSize / K) / refSize) - 5;  // best guess
+        long objSize = WB.getObjectSize(new Object[n]);
+        while (K*objSize > regionSize) {   // adjust to avoid OOME
+            n = n - 1;
+            objSize = WB.getObjectSize(new Object[n]);
+        }
+        N = n;
+
+        /*
+         *   --------------
+         *   region0   storage[0]        = new Object[N]
+         *             ...
+         *             storage[K-1]      = new Object[N]
+         *   ---------------
+         *   region1   storage[K]        = new Object[N]
+         *             ...
+         *             storage[2*K - 1]  = new Object[N]
+         *   --------------
+         *   ...
+         *   --------------
+         *   regionX   storage[X*K]         = new Object[N]
+         *             ...
+         *             storage[(X+1)*K -1]  = new Object[N]
+         *    where X = HeapFraction * TotalRegions
+         *   -------------
+         */
+        System.out.println("%% Objects");
+        System.out.println("%%   N (array length)      : " + N);
+        System.out.println("%%   K (objects in regions): " + K);
+        System.out.println("%%   Object size           : " + objSize +
+                "  (sizeOf(new Object[" + N + "])");
+        System.out.println("%%   Reference size        : " + refSize);
+
+        storage = new Object[regionCount * K][];
+        for (int i = 0; i < storage.length; i++) {
+            storage[i] = new Object[N];
+        }
+    }
+
+    public void go() throws InterruptedException {
+        // threshold for sparce -> fine
+        final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
+
+        // threshold for fine -> coarse
+        final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
+
+        // regToRegRefCounts - array of reference counts from region to region
+        // at the the end of iteration.
+        // The number of test iterations is array length - 1.
+        // If c[i] > c[i-1] then during the iteration i more references will
+        // be created.
+        // If c[i] < c[i-1] then some referenes will be cleaned.
+        int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
+            COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
+
+        // For progress tracking
+        int[] progress = new int[regToRegRefCounts.length];
+        progress[0] = 0;
+        for (int i = 1; i < regToRegRefCounts.length; i++) {
+            progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
+        }
+        try {
+            for (int i = 1; i < regToRegRefCounts.length; i++) {
+                int pre = regToRegRefCounts[i - 1];
+                int cur = regToRegRefCounts[i];
+                float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
+
+                System.out.println("%% step " + i
+                        + " out of " + (regToRegRefCounts.length - 1)
+                        + " (~" + (int) (100 * prog) + "% done)");
+                System.out.println("%%      " + pre + "  --> " + cur);
+                for (int to = 0; to < regionCount; to++) {
+                    // Select a celebrity object that we will install references to.
+                    // The celebrity will be referred from all other regions.
+                    // If the number of references after should be less than they
+                    // were before, select NULL.
+                    Object celebrity = cur > pre ? storage[to * K] : null;
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+
+                        int step = cur > pre ? +1 : -1;
+                        for (int rn = pre; rn != cur; rn += step) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
+                            if (System.currentTimeMillis() > finishAt) {
+                                throw new TimeoutException();
+                            }
+                        }
+                    }
+                }
+                if (pre > cur) {
+                    // Number of references went down.
+                    // Need to provoke recalculation of RSet.
+                    WB.g1StartConcMarkCycle();
+                    while (WB.g1InConcurrentMark()) {
+                        Thread.sleep(1);
+                    }
+                }
+
+                // To force the use of rememebered set entries we need to provoke a GC.
+                // To induce some fragmentation, and some mixed GCs, we need
+                // to make a few objects unreachable.
+                for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
+                    int to = toClean % regionCount;
+                    // Need to remove all references from all regions to the region 'to'
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+                        for (int rn = 0; rn <= cur; rn++) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = null;
+                        }
+                    }
+                    // 'Refresh' storage elements for the region 'to'
+                    // After that loop all 'old' objects in the region 'to'
+                    // should become unreachable.
+                    for (int k = 0; k < K; k++) {
+                        storage[(to * K + k) % storage.length] = new Object[N];
+                    }
+                }
+            }
+        } catch (TimeoutException e) {
+            System.out.println("%% TIMEOUT!!!");
+        }
+        long now = System.currentTimeMillis();
+        System.out.println("%% Summary");
+        System.out.println("%%   Time spent          : " + ((now - start) / 1000) + " seconds");
+        System.out.println("%%   Free memory left    : " + Runtime.getRuntime().freeMemory() / KB + "K");
+        System.out.println("%% Test passed");
+    }
+
+    /**
+     * Returns X index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return X index in the range: [0 ... N-1]
+     */
+    private int getX(int to, int from, int rn) {
+        return (rn * regionCount + to) % N;
+    }
+
+    /**
+     * Returns Y index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return Y index in the range: [0 ... K*regionCount -1]
+     */
+    private int getY(int to, int from, int rn) {
+        return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
+    }
+}
+
--- a/test/stress/gc/TestGCOld.java	Wed Apr 13 19:55:40 2016 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,417 +0,0 @@
-/*
-* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
-* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-*
-* This code is free software; you can redistribute it and/or modify it
-* under the terms of the GNU General Public License version 2 only, as
-* published by the Free Software Foundation.
-*
-* This code is distributed in the hope that it will be useful, but WITHOUT
-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-* version 2 for more details (a copy is included in the LICENSE file that
-* accompanied this code).
-*
-* You should have received a copy of the GNU General Public License version
-* 2 along with this work; if not, write to the Free Software Foundation,
-* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-*
-* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-* or visit www.oracle.com if you need additional information or have any
-* questions.
-*/
-
-/*
- * @test TestGCOld
- * @key gc
- * @key stress
- * @requires vm.gc=="null"
- * @summary Stress the GC by trying to make old objects more likely to be garbage than young objects.
- * @run main/othervm -Xmx384M -XX:+UseSerialGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseParallelGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseParallelGC -XX:-UseParallelOldGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseConcMarkSweepGC TestGCOld 50 1 20 10 10000
- * @run main/othervm -Xmx384M -XX:+UseG1GC TestGCOld 50 1 20 10 10000
- */
-
-import java.text.*;
-import java.util.Random;
-
-class TreeNode {
-    public TreeNode left, right;
-    public int val;                // will always be the height of the tree
-}
-
-
-/* Args:
-   live-data-size: in megabytes (approximate, will be rounded down).
-   work: units of mutator non-allocation work per byte allocated,
-     (in unspecified units.  This will affect the promotion rate
-      printed at the end of the run: more mutator work per step implies
-      fewer steps per second implies fewer bytes promoted per second.)
-   short/long ratio: ratio of short-lived bytes allocated to long-lived
-      bytes allocated.
-   pointer mutation rate: number of pointer mutations per step.
-   steps: number of steps to do.
-*/
-
-public class TestGCOld {
-
-  // Command-line parameters.
-
-  private static int size, workUnits, promoteRate, ptrMutRate, steps;
-
-  // Constants.
-
-  private static final int MEG = 1000000;
-  private static final int INSIGNIFICANT = 999; // this many bytes don't matter
-  private static final int BYTES_PER_WORD = 4;
-  private static final int BYTES_PER_NODE = 20; // bytes per TreeNode
-  private static final int WORDS_DEAD = 100;    // size of young garbage object
-
-  private final static int treeHeight = 14;
-  private final static long treeSize = heightToBytes(treeHeight);
-
-  private static final String msg1
-    = "Usage: java TestGCOld <size> <work> <ratio> <mutation> <steps>";
-  private static final String msg2
-    = "  where <size> is the live storage in megabytes";
-  private static final String msg3
-    = "        <work> is the mutator work per step (arbitrary units)";
-  private static final String msg4
-    = "        <ratio> is the ratio of short-lived to long-lived allocation";
-  private static final String msg5
-    = "        <mutation> is the mutations per step";
-  private static final String msg6
-    = "        <steps> is the number of steps";
-
-  // Counters (and global variables that discourage optimization)
-
-  private static long youngBytes = 0;    // total young bytes allocated
-  private static long nodes = 0;         // total tree nodes allocated
-  private static long actuallyMut = 0;   // pointer mutations in old trees
-  private static long mutatorSum = 0;    // checksum to discourage optimization
-  public static int[] aexport;           // exported array to discourage opt
-
-  // Global variables.
-
-  private static TreeNode[] trees;
-  private static int where = 0;               // roving index into trees
-  private static Random rnd = new Random();
-
-  // Returns the height of the given tree.
-
-  private static int height (TreeNode t) {
-    if (t == null) {
-      return 0;
-    }
-    else {
-      return 1 + Math.max (height (t.left), height (t.right));
-    }
-  }
-
-  // Returns the length of the shortest path in the given tree.
-
-  private static int shortestPath (TreeNode t) {
-    if (t == null) {
-      return 0;
-    }
-    else {
-      return 1 + Math.min (shortestPath (t.left), shortestPath (t.right));
-    }
-  }
-
-  // Returns the number of nodes in a balanced tree of the given height.
-
-  private static long heightToNodes (int h) {
-    if (h == 0) {
-      return 0;
-    }
-    else {
-      long n = 1;
-      while (h > 1) {
-        n = n + n;
-        h = h - 1;
-      }
-      return n + n - 1;
-    }
-  }
-
-  // Returns the number of bytes in a balanced tree of the given height.
-
-  private static long heightToBytes (int h) {
-    return BYTES_PER_NODE * heightToNodes (h);
-  }
-
-  // Returns the height of the largest balanced tree
-  // that has no more than the given number of nodes.
-
-  private static int nodesToHeight (long nodes) {
-    int h = 1;
-    long n = 1;
-    while (n + n - 1 <= nodes) {
-      n = n + n;
-      h = h + 1;
-    }
-    return h - 1;
-  }
-
-  // Returns the height of the largest balanced tree
-  // that occupies no more than the given number of bytes.
-
-  private static int bytesToHeight (long bytes) {
-    return nodesToHeight (bytes / BYTES_PER_NODE);
-  }
-
-  // Returns a newly allocated balanced binary tree of height h.
-
-  private static TreeNode makeTree(int h) {
-    if (h == 0) return null;
-    else {
-      TreeNode res = new TreeNode();
-      nodes++;
-      res.left = makeTree(h-1);
-      res.right = makeTree(h-1);
-      res.val = h;
-      return res;
-    }
-  }
-
-  // Allocates approximately size megabytes of trees and stores
-  // them into a global array.
-
-  private static void init() {
-    int ntrees = (int) ((size * MEG) / treeSize);
-    trees = new TreeNode[ntrees];
-
-    System.err.println("Allocating " + ntrees + " trees.");
-    System.err.println("  (" + (ntrees * treeSize) + " bytes)");
-    for (int i = 0; i < ntrees; i++) {
-      trees[i] = makeTree(treeHeight);
-      // doYoungGenAlloc(promoteRate*ntrees*treeSize, WORDS_DEAD);
-    }
-    System.err.println("  (" + nodes + " nodes)");
-
-    /* Allow any in-progress GC to catch up... */
-    // try { Thread.sleep(20000); } catch (InterruptedException x) {}
-  }
-
-  // Confirms that all trees are balanced and have the correct height.
-
-  private static void checkTrees() {
-    int ntrees = trees.length;
-    for (int i = 0; i < ntrees; i++) {
-      TreeNode t = trees[i];
-      int h1 = height(t);
-      int h2 = shortestPath(t);
-      if ((h1 != treeHeight) || (h2 != treeHeight)) {
-        System.err.println("*****BUG: " + h1 + " " + h2);
-      }
-    }
-  }
-
-  // Called only by replaceTree (below) and by itself.
-
-  private static void replaceTreeWork(TreeNode full, TreeNode partial, boolean dir) {
-    boolean canGoLeft = full.left != null && full.left.val > partial.val;
-    boolean canGoRight = full.right != null && full.right.val > partial.val;
-    if (canGoLeft && canGoRight) {
-      if (dir)
-        replaceTreeWork(full.left, partial, !dir);
-      else
-        replaceTreeWork(full.right, partial, !dir);
-    } else if (!canGoLeft && !canGoRight) {
-      if (dir)
-        full.left = partial;
-      else
-        full.right = partial;
-    } else if (!canGoLeft) {
-      full.left = partial;
-    } else {
-      full.right = partial;
-    }
-  }
-
-  // Given a balanced tree full and a smaller balanced tree partial,
-  // replaces an appropriate subtree of full by partial, taking care
-  // to preserve the shape of the full tree.
-
-  private static void replaceTree(TreeNode full, TreeNode partial) {
-    boolean dir = (partial.val % 2) == 0;
-    actuallyMut++;
-    replaceTreeWork(full, partial, dir);
-  }
-
-  // Allocates approximately n bytes of long-lived storage,
-  // replacing oldest existing long-lived storage.
-
-  private static void oldGenAlloc(long n) {
-    int full = (int) (n / treeSize);
-    long partial = n % treeSize;
-    // System.out.println("In oldGenAlloc, doing " + full + " full trees "
-    // + "and one partial tree of size " + partial);
-    for (int i = 0; i < full; i++) {
-      trees[where++] = makeTree(treeHeight);
-      if (where == trees.length) where = 0;
-    }
-    while (partial > INSIGNIFICANT) {
-      int h = bytesToHeight(partial);
-      TreeNode newTree = makeTree(h);
-      replaceTree(trees[where++], newTree);
-      if (where == trees.length) where = 0;
-      partial = partial - heightToBytes(h);
-    }
-  }
-
-  // Interchanges two randomly selected subtrees (of same size and depth).
-
-  private static void oldGenSwapSubtrees() {
-    // Randomly pick:
-    //   * two tree indices
-    //   * A depth
-    //   * A path to that depth.
-    int index1 = rnd.nextInt(trees.length);
-    int index2 = rnd.nextInt(trees.length);
-    int depth = rnd.nextInt(treeHeight);
-    int path = rnd.nextInt();
-    TreeNode tn1 = trees[index1];
-    TreeNode tn2 = trees[index2];
-    for (int i = 0; i < depth; i++) {
-      if ((path & 1) == 0) {
-        tn1 = tn1.left;
-        tn2 = tn2.left;
-      } else {
-        tn1 = tn1.right;
-        tn2 = tn2.right;
-      }
-      path >>= 1;
-    }
-    TreeNode tmp;
-    if ((path & 1) == 0) {
-      tmp = tn1.left;
-      tn1.left = tn2.left;
-      tn2.left = tmp;
-    } else {
-      tmp = tn1.right;
-      tn1.right = tn2.right;
-      tn2.right = tmp;
-    }
-    actuallyMut += 2;
-  }
-
-  // Update "n" old-generation pointers.
-
-  private static void oldGenMut(long n) {
-    for (int i = 0; i < n/2; i++) {
-      oldGenSwapSubtrees();
-    }
-  }
-
-  // Does the amount of mutator work appropriate for n bytes of young-gen
-  // garbage allocation.
-
-  private static void doMutWork(long n) {
-    int sum = 0;
-    long limit = workUnits*n/10;
-    for (long k = 0; k < limit; k++) sum++;
-    // We don't want dead code elimination to eliminate the loop above.
-    mutatorSum = mutatorSum + sum;
-  }
-
-  // Allocate n bytes of young-gen garbage, in units of "nwords"
-  // words.
-
-  private static void doYoungGenAlloc(long n, int nwords) {
-    final int nbytes = nwords*BYTES_PER_WORD;
-    int allocated = 0;
-    while (allocated < n) {
-      aexport = new int[nwords];
-      /* System.err.println("Step"); */
-      allocated += nbytes;
-    }
-    youngBytes = youngBytes + allocated;
-  }
-
-  // Allocate "n" bytes of young-gen data; and do the
-  // corresponding amount of old-gen allocation and pointer
-  // mutation.
-
-  // oldGenAlloc may perform some mutations, so this code
-  // takes those mutations into account.
-
-  private static void doStep(long n) {
-    long mutations = actuallyMut;
-
-    doYoungGenAlloc(n, WORDS_DEAD);
-    doMutWork(n);
-    oldGenAlloc(n / promoteRate);
-    oldGenMut(Math.max(0L, (mutations + ptrMutRate) - actuallyMut));
-  }
-
-  public static void main(String[] args) {
-    if (args.length != 5) {
-      System.err.println(msg1);
-      System.err.println(msg2);
-      System.err.println(msg3);
-      System.err.println(msg4);
-      System.err.println(msg5);
-      System.err.println(msg6);
-      return;
-    }
-
-    size = Integer.parseInt(args[0]);
-    workUnits = Integer.parseInt(args[1]);
-    promoteRate = Integer.parseInt(args[2]);
-    ptrMutRate = Integer.parseInt(args[3]);
-    steps = Integer.parseInt(args[4]);
-
-    System.out.println(size + " megabytes of live storage");
-    System.out.println(workUnits + " work units per step");
-    System.out.println("promotion ratio is 1:" + promoteRate);
-    System.out.println("pointer mutation rate is " + ptrMutRate);
-    System.out.println(steps + " steps");
-
-    init();
-//  checkTrees();
-    youngBytes = 0;
-    nodes = 0;
-
-    System.err.println("Initialization complete...");
-
-    long start = System.currentTimeMillis();
-
-    for (int step = 0; step < steps; step++) {
-      doStep(MEG);
-    }
-
-    long end = System.currentTimeMillis();
-    float secs = ((float)(end-start))/1000.0F;
-
-//  checkTrees();
-
-    NumberFormat nf = NumberFormat.getInstance();
-    nf.setMaximumFractionDigits(1);
-    System.out.println("\nTook " + nf.format(secs) + " sec in steady state.");
-    nf.setMaximumFractionDigits(2);
-    System.out.println("Allocated " + steps + " Mb of young gen garbage"
-                       + " (= " + nf.format(((float)steps)/secs) +
-                       " Mb/sec)");
-    System.out.println("    (actually allocated " +
-                       nf.format(((float) youngBytes)/MEG) + " megabytes)");
-    float promoted = ((float)steps) / (float)promoteRate;
-    System.out.println("Promoted " + promoted +
-                       " Mb (= " + nf.format(promoted/secs) + " Mb/sec)");
-    System.out.println("    (actually promoted " +
-                       nf.format(((float) (nodes * BYTES_PER_NODE))/MEG) +
-                       " megabytes)");
-    if (ptrMutRate != 0) {
-      System.out.println("Mutated " + actuallyMut +
-                         " pointers (= " +
-                         nf.format(actuallyMut/secs) + " ptrs/sec)");
-
-    }
-    // This output serves mainly to discourage optimization.
-    System.out.println("Checksum = " + (mutatorSum + aexport.length));
-
-  }
-}
--- a/test/stress/gc/TestMultiThreadStressRSet.java	Wed Apr 13 19:55:40 2016 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,305 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import sun.hotspot.WhiteBox;
-
-/*
- * @test TestMultiThreadStressRSet.java
- * @key stress
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @requires os.maxMemory > 2G
- *
- * @summary Stress G1 Remembered Set using multiple threads
- * @library /test/lib /testlibrary
- * @build sun.hotspot.WhiteBox
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc
- *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4
- *
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
- *   -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16
- *
- * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *   -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
- *   -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32
- */
-public class TestMultiThreadStressRSet {
-
-    private static final Random RND = new Random(2015 * 2016);
-    private static final WhiteBox WB = WhiteBox.getWhiteBox();
-    private static final int REF_SIZE = WB.getHeapOopSize();
-    private static final int REGION_SIZE = WB.g1RegionSize();
-
-    // How many regions to use for the storage
-    private static final int STORAGE_REGIONS = 20;
-
-    // Size a single obj in the storage
-    private static final int OBJ_SIZE = 1024;
-
-    // How many regions of young/old gen to use in the BUFFER
-    private static final int BUFFER_YOUNG_REGIONS = 60;
-    private static final int BUFFER_OLD_REGIONS = 40;
-
-    // Total number of objects in the storage.
-    private final int N;
-
-    // The storage of byte[]
-    private final List<Object> STORAGE;
-
-    // Where references to the Storage will be stored
-    private final List<Object[]> BUFFER;
-
-    // The length of a buffer element.
-    // RSet deals with "cards" (areas of 512 bytes), not with single refs
-    // So, to affect the RSet the BUFFER refs should be allocated in different
-    // memory cards.
-    private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE);
-
-    // Total number of objects in the young/old buffers
-    private final int YOUNG;
-    private final int OLD;
-
-    // To cause Remembered Sets change their coarse level the test uses a window
-    // within STORAGE. All the BUFFER elements refer to only STORAGE objects
-    // from the current window. The window is defined by a range.
-    // The first element has got the index: 'windowStart',
-    // the last one: 'windowStart + windowSize - 1'
-    // The window is shifting periodically.
-    private int windowStart;
-    private final int windowSize;
-
-    // Counter of created worker threads
-    private int counter = 0;
-
-    private volatile String errorMessage = null;
-    private volatile boolean isEnough = false;
-
-    public static void main(String args[]) {
-        if (args.length != 2) {
-            throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length);
-        }
-        long time = Long.parseLong(args[0]);
-        int threads = Integer.parseInt(args[1]);
-        new TestMultiThreadStressRSet().test(time * 1000, threads);
-    }
-
-    /**
-     * Initiates test parameters, fills out the STORAGE and BUFFER.
-     */
-    public TestMultiThreadStressRSet() {
-
-        N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1;
-        STORAGE = new ArrayList<>(N);
-        int bytes = OBJ_SIZE - 20;
-        for (int i = 0; i < N - 1; i++) {
-            STORAGE.add(new byte[bytes]);
-        }
-        STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous
-        windowStart = 0;
-        windowSize = REGION_SIZE / OBJ_SIZE;
-
-        BUFFER = new ArrayList<>();
-        int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN;
-        OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject;
-        YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject;
-        for (int i = 0; i < OLD + YOUNG; i++) {
-            BUFFER.add(new Object[BUF_ARR_LEN]);
-        }
-    }
-
-    /**
-     * Does the testing. Steps:
-     * <ul>
-     * <li> starts the Shifter thread
-     * <li> during the given time starts new Worker threads, keeping the number
-     * of live thread under limit.
-     * <li> stops the Shifter thread
-     * </ul>
-     *
-     * @param timeInMillis how long to stress
-     * @param maxThreads the maximum number of Worker thread working together.
-     */
-    public void test(long timeInMillis, int maxThreads) {
-        if (timeInMillis <= 0 || maxThreads <= 0) {
-            throw new IllegalArgumentException("TEST BUG: be positive!");
-        }
-        System.out.println("%% Time to work: " + timeInMillis / 1000 + "s");
-        System.out.println("%% Number of threads: " + maxThreads);
-        long finish = System.currentTimeMillis() + timeInMillis;
-        Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9));
-        shift.start();
-        for (int i = 0; i < maxThreads; i++) {
-            new Worker(this, 100).start();
-        }
-        try {
-            while (System.currentTimeMillis() < finish && errorMessage == null) {
-                Thread.sleep(100);
-            }
-        } catch (Throwable t) {
-            printAllStackTraces(System.err);
-            t.printStackTrace(System.err);
-            this.errorMessage = t.getMessage();
-        } finally {
-            isEnough = true;
-        }
-        System.out.println("%% Total work cycles: " + counter);
-        if (errorMessage != null) {
-            throw new RuntimeException(errorMessage);
-        }
-    }
-
-    /**
-     * Returns an element from from the BUFFER (an object array) to keep
-     * references to the storage.
-     *
-     * @return an Object[] from buffer.
-     */
-    private Object[] getFromBuffer() {
-        int index = counter % (OLD + YOUNG);
-        synchronized (BUFFER) {
-            if (index < OLD) {
-                if (counter % 100 == (counter / 100) % 100) {
-                    // need to generate garbage in the old gen to provoke mixed GC
-                    return replaceInBuffer(index);
-                } else {
-                    return BUFFER.get(index);
-                }
-            } else {
-                return replaceInBuffer(index);
-            }
-        }
-    }
-
-    private Object[] replaceInBuffer(int index) {
-        Object[] objs = new Object[BUF_ARR_LEN];
-        BUFFER.set(index, objs);
-        return objs;
-    }
-
-    /**
-     * Returns a random object from the current window within the storage.
-     * A storage element with index from windowStart to windowStart+windowSize.
-     *
-     * @return a random element from the current window within the storage.
-     */
-    private Object getRandomObject() {
-        int index = (windowStart + RND.nextInt(windowSize)) % N;
-        return STORAGE.get(index);
-    }
-
-    private static void printAllStackTraces(PrintStream ps) {
-        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
-        for (Thread t : traces.keySet()) {
-            ps.println(t.toString() + " " + t.getState());
-            for (StackTraceElement traceElement : traces.get(t)) {
-                ps.println("\tat " + traceElement);
-            }
-        }
-    }
-
-    /**
-     * Thread to create a number of references from BUFFER to STORAGE.
-     */
-    private static class Worker extends Thread {
-
-        final TestMultiThreadStressRSet boss;
-        final int refs; // number of refs to OldGen
-
-        /**
-         * @param boss the tests
-         * @param refsToOldGen how many references to the OldGen to create
-         */
-        Worker(TestMultiThreadStressRSet boss, int refsToOldGen) {
-            this.boss = boss;
-            this.refs = refsToOldGen;
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!boss.isEnough) {
-                    Object[] objs = boss.getFromBuffer();
-                    int step = objs.length / refs;
-                    for (int i = 0; i < refs; i += step) {
-                        objs[i] = boss.getRandomObject();
-                    }
-                    boss.counter++;
-                }
-            } catch (Throwable t) {
-                t.printStackTrace(System.out);
-                boss.errorMessage = t.getMessage();
-            }
-        }
-    }
-
-    /**
-     * Periodically shifts the current STORAGE window, removing references
-     * in BUFFER that refer to objects outside the window.
-     */
-    private static class Shifter extends Thread {
-
-        final TestMultiThreadStressRSet boss;
-        final int sleepTime;
-        final int shift;
-
-        Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) {
-            this.boss = boss;
-            this.sleepTime = sleepTime;
-            this.shift = shift;
-        }
-
-        @Override
-        public void run() {
-            try {
-                while (!boss.isEnough) {
-                    Thread.sleep(sleepTime);
-                    boss.windowStart += shift;
-                    for (int i = 0; i < boss.OLD; i++) {
-                        Object[] objs = boss.BUFFER.get(i);
-                        for (int j = 0; j < objs.length; j++) {
-                            objs[j] = null;
-                        }
-                    }
-                    if (!WB.g1InConcurrentMark()) {
-                        System.out.println("%% start CMC");
-                        WB.g1StartConcMarkCycle();
-                    } else {
-                        System.out.println("%% CMC is already in progress");
-                    }
-                }
-            } catch (Throwable t) {
-                t.printStackTrace(System.out);
-                boss.errorMessage = t.getMessage();
-            }
-        }
-    }
-}
-
--- a/test/stress/gc/TestStressIHOPMultiThread.java	Wed Apr 13 19:55:40 2016 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
- /*
- * @test TestStressIHOPMultiThread
- * @bug 8148397
- * @key stress
- * @summary Stress test for IHOP
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=1m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread1.log
- *              -Dtimeout=2 -DheapUsageMinBound=30 -DheapUsageMaxBound=80
- *              -Dthreads=2 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=2m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread2.log
- *              -Dtimeout=2 -DheapUsageMinBound=60 -DheapUsageMaxBound=90
- *              -Dthreads=3 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx256m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=4m -XX:-G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread3.log
- *              -Dtimeout=2 -DheapUsageMinBound=40 -DheapUsageMaxBound=90
- *              -Dthreads=5 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx128m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=8m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread4.log
- *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
- *              -Dthreads=10 TestStressIHOPMultiThread
- * @run main/othervm/timeout=200 -Xmx512m -XX:G1HeapWastePercent=0 -XX:G1MixedGCCountTarget=1
- *              -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:+G1UseAdaptiveIHOP
- *              -Xlog:gc+ihop=debug,gc+ihop+ergo=debug,gc+ergo=debug:TestStressIHOPMultiThread5.log
- *              -Dtimeout=2 -DheapUsageMinBound=20 -DheapUsageMaxBound=90
- *              -Dthreads=17 TestStressIHOPMultiThread
- */
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Stress test for Adaptive IHOP. Starts a number of threads that fill and free
- * specified amount of memory. Tests work with enabled IHOP logging.
- *
- */
-public class TestStressIHOPMultiThread {
-
-    public final static List<Object> GARBAGE = new LinkedList<>();
-
-    private final long HEAP_SIZE;
-    // Amount of memory to be allocated before iterations start
-    private final long HEAP_PREALLOC_SIZE;
-    // Amount of memory to be allocated and freed during iterations
-    private final long HEAP_ALLOC_SIZE;
-    private final int CHUNK_SIZE = 100000;
-
-    private final int TIMEOUT;
-    private final int THREADS;
-    private final int HEAP_LOW_BOUND;
-    private final int HEAP_HIGH_BOUND;
-
-    private volatile boolean running = true;
-    private final List<AllocationThread> threads;
-
-    public static void main(String[] args) throws InterruptedException {
-        new TestStressIHOPMultiThread().start();
-
-    }
-
-    TestStressIHOPMultiThread() {
-
-        TIMEOUT = Integer.getInteger("timeout") * 60;
-        THREADS = Integer.getInteger("threads");
-        HEAP_LOW_BOUND = Integer.getInteger("heapUsageMinBound");
-        HEAP_HIGH_BOUND = Integer.getInteger("heapUsageMaxBound");
-        HEAP_SIZE = Runtime.getRuntime().maxMemory();
-
-        HEAP_PREALLOC_SIZE = HEAP_SIZE * HEAP_LOW_BOUND / 100;
-        HEAP_ALLOC_SIZE = HEAP_SIZE * (HEAP_HIGH_BOUND - HEAP_LOW_BOUND) / 100;
-
-        threads = new ArrayList<>(THREADS);
-    }
-
-    public void start() throws InterruptedException {
-        fill();
-        createThreads();
-        waitForStress();
-        stressDone();
-        waitForFinish();
-    }
-
-    /**
-     * Fills HEAP_PREALLOC_SIZE bytes of garbage.
-     */
-    private void fill() {
-        long allocated = 0;
-        while (allocated < HEAP_PREALLOC_SIZE) {
-            GARBAGE.add(new byte[CHUNK_SIZE]);
-            allocated += CHUNK_SIZE;
-        }
-    }
-
-    /**
-     * Creates a number of threads which will fill and free amount of memory.
-     */
-    private void createThreads() {
-        for (int i = 0; i < THREADS; ++i) {
-            System.out.println("Create thread " + i);
-            AllocationThread thread =new TestStressIHOPMultiThread.AllocationThread(i, HEAP_ALLOC_SIZE / THREADS);
-            // Put reference to thread garbage into common garbage for avoiding possible optimization.
-            GARBAGE.add(thread.getList());
-            threads.add(thread);
-        }
-        threads.forEach(t -> t.start());
-    }
-
-    /**
-     * Wait each thread for finishing
-     */
-    private void waitForFinish() {
-        threads.forEach(thread -> {
-            thread.silentJoin();
-        });
-    }
-
-    private boolean isRunning() {
-        return running;
-    }
-
-    private void stressDone() {
-        running = false;
-    }
-
-    private void waitForStress() throws InterruptedException {
-        Thread.sleep(TIMEOUT * 1000);
-    }
-
-    private class AllocationThread extends Thread {
-
-        private final List<Object> garbage;
-
-        private final long amountOfGarbage;
-        private final int threadId;
-
-        public AllocationThread(int id, long amount) {
-            super("Thread " + id);
-            threadId = id;
-            amountOfGarbage = amount;
-            garbage = new LinkedList<>();
-        }
-
-        /**
-         * Returns list of garbage.
-         * @return List with thread garbage.
-         */
-        public List<Object> getList(){
-            return garbage;
-        }
-
-        @Override
-        public void run() {
-            System.out.println("Start the thread " + threadId);
-            while (TestStressIHOPMultiThread.this.isRunning()) {
-                allocate(amountOfGarbage);
-                free();
-            }
-        }
-
-        private void silentJoin() {
-            System.out.println("Join the thread " + threadId);
-            try {
-                join();
-            } catch (InterruptedException ie) {
-                throw new RuntimeException(ie);
-            }
-        }
-
-        /**
-         * Allocates thread local garbage
-         */
-        private void allocate(long amount) {
-            long allocated = 0;
-            while (allocated < amount && TestStressIHOPMultiThread.this.isRunning()) {
-                garbage.add(new byte[CHUNK_SIZE]);
-                allocated += CHUNK_SIZE;
-            }
-        }
-
-        /**
-         * Frees thread local garbage
-         */
-        private void free() {
-            garbage.clear();
-        }
-    }
-}
--- a/test/stress/gc/TestStressRSetCoarsening.java	Wed Apr 13 19:55:40 2016 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,342 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.concurrent.TimeoutException;
-import sun.hotspot.WhiteBox;
-
-/*
- * @test TestStressRSetCoarsening.java
- * @key stress
- * @bug 8146984 8147087
- * @requires vm.gc=="G1" | vm.gc=="null"
- * @requires os.maxMemory > 3G
- *
- * @summary Stress G1 Remembered Set by creating a lot of cross region links
- * @modules java.base/sun.misc
- * @library /testlibrary /test/lib
- * @build sun.hotspot.WhiteBox
- * @run main ClassFileInstaller sun.hotspot.WhiteBox
- *                              sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  1  0 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx500m -XX:G1HeapRegionSize=8m TestStressRSetCoarsening  1 10 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx500m -XX:G1HeapRegionSize=32m TestStressRSetCoarsening 42 10 300
- * @run main/othervm/timeout=300
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx500m -XX:G1HeapRegionSize=1m TestStressRSetCoarsening  2 0 300
- * @run main/othervm/timeout=1800
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 500 0  1800
- * @run main/othervm/timeout=1800
- *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *     -XX:+UseG1GC -Xlog:gc* -XX:MaxGCPauseMillis=1000
- *     -Xmx1G -XX:G1HeapRegionSize=1m TestStressRSetCoarsening 10  10 1800
- */
-
-/**
- * What the test does.
- * Preparation stage:
- *   Fill out ~90% of the heap with objects, each object is an object array.
- *   If we want to allocate K objects per region, we calculate N to meet:
- *      sizeOf(Object[N]) ~= regionSize / K
- * Stress stage:
- *   No more allocation, so no more GC.
- *   We will perform a number of  iterations. On each iteration i,
- *   for each pair of regions Rx and Ry we will set c[i] references
- *   from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
- *   concurrent mark cycle will be initiated (to recalculate remembered sets).
- *   As the result RSet will be growing up and down, up and down many times.
- *
- * The test expects: no crash and no timeouts.
- *
- * Test Parameters:
- *   args[0] - number of objects per Heap Region (1 - means humongous)
- *   args[1] - number of regions to refresh to provoke GC at the end of cycle.
- *             (0 - means no GC, i.e. no reading from RSet)
- *   args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
- */
-public class TestStressRSetCoarsening {
-
-    public static void main(String... args) throws InterruptedException {
-        if (args.length != 3) {
-            throw new IllegalArgumentException("Wrong number of arguments " + args.length);
-        }
-        int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
-        int regsToRefresh = Integer.parseInt(args[1]);  // 0 means no regions to refresh at the end of cycle
-        int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
-        new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
-    }
-
-    private static final long KB = 1024;
-    private static final long MB = 1024 * KB;
-
-    private static final WhiteBox WB = WhiteBox.getWhiteBox();
-
-    public final Object[][] storage;
-
-    /**
-     * Number of objects per region. This is a test parameter.
-     */
-    public final int K;
-
-    /**
-     * Length of object array: sizeOf(Object[N]) ~= regionSize / K
-     * N will be calculated as function of K.
-     */
-    public final int N;
-
-    /**
-     * How many regions involved into testing.
-     * Will be calculated as heapFractionToAllocate * freeRegionCount.
-     */
-    public final int regionCount;
-
-    /**
-     * How much heap to use.
-     */
-    public final float heapFractionToAllocate = 0.9f;
-
-    /**
-     * How many regions to be refreshed at the end of cycle.
-     * This is a test parameter.
-     */
-    public final int regsToRefresh;
-
-    /**
-     * Initial time.
-     */
-    public final long start;
-
-    /**
-     * Time when the test should stop working.
-     */
-    public final long finishAt;
-
-    /**
-     * Does pre-calculation and allocate necessary objects.
-     *
-     * @param objPerRegions how many objects per G1 heap region
-     */
-    TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
-        this.K = objPerRegions;
-        this.regsToRefresh = regsToRefresh;
-        this.start = System.currentTimeMillis();
-        this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
-
-        long regionSize = WB.g1RegionSize();
-
-        // How many free regions
-        Runtime rt = Runtime.getRuntime();
-        long used = rt.totalMemory() - rt.freeMemory();
-        long totalFree = rt.maxMemory() - used;
-        regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
-        long toAllocate = regionCount * regionSize;
-        System.out.println("%% Test parameters");
-        System.out.println("%%   Objects per region              : " + K);
-        System.out.println("%%   Heap fraction to allocate       : " + (int) (heapFractionToAllocate * 100) + "%");
-        System.out.println("%%   Regions to refresh to provoke GC: " + regsToRefresh);
-
-        System.out.println("%% Memory");
-        System.out.println("%%   used          :        " + used / MB + "M");
-        System.out.println("%%   available     :        " + totalFree / MB + "M");
-        System.out.println("%%   to allocate   :        " + toAllocate / MB + "M");
-        System.out.println("%%     (in regs)   :        " + regionCount);
-        System.out.println("%%   G1 Region Size:        " + regionSize / MB + "M");
-
-        int refSize = WB.getHeapOopSize();
-
-        // Calculate N:    K*sizeOf(Object[N]) ~= regionSize
-        //                 sizeOf(Object[N]) ~=  (N+4)*refSize
-        // ==>
-        //                 N = regionSize / K / refSize - 4;
-        int n = (int) ((regionSize / K) / refSize) - 5;  // best guess
-        long objSize = WB.getObjectSize(new Object[n]);
-        while (K*objSize > regionSize) {   // adjust to avoid OOME
-            n = n - 1;
-            objSize = WB.getObjectSize(new Object[n]);
-        }
-        N = n;
-
-        /*
-         *   --------------
-         *   region0   storage[0]        = new Object[N]
-         *             ...
-         *             storage[K-1]      = new Object[N]
-         *   ---------------
-         *   region1   storage[K]        = new Object[N]
-         *             ...
-         *             storage[2*K - 1]  = new Object[N]
-         *   --------------
-         *   ...
-         *   --------------
-         *   regionX   storage[X*K]         = new Object[N]
-         *             ...
-         *             storage[(X+1)*K -1]  = new Object[N]
-         *    where X = HeapFraction * TotalRegions
-         *   -------------
-         */
-        System.out.println("%% Objects");
-        System.out.println("%%   N (array length)      : " + N);
-        System.out.println("%%   K (objects in regions): " + K);
-        System.out.println("%%   Object size           : " + objSize +
-                "  (sizeOf(new Object[" + N + "])");
-        System.out.println("%%   Reference size        : " + refSize);
-
-        storage = new Object[regionCount * K][];
-        for (int i = 0; i < storage.length; i++) {
-            storage[i] = new Object[N];
-        }
-    }
-
-    public void go() throws InterruptedException {
-        // threshold for sparce -> fine
-        final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
-
-        // threshold for fine -> coarse
-        final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
-
-        // regToRegRefCounts - array of reference counts from region to region
-        // at the the end of iteration.
-        // The number of test iterations is array length - 1.
-        // If c[i] > c[i-1] then during the iteration i more references will
-        // be created.
-        // If c[i] < c[i-1] then some referenes will be cleaned.
-        int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
-            COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
-
-        // For progress tracking
-        int[] progress = new int[regToRegRefCounts.length];
-        progress[0] = 0;
-        for (int i = 1; i < regToRegRefCounts.length; i++) {
-            progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
-        }
-        try {
-            for (int i = 1; i < regToRegRefCounts.length; i++) {
-                int pre = regToRegRefCounts[i - 1];
-                int cur = regToRegRefCounts[i];
-                float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
-
-                System.out.println("%% step " + i
-                        + " out of " + (regToRegRefCounts.length - 1)
-                        + " (~" + (int) (100 * prog) + "% done)");
-                System.out.println("%%      " + pre + "  --> " + cur);
-                for (int to = 0; to < regionCount; to++) {
-                    // Select a celebrity object that we will install references to.
-                    // The celebrity will be referred from all other regions.
-                    // If the number of references after should be less than they
-                    // were before, select NULL.
-                    Object celebrity = cur > pre ? storage[to * K] : null;
-                    for (int from = 0; from < regionCount; from++) {
-                        if (to == from) {
-                            continue; // no need to refer to itself
-                        }
-
-                        int step = cur > pre ? +1 : -1;
-                        for (int rn = pre; rn != cur; rn += step) {
-                            storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
-                            if (System.currentTimeMillis() > finishAt) {
-                                throw new TimeoutException();
-                            }
-                        }
-                    }
-                }
-                if (pre > cur) {
-                    // Number of references went down.
-                    // Need to provoke recalculation of RSet.
-                    WB.g1StartConcMarkCycle();
-                    while (WB.g1InConcurrentMark()) {
-                        Thread.sleep(1);
-                    }
-                }
-
-                // To force the use of rememebered set entries we need to provoke a GC.
-                // To induce some fragmentation, and some mixed GCs, we need
-                // to make a few objects unreachable.
-                for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
-                    int to = toClean % regionCount;
-                    // Need to remove all references from all regions to the region 'to'
-                    for (int from = 0; from < regionCount; from++) {
-                        if (to == from) {
-                            continue; // no need to refer to itself
-                        }
-                        for (int rn = 0; rn <= cur; rn++) {
-                            storage[getY(to, from, rn)][getX(to, from, rn)] = null;
-                        }
-                    }
-                    // 'Refresh' storage elements for the region 'to'
-                    // After that loop all 'old' objects in the region 'to'
-                    // should become unreachable.
-                    for (int k = 0; k < K; k++) {
-                        storage[(to * K + k) % storage.length] = new Object[N];
-                    }
-                }
-            }
-        } catch (TimeoutException e) {
-            System.out.println("%% TIMEOUT!!!");
-        }
-        long now = System.currentTimeMillis();
-        System.out.println("%% Summary");
-        System.out.println("%%   Time spent          : " + ((now - start) / 1000) + " seconds");
-        System.out.println("%%   Free memory left    : " + Runtime.getRuntime().freeMemory() / KB + "K");
-        System.out.println("%% Test passed");
-    }
-
-    /**
-     * Returns X index in the Storage of the reference #rn from the region
-     * 'from' to the region 'to'.
-     *
-     * @param to region # to refer to
-     * @param from region # to refer from
-     * @param rn number of reference
-     *
-     * @return X index in the range: [0 ... N-1]
-     */
-    private int getX(int to, int from, int rn) {
-        return (rn * regionCount + to) % N;
-    }
-
-    /**
-     * Returns Y index in the Storage of the reference #rn from the region
-     * 'from' to the region 'to'.
-     *
-     * @param to region # to refer to
-     * @param from region # to refer from
-     * @param rn number of reference
-     *
-     * @return Y index in the range: [0 ... K*regionCount -1]
-     */
-    private int getY(int to, int from, int rn) {
-        return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
-    }
-}
-