8132708: Add tests for Humongous objects allocation threshold
authorkzhaldyb
Fri, 07 Aug 2015 17:58:01 +0300
changeset 32587 397d087f7204
parent 32584 2e0377d76c5a
child 32588 f41486a59ab0
8132708: Add tests for Humongous objects allocation threshold Summary: Added the test which checks that Humongous objects allocation threshold works as expected Reviewed-by: tschatzl, dfazunen
hotspot/test/gc/g1/humongousObjects/Helpers.java
hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/Helpers.java	Fri Aug 07 17:58:01 2015 +0300
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ */
+
+package gc.g1.humongousObjects;
+
+import sun.hotspot.WhiteBox;
+
+public class Helpers {
+
+    // In case of 128 byte padding
+    private static final int MAX_PADDING_SIZE = 128;
+
+    /**
+     * Detects amount of extra bytes required to allocate a byte array.
+     * Allocating a byte[n] array takes more then just n bytes in the heap.
+     * Extra bytes are required to store object reference and the length.
+     * This amount depends on bitness and other factors.
+     *
+     * @return byte[] memory overhead
+     */
+    public static int detectByteArrayAllocationOverhead() {
+
+        WhiteBox whiteBox = WhiteBox.getWhiteBox();
+
+        int zeroLengthByteArraySize = (int) whiteBox.getObjectSize(new byte[0]);
+
+        // Since we do not know is there any padding in zeroLengthByteArraySize we cannot just take byte[0] size as overhead
+        for (int i = 1; i < MAX_PADDING_SIZE + 1; ++i) {
+            int realAllocationSize = (int) whiteBox.getObjectSize(new byte[i]);
+            if (realAllocationSize != zeroLengthByteArraySize) {
+                // It means we did not have any padding on previous step
+                return zeroLengthByteArraySize - (i - 1);
+            }
+        }
+        throw new Error("We cannot find byte[] memory overhead - should not reach here");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java	Fri Aug 07 17:58:01 2015 +0300
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ */
+
+package gc.g1.humongousObjects;
+
+import jdk.test.lib.Asserts;
+import sun.hotspot.WhiteBox;
+
+/**
+ * @test TestHumongousThreshold
+ * @summary Checks that objects larger than half a region are allocated as humongous
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @library /testlibrary /../../test/lib
+ * @modules java.management
+ * @build sun.hotspot.WhiteBox
+ *        gc.g1.humongousObjects.Helpers
+ *        gc.g1.humongousObjects.TestHumongousThreshold
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=1M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=2M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=4M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=8M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=16M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -XX:G1HeapRegionSize=32M
+ * gc.g1.humongousObjects.TestHumongousThreshold
+ *
+ */
+
+public class TestHumongousThreshold {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final int REGION_SIZE = WHITE_BOX.g1RegionSize();
+    private static final int MAX_CONTINUOUS_SIZE_CHECK = 129;
+    private static final int NON_HUMONGOUS_DIVIDER = 10;
+
+    /**
+     * The method allocates byte[] with specified size and checks that:
+     * 1. byte[] is allocated as we specified in expectedHumongous.
+     * 2. byte[] is allocated as humongous if its size is large than a half of region and non-humongous otherwise.
+     * It uses WB to obtain the size of created byte[]. Only objects larger than half of region are expected
+     * to be humongous.
+     *
+     * @param arraySize size of allocation
+     * @param expectedHumongous expected humongous/non-humongous allocation
+     * @return allocated byte array
+     */
+
+    private static byte[] allocateAndCheck(int arraySize, boolean expectedHumongous) {
+        byte[] storage = new byte[arraySize];
+        long objectSize = WHITE_BOX.getObjectSize(storage);
+        boolean shouldBeHumongous = objectSize > (REGION_SIZE / 2);
+
+        Asserts.assertEquals(expectedHumongous, shouldBeHumongous, "Despite we expected this object to be "
+                + (expectedHumongous ? "humongous" : "non-humongous") + " it appeared otherwise when we checked "
+                + "object size - likely test bug; Allocation size = " + arraySize + "; Object size = " + objectSize
+                + "; region size = " + REGION_SIZE);
+
+        Asserts.assertEquals(WHITE_BOX.g1IsHumongous(storage), shouldBeHumongous,
+                "Object should be allocated as " + (shouldBeHumongous ? "humongous"
+                        : "non-humongous") + " but it wasn't; Allocation size = " + arraySize + "; Object size = "
+                        + objectSize + "; region size = " + REGION_SIZE);
+        return storage;
+    }
+
+    public static void main(String[] args) {
+        int byteArrayMemoryOverhead = Helpers.detectByteArrayAllocationOverhead();
+
+        // Largest non-humongous byte[]
+        int maxByteArrayNonHumongousSize = (REGION_SIZE / 2) - byteArrayMemoryOverhead;
+
+        // Increment for non-humongous testing
+        int nonHumongousStep = maxByteArrayNonHumongousSize / NON_HUMONGOUS_DIVIDER;
+
+        // Maximum byte[] that takes one region
+        int maxByteArrayOneRegionSize = REGION_SIZE - byteArrayMemoryOverhead;
+
+        // Sizes in regions
+        // i,e, 1.0f means one region, 1.5f means one and half region etc
+        float[] humongousFactors = {0.8f, 1.0f, 1.2f, 1.5f, 1.7f, 2.0f, 2.5f};
+
+        // Some diagnostic output
+        System.out.format("%s started%n", TestHumongousThreshold.class.getName());
+        System.out.format("Actual G1 region size %d%n", REGION_SIZE);
+        System.out.format("byte[] memory overhead %d%n", byteArrayMemoryOverhead);
+
+        // Non-humongous allocations
+        System.out.format("Doing non-humongous allocations%n");
+
+        // Testing allocations with byte[] with length from 0 to MAX_CONTINUOUS_SIZE_CHECK
+        System.out.format("Testing allocations with byte[] with length from 0 to %d%n", MAX_CONTINUOUS_SIZE_CHECK);
+        for (int i = 0; i < MAX_CONTINUOUS_SIZE_CHECK; ++i) {
+            allocateAndCheck(i, false);
+        }
+
+        // Testing allocations with byte[] with length from 0 to nonHumongousStep * NON_HUMONGOUS_DIVIDER
+        System.out.format("Testing allocations with byte[] with length from 0 to %d with step %d%n",
+                nonHumongousStep * NON_HUMONGOUS_DIVIDER, nonHumongousStep);
+        for (int i = 0; i < NON_HUMONGOUS_DIVIDER; ++i) {
+            allocateAndCheck(i * nonHumongousStep, false);
+        }
+
+        // Testing allocations with byte[] of maximum non-humongous length
+        System.out.format("Testing allocations with byte[] of maximum non-humongous length %d%n",
+                maxByteArrayNonHumongousSize);
+        allocateAndCheck(maxByteArrayNonHumongousSize, false);
+
+        // Humongous allocations
+        System.out.format("Doing humongous allocations%n");
+        // Testing with minimum humongous object
+        System.out.format("Testing with byte[] of minimum humongous object %d%n", maxByteArrayNonHumongousSize + 1);
+        allocateAndCheck(maxByteArrayNonHumongousSize + 1, true);
+
+        // Testing allocations with byte[] with length from (maxByteArrayNonHumongousSize + 1) to
+        // (maxByteArrayNonHumongousSize + 1 + MAX_CONTINUOUS_SIZE_CHECK)
+        System.out.format("Testing allocations with byte[] with length from %d to %d%n",
+                maxByteArrayNonHumongousSize + 1, maxByteArrayNonHumongousSize + 1 + MAX_CONTINUOUS_SIZE_CHECK);
+        for (int i = 0; i < MAX_CONTINUOUS_SIZE_CHECK; ++i) {
+            allocateAndCheck(maxByteArrayNonHumongousSize + 1 + i, true);
+        }
+
+        // Checking that large (more than a half of region size) objects are humongous
+        System.out.format("Checking that large (more than a half of region size) objects are humongous%n");
+        for (float factor : humongousFactors) {
+            allocateAndCheck((int) (maxByteArrayOneRegionSize * factor), true);
+        }
+    }
+}