8059551: JEP-JDK-8043304: Test task: stress tests
authorpchistyakov
Mon, 12 Jan 2015 18:58:49 +0300
changeset 28501 c9c359a66a15
parent 28500 8cab8bd43b39
child 28502 16b69673f35c
8059551: JEP-JDK-8043304: Test task: stress tests Reviewed-by: drchase, kvn, iignatyev
hotspot/src/share/vm/compiler/compileBroker.cpp
hotspot/test/compiler/codecache/stress/CodeCacheStressRunner.java
hotspot/test/compiler/codecache/stress/Helper.java
hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java
hotspot/test/compiler/codecache/stress/RandomAllocationTest.java
hotspot/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp	Wed Jan 14 09:54:08 2015 +0300
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Mon Jan 12 18:58:49 2015 +0300
@@ -252,7 +252,7 @@
   } else {
     task = new CompileTask();
     DEBUG_ONLY(_num_allocated_tasks++;)
-    assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?");
+    assert (WhiteBoxAPI || _num_allocated_tasks < 10000, "Leaking compilation tasks?");
     task->set_next(NULL);
     task->set_is_free(true);
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/CodeCacheStressRunner.java	Mon Jan 12 18:58:49 2015 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.java.testlibrary.TimeLimitedRunner;
+import com.oracle.java.testlibrary.Utils;
+
+public class CodeCacheStressRunner {
+    private final Runnable action;
+    public CodeCacheStressRunner(Runnable action) {
+        this.action = action;
+    }
+
+    protected final void runTest() {
+        Helper.startInfiniteLoopThread(action);
+        try {
+            // adjust timeout and substract vm init and exit time
+            long timeout = Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT);
+            timeout *= 0.9;
+            new TimeLimitedRunner(timeout, 2.0d, this::test).call();
+        } catch (Exception e) {
+            throw new Error("Exception occurred during test execution", e);
+        }
+    }
+
+    private boolean test() {
+        Helper.TestCase obj = Helper.TestCase.get();
+        Helper.callMethod(obj.getCallable(), obj.expectedValue());
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/Helper.java	Mon Jan 12 18:58:49 2015 +0300
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014, 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.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.Random;
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.ByteCodeLoader;
+import com.oracle.java.testlibrary.InfiniteLoop;
+import com.oracle.java.testlibrary.Utils;
+import sun.hotspot.WhiteBox;
+
+public final class Helper {
+    public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    public static final Random RNG = Utils.getRandomInstance();
+
+    private static final long THRESHOLD = WHITE_BOX.getIntxVMFlag("CompileThreshold");
+    private static final String TEST_CASE_IMPL_CLASS_NAME = "Helper$TestCaseImpl";
+    private static byte[] CLASS_DATA;
+    static {
+        try {
+            CLASS_DATA = loadClassData(TEST_CASE_IMPL_CLASS_NAME);
+        } catch (IOException e) {
+            throw new Error("TESTBUG: cannot load class byte code", e);
+        }
+    }
+
+    private Helper() {
+    }
+
+    public static void startInfiniteLoopThread(Runnable action) {
+        startInfiniteLoopThread(action, 0L);
+    }
+
+    public static void startInfiniteLoopThread(Runnable action, long millis) {
+        Thread t = new Thread(new InfiniteLoop(action, millis));
+        t.setDaemon(true);
+        t.start();
+    }
+
+    public static int callMethod(Callable<Integer> callable, int expected) {
+        int result = 0;
+        for (int i = 0; i < THRESHOLD; ++i) {
+            try {
+                result = callable.call();
+            } catch (Exception e) {
+                throw new AssertionError(
+                        "Exception occurred during test method execution", e);
+            }
+            Asserts.assertEQ(result, expected, "Method returns unexpected value");
+        }
+        return result;
+    }
+
+    private static byte[] loadClassData(String name) throws IOException {
+        try (BufferedInputStream in = new BufferedInputStream(
+                ClassLoader.getSystemResourceAsStream(name.replace(".", "/")
+                        + ".class"))) {
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int read;
+            while ((read = in.read(buffer)) != -1) {
+                result.write(buffer, 0, read);
+            }
+            return result.toByteArray();
+        }
+    }
+
+    public interface TestCase {
+
+        public static TestCase get() {
+            try {
+                Class clazz = ByteCodeLoader.load(
+                        TEST_CASE_IMPL_CLASS_NAME, CLASS_DATA);
+                return (TestCase) clazz.newInstance();
+            } catch (ReflectiveOperationException e) {
+                throw new Error(String.format(
+                        "TESTBUG: error while creating %s instance from reloaded class",
+                        TEST_CASE_IMPL_CLASS_NAME), e);
+            }
+        }
+
+        Callable<Integer> getCallable();
+        int method();
+        int expectedValue();
+    }
+
+    public static class TestCaseImpl implements TestCase {
+        private static final int RETURN_VALUE = 42;
+        private static final int RECURSION_DEPTH = 10;
+        private volatile int i;
+
+        @Override
+        public Callable<Integer> getCallable() {
+            return () -> {
+                i = 0;
+                return method();
+            };
+        }
+
+        @Override
+        public int method() {
+            ++i;
+            int result = RETURN_VALUE;
+            if (i < RECURSION_DEPTH) {
+                return result + method();
+            }
+            return result;
+        }
+
+        @Override
+        public int expectedValue() {
+            return RETURN_VALUE * RECURSION_DEPTH;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/OverloadCompileQueueTest.java	Mon Jan 12 18:58:49 2015 +0300
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014, 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.lang.reflect.Method;
+import java.util.stream.IntStream;
+
+import com.oracle.java.testlibrary.Platform;
+
+/*
+ * @test OverloadCompileQueueTest
+ * @library /testlibrary /../../test/lib
+ * @build OverloadCompileQueueTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache OverloadCompileQueueTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache OverloadCompileQueueTest
+ * @summary stressing code cache by overloading compile queues
+ */
+public class OverloadCompileQueueTest implements Runnable {
+    private static final int MAX_SLEEP = 10000;
+    private static final String METHOD_TO_ENQUEUE = "method";
+    private static final int LEVEL_SIMPLE = 1;
+    private static final int LEVEL_FULL_OPTIMIZATION = 4;
+    private static final boolean INTERPRETED
+            = System.getProperty("java.vm.info").startsWith("interpreted ");
+    private static final boolean TIERED_COMPILATION
+            = Helper.WHITE_BOX.getBooleanVMFlag("TieredCompilation");
+    private static final int TIERED_STOP_AT_LEVEL
+            = Helper.WHITE_BOX.getIntxVMFlag("TieredStopAtLevel").intValue();
+    private static final int[] AVAILABLE_LEVELS;
+    static {
+        if (TIERED_COMPILATION) {
+            AVAILABLE_LEVELS = IntStream
+                    .rangeClosed(LEVEL_SIMPLE, TIERED_STOP_AT_LEVEL)
+                    .toArray();
+        } else if (Platform.isServer()) {
+            AVAILABLE_LEVELS = new int[] { LEVEL_FULL_OPTIMIZATION };
+        } else if (Platform.isClient() || Platform.isMinimal()) {
+            AVAILABLE_LEVELS = new int[] { LEVEL_SIMPLE };
+        } else {
+            throw new Error(String.format(
+                    "TESTBUG: unknown VM: %s", System.getProperty("java.vm.name")));
+        }
+    }
+
+    public static void main(String[] args) {
+        if (INTERPRETED) {
+            System.err.println("Test isn't applicable for interpreter. Skip test.");
+            return;
+        }
+        new CodeCacheStressRunner(new OverloadCompileQueueTest()).runTest();
+    }
+
+    public OverloadCompileQueueTest() {
+        Helper.startInfiniteLoopThread(this::lockUnlock);
+    }
+
+    @Override
+    public void run() {
+        Helper.TestCase obj = Helper.TestCase.get();
+        Class clazz = obj.getClass();
+        Method mEnqueue;
+        try {
+            mEnqueue = clazz.getMethod(METHOD_TO_ENQUEUE);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new Error(String.format(
+                    "TESTBUG: cannot get method '%s' of class %s",
+                    METHOD_TO_ENQUEUE, clazz.getName()), e);
+        }
+        for (int compLevel : AVAILABLE_LEVELS) {
+            Helper.WHITE_BOX.enqueueMethodForCompilation(mEnqueue, compLevel);
+        }
+    }
+
+    private void lockUnlock() {
+        try {
+            Helper.WHITE_BOX.lockCompilation();
+            Thread.sleep(Helper.RNG.nextInt(MAX_SLEEP));
+        } catch (InterruptedException e) {
+            throw new Error("TESTBUG: lockUnlocker thread was unexpectedly interrupted", e);
+        } finally {
+            Helper.WHITE_BOX.unlockCompilation();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/RandomAllocationTest.java	Mon Jan 12 18:58:49 2015 +0300
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 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.ArrayList;
+
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test RandomAllocationTest
+ * @library /testlibrary /../../test/lib
+ * @build RandomAllocationTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache RandomAllocationTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache RandomAllocationTest
+ * @summary stressing code cache by allocating randomly sized "dummy" code blobs
+ */
+public class RandomAllocationTest implements Runnable {
+    private static final long CODE_CACHE_SIZE
+            = Helper.WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize");
+    private static final int MAX_BLOB_SIZE = (int) (CODE_CACHE_SIZE >> 7);
+    private static final BlobType[] BLOB_TYPES
+            = BlobType.getAvailable().toArray(new BlobType[0]);
+
+    public static void main(String[] args) {
+        new CodeCacheStressRunner(new RandomAllocationTest()).runTest();
+    }
+
+    private final ArrayList<Long> blobs = new ArrayList<>();
+    @Override
+    public void run() {
+        boolean allocate = blobs.isEmpty() || Helper.RNG.nextBoolean();
+        if (allocate) {
+            int type = Helper.RNG.nextInt(BLOB_TYPES.length);
+            long addr = Helper.WHITE_BOX.allocateCodeBlob(
+                    Helper.RNG.nextInt(MAX_BLOB_SIZE), BLOB_TYPES[type].id);
+            if (addr != 0) {
+                blobs.add(addr);
+            }
+        } else {
+            int index = Helper.RNG.nextInt(blobs.size());
+            Helper.WHITE_BOX.freeCodeBlob(blobs.remove(index));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java	Mon Jan 12 18:58:49 2015 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, 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 UnexpectedDeoptimizationTest
+ * @library /testlibrary /../../test/lib
+ * @build UnexpectedDeoptimizationTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache -XX:-DeoptimizeRandom
+ *                   UnexpectedDeoptimizationTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:CompileCommand=dontinline,Helper$TestCase::method
+ *                   -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom
+ *                   UnexpectedDeoptimizationTest
+ * @summary stressing code cache by forcing unexpected deoptimizations
+ */
+public class UnexpectedDeoptimizationTest implements Runnable {
+
+    public static void main(String[] args) {
+        new CodeCacheStressRunner(new UnexpectedDeoptimizationTest()).runTest();
+    }
+
+    @Override
+    public void run() {
+        Helper.WHITE_BOX.deoptimizeFrames(Helper.RNG.nextBoolean());
+    }
+
+}