Merge
authoriignatyev
Fri, 29 Jan 2016 12:30:00 +0000
changeset 35886 94e8a812959d
parent 35884 ec439aaca107 (current diff)
parent 35885 6e62be7db2c8 (diff)
child 35888 d737e343520a
Merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,327 @@
+/*
+ * 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 TestPLABPromotion
+ * @bug 8141278
+ * @summary Test PLAB promotion
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @library /testlibrary /../../test/lib /
+ * @modules java.management
+ * @build ClassFileInstaller
+ *        sun.hotspot.WhiteBox
+ *        gc.g1.plab.lib.MemoryConsumer
+ *        gc.g1.plab.lib.LogParser
+ *        gc.g1.plab.lib.AppPLABPromotion
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main gc.g1.plab.TestPLABPromotion
+ */
+package gc.g1.plab;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.PrintStream;
+
+import gc.g1.plab.lib.AppPLABPromotion;
+import gc.g1.plab.lib.LogParser;
+import gc.g1.plab.lib.PLABUtils;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Platform;
+
+/**
+ * Test checks PLAB promotion of different size objects.
+ */
+public class TestPLABPromotion {
+
+    // GC ID with survivor PLAB statistics
+    private final static long GC_ID_SURVIVOR_STATS = 1l;
+    // GC ID with old PLAB statistics
+    private final static long GC_ID_OLD_STATS = 2l;
+
+    // Threshold to determine whether the correct amount of objects were promoted.
+    // This is only an approximate threshold for these checks.
+    private final static long MEM_CONSUMPTION_THRESHOLD = 256l * 1024l;
+
+    private static final int PLAB_SIZE_SMALL = 1024;
+    private static final int PLAB_SIZE_MEDIUM = 4096;
+    private static final int PLAB_SIZE_HIGH = 65536;
+    private static final int OBJECT_SIZE_SMALL = 10;
+    private static final int OBJECT_SIZE_MEDIUM = 100;
+    private static final int OBJECT_SIZE_HIGH = 1000;
+    private static final int GC_NUM_SMALL = 1;
+    private static final int GC_NUM_MEDIUM = 3;
+    private static final int GC_NUM_HIGH = 7;
+    private static final int WASTE_PCT_SMALL = 10;
+    private static final int WASTE_PCT_MEDIUM = 20;
+    private static final int WASTE_PCT_HIGH = 30;
+    private static final int YOUNG_SIZE_LOW = 16;
+    private static final int YOUNG_SIZE_HIGH = 64;
+    private static final boolean PLAB_FIXED = true;
+    private static final boolean PLAB_DYNAMIC = false;
+
+    private final static TestCase[] TEST_CASES = {
+        // Test cases for unreachable object, PLAB size is fixed
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, false, false),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, false, false),
+        // Test cases for reachable objects, PLAB size is fixed
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, false),
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_HIGH, PLAB_FIXED, true, false),
+        // Test cases for unreachable object, PLAB size is not fixed
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, false, false),
+        // Test cases for reachable objects, PLAB size is not fixed
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true),
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true),
+        new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, false),
+        new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true),
+        new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true)
+    };
+
+    public static void main(String[] args) throws Throwable {
+
+        for (TestCase testCase : TEST_CASES) {
+            // What we going to check.
+            testCase.print(System.out);
+            List<String> options = PLABUtils.prepareOptions(testCase.toOptions());
+            options.add(AppPLABPromotion.class.getName());
+            OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()]));
+            if (out.getExitValue() != 0) {
+                System.out.println(out.getOutput());
+                throw new RuntimeException("Expect exit code 0.");
+            }
+            checkResults(out.getOutput(), testCase);
+        }
+    }
+
+    private static void checkResults(String output, TestCase testCase) {
+        long plabAllocatedSurvivor;
+        long directAllocatedSurvivor;
+        long plabAllocatedOld;
+        long directAllocatedOld;
+        long memAllocated = testCase.getMemToFill();
+        long wordSize = Platform.is32bit() ? 4l : 8l;
+        LogParser logParser = new LogParser(output);
+
+        Map<String, Long> survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS);
+        Map<String, Long> oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS);
+
+        plabAllocatedSurvivor = wordSize * survivorStats.get("used");
+        directAllocatedSurvivor = wordSize * survivorStats.get("direct_allocated");
+        plabAllocatedOld = wordSize * oldStats.get("used");
+        directAllocatedOld = wordSize * oldStats.get("direct_allocated");
+
+        System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated);
+        System.out.printf("Old      PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated);
+
+        // Unreachable objects case
+        if (testCase.isDeadObjectCase()) {
+            // No dead objects should be promoted
+            if (plabAllocatedSurvivor > MEM_CONSUMPTION_THRESHOLD || directAllocatedSurvivor > MEM_CONSUMPTION_THRESHOLD) {
+                System.out.println(output);
+                throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Survivor");
+            }
+            if (plabAllocatedOld > MEM_CONSUMPTION_THRESHOLD || directAllocatedOld > MEM_CONSUMPTION_THRESHOLD) {
+                System.out.println(output);
+                throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Old");
+            }
+        } else {
+            // Live objects case
+            if (testCase.isPromotedByPLAB()) {
+                // All live small objects should be promoted using PLAB
+                if (Math.abs(plabAllocatedSurvivor - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                    System.out.println(output);
+                    throw new RuntimeException("Expect that Survivor PLAB allocation are similar to all mem consumed");
+                }
+                if (Math.abs(plabAllocatedOld - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                    System.out.println(output);
+                    throw new RuntimeException("Expect that Old PLAB allocation are similar to all mem consumed");
+                }
+            } else {
+                // All big objects should be directly allocated
+                if (Math.abs(directAllocatedSurvivor - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                    System.out.println(output);
+                    throw new RuntimeException("Test fails. Expect that Survivor direct allocation are similar to all mem consumed");
+                }
+                if (Math.abs(directAllocatedOld - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                    System.out.println(output);
+                    throw new RuntimeException("Test fails. Expect that Old direct allocation are similar to all mem consumed");
+                }
+            }
+
+            // All promoted objects size should be similar to all consumed memory
+            if (Math.abs(plabAllocatedSurvivor + directAllocatedSurvivor - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                System.out.println(output);
+                throw new RuntimeException("Test fails. Expect that Survivor gen total allocation are similar to all mem consumed");
+            }
+            if (Math.abs(plabAllocatedOld + directAllocatedOld - memAllocated) > MEM_CONSUMPTION_THRESHOLD) {
+                System.out.println(output);
+                throw new RuntimeException("Test fails. Expect that Old gen total allocation are similar to all mem consumed");
+            }
+        }
+        System.out.println("Test passed!");
+    }
+
+    private static Map<String, Long> getPlabStats(LogParser logParser, LogParser.ReportType type, long gc_id) {
+
+        Map<String, Long> survivorStats = logParser.getEntries()
+                .get(gc_id)
+                .get(type);
+        return survivorStats;
+    }
+
+    /**
+     * Description of one test case.
+     */
+    private static class TestCase {
+
+        private final int wastePct;
+        private final int plabSize;
+        private final int chunkSize;
+        private final int parGCThreads;
+        private final int edenSize;
+        private final boolean plabIsFixed;
+        private final boolean objectsAreReachable;
+        private final boolean promotedByPLAB;
+
+        /**
+         * @param wastePct
+         * ParallelGCBufferWastePct
+         * @param plabSize
+         * -XX:OldPLABSize and -XX:YoungPLABSize
+         * @param chunkSize
+         * requested object size for memory consumption
+         * @param parGCThreads
+         * -XX:ParallelGCThreads
+         * @param edenSize
+         * NewSize and MaxNewSize
+         * @param plabIsFixed
+         * Use dynamic PLAB or fixed size PLAB
+         * @param objectsAreReachable
+         * true - allocate live objects
+         * false - allocate unreachable objects
+         * @param promotedByPLAB
+         * true - we expect to see PLAB allocation during promotion
+         * false - objects will be directly allocated during promotion
+         */
+        public TestCase(int wastePct,
+                int plabSize,
+                int chunkSize,
+                int parGCThreads,
+                int edenSize,
+                boolean plabIsFixed,
+                boolean objectsAreReachable,
+                boolean promotedByPLAB
+        ) {
+            if (wastePct == 0 || plabSize == 0 || chunkSize == 0 || parGCThreads == 0 || edenSize == 0) {
+                throw new IllegalArgumentException("Parameters should not be 0");
+            }
+            this.wastePct = wastePct;
+            this.plabSize = plabSize;
+            this.chunkSize = chunkSize;
+            this.parGCThreads = parGCThreads;
+            this.edenSize = edenSize;
+            this.plabIsFixed = plabIsFixed;
+            this.objectsAreReachable = objectsAreReachable;
+            this.promotedByPLAB = promotedByPLAB;
+        }
+
+        /**
+         * Convert current TestCase to List of options.
+         * Assume test will fill half of existed eden.
+         *
+         * @return
+         * List of options
+         */
+        public List<String> toOptions() {
+            return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads,
+                    "-XX:ParallelGCBufferWastePct=" + wastePct,
+                    "-XX:OldPLABSize=" + plabSize,
+                    "-XX:YoungPLABSize=" + plabSize,
+                    "-XX:" + (plabIsFixed ? "-" : "+") + "ResizePLAB",
+                    "-Dchunk.size=" + chunkSize,
+                    "-Dreachable=" + objectsAreReachable,
+                    "-XX:NewSize=" + edenSize + "m",
+                    "-XX:MaxNewSize=" + edenSize + "m",
+                    "-Dmem.to.fill=" + getMemToFill()
+            );
+        }
+
+        /**
+         * Print details about test case.
+         */
+        public void print(PrintStream out) {
+            boolean expectPLABAllocation = promotedByPLAB && objectsAreReachable;
+            boolean expectDirectAllocation = (!promotedByPLAB) && objectsAreReachable;
+
+            out.println("Test case details:");
+            out.println("  Young gen size : " + edenSize + "M");
+            out.println("  Predefined PLAB size : " + plabSize);
+            out.println("  Parallel GC buffer waste pct : " + wastePct);
+            out.println("  Chunk size : " + chunkSize);
+            out.println("  Parallel GC threads : " + parGCThreads);
+            out.println("  Objects are created : " + (objectsAreReachable ? "reachable" : "unreachable"));
+            out.println("  PLAB size is fixed: " + (plabIsFixed ? "yes" : "no"));
+            out.println("Test expectations:");
+            out.println("  PLAB allocation : " + (expectPLABAllocation ? "expected" : "unexpected"));
+            out.println("  Direct allocation : " + (expectDirectAllocation ? "expected" : "unexpected"));
+        }
+
+        /**
+         * @return
+         * true if we expect PLAB allocation
+         * false if no
+         */
+        public boolean isPromotedByPLAB() {
+            return promotedByPLAB;
+        }
+
+        /**
+         * @return
+         * true if it is test case for unreachable objects
+         * false for live objects
+         */
+        public boolean isDeadObjectCase() {
+            return !objectsAreReachable;
+        }
+
+        /**
+         * Returns amount of memory to fill
+         *
+         * @return amount of memory
+         */
+        public long getMemToFill() {
+            return (long) (edenSize) * 1024l * 1024l / 2;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/TestPLABResize.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,222 @@
+/*
+ * 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 TestPLABResize
+ * @bug 8141278
+ * @summary Test for PLAB resizing
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @library /testlibrary /../../test/lib /
+ * @modules java.management
+ * @build ClassFileInstaller
+ *        sun.hotspot.WhiteBox
+ *        gc.g1.plab.lib.LogParser
+ *        gc.g1.plab.lib.MemoryConsumer
+ *        gc.g1.plab.lib.PLABUtils
+ *        gc.g1.plab.lib.AppPLABResize
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main gc.g1.plab.TestPLABResize
+ */
+package gc.g1.plab;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.io.PrintStream;
+
+import gc.g1.plab.lib.LogParser;
+import gc.g1.plab.lib.PLABUtils;
+import gc.g1.plab.lib.AppPLABResize;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+/**
+ * Test for PLAB resizing.
+ */
+public class TestPLABResize {
+
+    private static final int OBJECT_SIZE_SMALL = 10;
+    private static final int OBJECT_SIZE_MEDIUM = 70;
+    private static final int OBJECT_SIZE_HIGH = 150;
+    private static final int GC_NUM_SMALL = 1;
+    private static final int GC_NUM_MEDIUM = 3;
+    private static final int GC_NUM_HIGH = 7;
+    private static final int WASTE_PCT_SMALL = 10;
+    private static final int WASTE_PCT_MEDIUM = 20;
+    private static final int WASTE_PCT_HIGH = 30;
+
+    private static final int ITERATIONS_SMALL = 3;
+    private static final int ITERATIONS_MEDIUM = 5;
+    private static final int ITERATIONS_HIGH = 8;
+
+    private final static TestCase[] TEST_CASES = {
+        new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_SMALL, GC_NUM_SMALL, ITERATIONS_MEDIUM),
+        new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_HIGH, ITERATIONS_SMALL),
+        new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH),
+        new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, ITERATIONS_MEDIUM),
+        new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, ITERATIONS_SMALL),
+        new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH),
+        new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, ITERATIONS_MEDIUM),
+        new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, ITERATIONS_SMALL),
+        new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH)
+    };
+
+    public static void main(String[] args) throws Throwable {
+        for (TestCase testCase : TEST_CASES) {
+            testCase.print(System.out);
+            List<String> options = PLABUtils.prepareOptions(testCase.toOptions());
+            options.add(AppPLABResize.class.getName());
+            OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()]));
+            if (out.getExitValue() != 0) {
+                System.out.println(out.getOutput());
+                throw new RuntimeException("Exit code is not 0");
+            }
+            checkResults(out.getOutput(), testCase);
+        }
+    }
+
+    /**
+     * Checks testing results.
+     * Expected results - desired PLAB size is decreased and increased during promotion to Survivor.
+     *
+     * @param output - VM output
+     * @param testCase
+     */
+    private static void checkResults(String output, TestCase testCase) {
+        final LogParser log = new LogParser(output);
+        final Map<Long, Map<LogParser.ReportType, Map<String, Long>>> entries = log.getEntries();
+
+        final ArrayList<Long> plabSizes = entries.entrySet()
+                .stream()
+                .map(item -> {
+                    return item.getValue()
+                            .get(LogParser.ReportType.SURVIVOR_STATS)
+                            .get("desired_plab_sz");
+                })
+                .collect(Collectors.toCollection(ArrayList::new));
+
+        // Check that desired plab size was changed during iterations.
+        // It should decrease during first half of iterations
+        // and increase after.
+        List<Long> decreasedPlabs = plabSizes.subList(testCase.getIterations(), testCase.getIterations() * 2);
+        List<Long> increasedPlabs = plabSizes.subList(testCase.getIterations() * 2, testCase.getIterations() * 3);
+
+        Long prev = decreasedPlabs.get(0);
+        for (int index = 1; index < decreasedPlabs.size(); ++index) {
+            Long current = decreasedPlabs.get(index);
+            if (prev < current) {
+                System.out.println(output);
+                throw new RuntimeException("Test failed! Expect that previous PLAB size should be greater than current. Prev.size: " + prev + " Current size:" + current);
+            }
+            prev = current;
+        }
+
+        prev = increasedPlabs.get(0);
+        for (int index = 1; index < increasedPlabs.size(); ++index) {
+            Long current = increasedPlabs.get(index);
+            if (prev > current) {
+                System.out.println(output);
+                throw new RuntimeException("Test failed! Expect that previous PLAB size should be less than current. Prev.size: " + prev + " Current size:" + current);
+            }
+            prev = current;
+        }
+
+        System.out.println("Test passed!");
+    }
+
+    /**
+     * Description of one test case.
+     */
+    private static class TestCase {
+
+        private final int wastePct;
+        private final int chunkSize;
+        private final int parGCThreads;
+        private final int iterations;
+
+        /**
+         * @param wastePct
+         * ParallelGCBufferWastePct
+         * @param chunkSize
+         * requested object size for memory consumption
+         * @param parGCThreads
+         * -XX:ParallelGCThreads
+         * @param iterations
+         *
+         */
+        public TestCase(int wastePct,
+                int chunkSize,
+                int parGCThreads,
+                int iterations
+        ) {
+            if (wastePct == 0 || chunkSize == 0 || parGCThreads == 0 || iterations == 0) {
+                throw new IllegalArgumentException("Parameters should not be 0");
+            }
+            this.wastePct = wastePct;
+
+            this.chunkSize = chunkSize;
+            this.parGCThreads = parGCThreads;
+            this.iterations = iterations;
+        }
+
+        /**
+         * Convert current TestCase to List of options.
+         *
+         * @return
+         * List of options
+         */
+        public List<String> toOptions() {
+            return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads,
+                    "-XX:ParallelGCBufferWastePct=" + wastePct,
+                    "-XX:+ResizePLAB",
+                    "-Dthreads=" + parGCThreads,
+                    "-Dchunk.size=" + chunkSize,
+                    "-Diterations=" + iterations,
+                    "-XX:NewSize=16m",
+                    "-XX:MaxNewSize=16m"
+            );
+        }
+
+        /**
+         * Print details about test case.
+         */
+        public void print(PrintStream out) {
+            out.println("Test case details:");
+            out.println("  Parallel GC buffer waste pct : " + wastePct);
+            out.println("  Chunk size : " + chunkSize);
+            out.println("  Parallel GC threads : " + parGCThreads);
+            out.println("  Iterations: " + iterations);
+        }
+
+        /**
+         * @return iterations
+         */
+        public int getIterations() {
+            return iterations;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/AppPLABPromotion.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+package gc.g1.plab.lib;
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * This application is part of PLAB promotion test.
+ * The application fills a part of young gen with a number of small objects.
+ * Then it calls young GC twice to promote objects from eden to survivor, and from survivor to old.
+ * The test which running the application is responsible to set up test parameters
+ * and VM flags including flags turning GC logging on. The test will then check the produced log.
+ */
+final public class AppPLABPromotion {
+
+    private final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+    /**
+     * AppPLABPromotion is used for testing PLAB promotion.
+     * Expects the following properties to be set:
+     * - chunk.size - size of one object (byte array)
+     * - mem.to.fill - amount of memory to be consumed
+     * - reachable - memory should be consumed by live or dead objects
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        long chunkSize = Long.getLong("chunk.size");
+        long memToFill = Long.getLong("mem.to.fill");
+        boolean reachable = Boolean.getBoolean("reachable");
+        if (chunkSize == 0) {
+            throw new IllegalArgumentException("Chunk size must be not 0");
+        }
+        if (memToFill <= 0) {
+            throw new IllegalArgumentException("mem.to.fill property should be above 0");
+        }
+        // Fill requested amount of memory
+        allocate(reachable, memToFill, chunkSize);
+        // Promote all allocated objects from Eden to Survivor
+        WHITE_BOX.youngGC();
+        // Promote all allocated objects from Survivor to Old
+        WHITE_BOX.youngGC();
+    }
+
+    /**
+     *
+     * @param reachable - should allocate reachable object
+     * @param memSize - Memory to fill
+     * @param chunkSize - requested bytes per objects.
+     * Actual size of bytes per object will be greater
+     */
+    private static void allocate(boolean reachable, long memSize, long chunkSize) {
+        long realSize = WHITE_BOX.getObjectSize(new byte[(int) chunkSize]);
+        int items = (int) ((memSize - 1) / (realSize)) + 1;
+        MemoryConsumer storage;
+        if (reachable) {
+            storage = new MemoryConsumer(items, (int) chunkSize);
+        } else {
+            storage = new MemoryConsumer(1, (int) chunkSize);
+        }
+        // Make all young gen available.
+        WHITE_BOX.fullGC();
+        storage.consume(items * chunkSize);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/AppPLABResize.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package gc.g1.plab.lib;
+
+import jdk.test.lib.Platform;
+import sun.hotspot.WhiteBox;
+
+/**
+ * This application is part of PLAB Resize test.
+ * The application allocates objects in 3 iterations:
+ * 1. Objects of fixed size
+ * 2. Objects of decreasing size
+ * 3. Objects of increasing size
+ * The application doesn't have any assumptions about expected behavior.
+ * It's supposed to be executed by a test which should set up test parameters (object sizes, number of allocations, etc)
+ * and VM flags including flags turning GC logging on. The test will then check the produced log.
+ *
+ * Expects the following properties to be set:
+ * - iterations - amount of iteration per cycle.
+ * - chunk.size - size of objects to be allocated
+ * - threads - number of gc threads (-XX:ParallelGCThreads) to calculate PLAB sizes.
+ */
+final public class AppPLABResize {
+
+    // Memory to be promoted by PLAB for one thread.
+    private static final long MEM_ALLOC_WORDS = 32768;
+    // Defined by properties.
+    private static final int ITERATIONS = Integer.getInteger("iterations");
+    private static final long CHUNK = Long.getLong("chunk.size");
+    private static final int GC_THREADS = Integer.getInteger("threads");
+
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+    /**
+     * Main method for AppPLABResizing. Application expect for next properties:
+     * iterations, chunk.size and threads.
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+
+        if (ITERATIONS == 0 || CHUNK == 0 || GC_THREADS == 0) {
+            throw new IllegalArgumentException("Properties should be set");
+        }
+
+        long wordSize = Platform.is32bit() ? 4l : 8l;
+        // PLAB size is shared between threads.
+        long initialMemorySize = wordSize * GC_THREADS * MEM_ALLOC_WORDS;
+
+        // Expect changing memory to half during all iterations.
+        long memChangeStep = initialMemorySize / 2 / ITERATIONS;
+
+        WHITE_BOX.fullGC();
+
+        // Warm the PLAB. Fill memory ITERATIONS times without changing memory size.
+        iterateAllocation(initialMemorySize, 0);
+        // Fill memory ITERATIONS times.
+        // Initial size is initialMemorySize and step is -memChangeStep
+        iterateAllocation(initialMemorySize, -memChangeStep);
+        // Fill memory ITERATIONS times.
+        // Initial size is memoryAfterChanging, step is memChangeStep.
+        // Memory size at start should be greater then last size on previous step.
+        // Last size on previous step is initialMemorySize - memChangeStep*(ITERATIONS - 1)
+        long memoryAfterChanging = initialMemorySize - memChangeStep * (ITERATIONS - 2);
+        iterateAllocation(memoryAfterChanging, memChangeStep);
+    }
+
+    private static void iterateAllocation(long memoryToFill, long change) {
+        int items;
+        if (change > 0) {
+            items = (int) ((memoryToFill + change * ITERATIONS) / CHUNK) + 1;
+        } else {
+            items = (int) (memoryToFill / CHUNK) + 1;
+        }
+
+        long currentMemToFill = memoryToFill;
+        for (int iteration = 0; iteration < ITERATIONS; ++iteration) {
+            MemoryConsumer storage = new MemoryConsumer(items, (int) CHUNK);
+            storage.consume(currentMemToFill);
+            // Promote all objects to survivor
+            WHITE_BOX.youngGC();
+            storage.clear();
+            currentMemToFill += change;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/LogParser.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+package gc.g1.plab.lib;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * LogParser class parses VM output to get PLAB and ConsumptionStats values.
+ *
+ * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like:
+ *
+ * [2,244s][info   ][gc     ] GC(30) Concurrent Mark abort
+ * [2,245s][debug  ][gc,plab] GC(33)  (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0)  (plab_sz = 0 desired_plab_sz = 258)
+ * [2,245s][debug  ][gc,plab] GC(33)  (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0)  (plab_sz = 0 desired_plab_sz = 258)
+ * [2,245s][info   ][gc     ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms
+ * [2,246s][debug  ][gc,plab] GC(34)  (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0)  (plab_sz = 0 desired_plab_sz = 258)
+ * [2,246s][debug  ][gc,plab] GC(34)  (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0)  (plab_sz = 0 desired_plab_sz = 258)
+ * [2,246s][info   ][gc     ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms
+
+ */
+final public class LogParser {
+
+    // Name for GC ID field in report.
+    public final static String GC_ID = "gc_id";
+
+    /**
+     * Type of parsed log element.
+     */
+    public static enum ReportType {
+
+        SURVIVOR_STATS,
+        OLD_STATS
+    }
+
+    private final String log;
+
+    private final Map<Long, Map<ReportType, Map<String,Long>>> reportHolder;
+
+    // GC ID
+    private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)");
+    // Pattern for extraction pair <name>=<numeric value>
+    private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+");
+
+    /**
+     * Construct LogParser Object
+     *
+     * @param log - VM Output
+     */
+    public LogParser(String log) {
+        if (log == null) {
+            throw new IllegalArgumentException("Parameter log should not be null.");
+        }
+        this.log = log;
+        reportHolder = parseLines();
+    }
+
+    /**
+     * @return log which is being processed
+     */
+    public String getLog() {
+        return log;
+    }
+
+    /**
+     * Returns list of log entries.
+     *
+     * @return list of Pair with ReportType and Map of parameters/values.
+     */
+    public Map<Long,Map<ReportType, Map<String,Long>>> getEntries() {
+        return reportHolder;
+    }
+
+    private Map<Long,Map<ReportType, Map<String,Long>>> parseLines() throws NumberFormatException {
+        Scanner lineScanner = new Scanner(log);
+        Map<Long,Map<ReportType, Map<String,Long>>> allocationStatistics = new HashMap<>();
+        Optional<Long> gc_id;
+        while (lineScanner.hasNextLine()) {
+            String line = lineScanner.nextLine();
+            gc_id = getGcId(line);
+            if ( gc_id.isPresent() ) {
+                Matcher matcher = PAIRS_PATTERN.matcher(line);
+                if (matcher.find()) {
+                    Map<ReportType,Map<String, Long>> oneReportItem;
+                    ReportType reportType;
+                    // Second line in log is statistics for Old PLAB allocation
+                    if ( !allocationStatistics.containsKey(gc_id.get()) ) {
+                        oneReportItem = new EnumMap<>(ReportType.class);
+                        reportType = ReportType.SURVIVOR_STATS;
+                        allocationStatistics.put(gc_id.get(), oneReportItem);
+                    } else {
+                        oneReportItem = allocationStatistics.get(gc_id.get());
+                        reportType = ReportType.OLD_STATS;
+                    }
+
+                    // Extract all pairs from log.
+                    HashMap<String, Long> plabStats = new HashMap<>();
+                    do {
+                        String pair = matcher.group();
+                        String[] nameValue = pair.replaceAll(" ", "").split("=");
+                        plabStats.put(nameValue[0], Long.parseLong(nameValue[1]));
+                    } while (matcher.find());
+                    oneReportItem.put(reportType,plabStats);
+                }
+            }
+        }
+        return allocationStatistics;
+    }
+
+    private Optional<Long> getGcId(String line) {
+        Matcher number = GC_ID_PATTERN.matcher(line);
+        if (number.find()) {
+            return Optional.of(Long.parseLong(number.group(1)));
+        }
+        return Optional.empty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/MemoryConsumer.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package gc.g1.plab.lib;
+
+/**
+ * The MemoryConsumer is used for consuming different amount of memory.
+ * Class will store not more than 'capacity' number of objects with 'chunk' size.
+ * If we exceed capacity, object will be stored at existing entries,
+ * all previously added objects will be overwritten.
+ * If capacity=1, only last object will be saved.
+ */
+public class MemoryConsumer {
+
+    private int capacity;
+    private int chunk;
+
+    private Object[] array;
+    private int index;
+
+    /**
+     * Create MemoryConsumer object with defined capacity
+     *
+     * @param capacity
+     * @param chunk
+     */
+    public MemoryConsumer(int capacity, int chunk) {
+        if (capacity <= 0) {
+            throw new IllegalArgumentException("Items number should be greater than 0.");
+        }
+        if (chunk <= 0) {
+            throw new IllegalArgumentException("Chunk size should be greater than 0.");
+        }
+        this.capacity = capacity;
+        this.chunk = chunk;
+        index = 0;
+        array = new Object[this.capacity];
+    }
+
+    /**
+     * Store object into MemoryConsumer.
+     *
+     * @param o - Object to store
+     */
+    private void store(Object o) {
+        if (array == null) {
+            throw new RuntimeException("Capacity should be set before storing");
+        }
+        array[index % capacity] = o;
+        ++index;
+    }
+
+    public void consume(long memoryToFill) {
+        long allocated = 0;
+        while (allocated < memoryToFill) {
+            store(new byte[chunk]);
+            allocated += chunk;
+        }
+    }
+
+    /**
+     * Clear all stored objects.
+     */
+    public void clear() {
+        array = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/PLABUtils.java	Fri Jan 29 12:30:00 2016 +0000
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+package gc.g1.plab.lib;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import jdk.test.lib.Utils;
+
+/**
+ * Utilities for PLAB testing.
+ */
+public class PLABUtils {
+
+    /**
+     * PLAB tests default options list
+     */
+    private final static String[] GC_TUNE_OPTIONS = {
+        "-XX:+UseG1GC",
+        "-XX:G1HeapRegionSize=1m",
+        "-XX:OldSize=64m",
+        "-XX:-UseAdaptiveSizePolicy",
+        "-XX:-UseTLAB",
+        "-XX:SurvivorRatio=1"
+    };
+
+    /**
+     * GC logging options list.
+     */
+    private final static String G1_PLAB_LOGGING_OPTIONS[] = {
+        "-Xlog:gc=debug,gc+plab=debug"
+    };
+
+    /**
+     * List of options required to use WhiteBox.
+     */
+    private final static String WB_DIAGNOSTIC_OPTIONS[] = {
+        "-Xbootclasspath/a:.",
+        "-XX:+UnlockDiagnosticVMOptions",
+        "-XX:+WhiteBoxAPI"
+    };
+
+    /**
+     * Prepares options for testing.
+     *
+     * @param options - additional options for testing
+     * @return List of options
+     */
+    public static List<String> prepareOptions(List<String> options) {
+        if (options == null) {
+            throw new IllegalArgumentException("Options cannot be null");
+        }
+        List<String> executionOtions = new ArrayList<>(
+                Arrays.asList(Utils.getTestJavaOpts())
+        );
+        Collections.addAll(executionOtions, WB_DIAGNOSTIC_OPTIONS);
+        Collections.addAll(executionOtions, G1_PLAB_LOGGING_OPTIONS);
+        Collections.addAll(executionOtions, GC_TUNE_OPTIONS);
+        executionOtions.addAll(options);
+        return executionOtions;
+    }
+}