# HG changeset patch # User iignatyev # Date 1418332810 -10800 # Fri Dec 12 00:20:10 2014 +0300 # Node ID 70cb33b92afb3abbfad32e5d85547a523682a4f1 # Parent 810e47461d4f725ba645ad88c87c86a4edd6e39e 8059551: JEP-JDK-8043304: Test task: stress tests Reviewed-by: Contributed-by: pavel.chistyakov@oracle.com diff --git a/test/compiler/codecache/stress/CodeCacheStressRunner.java b/test/compiler/codecache/stress/CodeCacheStressRunner.java new file mode 100644 --- /dev/null +++ b/test/compiler/codecache/stress/CodeCacheStressRunner.java @@ -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()); + return true; + } + +} diff --git a/test/compiler/codecache/stress/Helper.java b/test/compiler/codecache/stress/Helper.java new file mode 100644 --- /dev/null +++ b/test/compiler/codecache/stress/Helper.java @@ -0,0 +1,135 @@ +/* + * 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 abstract class Helper { + public static final WhiteBox WB = WhiteBox.getWhiteBox(); + public static final Random R = Utils.getRandomInstance(); + + private static final long THRESHOLD = WB.getIntxVMFlag("CompileThreshold"); + private static byte[] CLASS_DATA; + static { + try { + CLASS_DATA = loadClassData(TestCaseImpl.class.getName()); + } catch (IOException e) { + throw new Error("TESTBUG: cannot load class byte code", e); + } + } + + 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 callable) { + 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, TestCaseImpl.EXPECTED_VALUE, + "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() { + String className = TestCaseImpl.class.getName(); + try { + Class clazz = ByteCodeLoader.load(className, CLASS_DATA); + return (TestCase) clazz.newInstance(); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG: error while creating " + className + + " instance from reloaded class", e); + } + } + + Callable getCallable(); + int method(); + } + + public static class TestCaseImpl implements TestCase { + private static final int RETURN_VALUE = 42; + private static final int RECURSION_DEPTH = 10; + public static final int EXPECTED_VALUE = RETURN_VALUE * RECURSION_DEPTH; + private volatile int i; + public TestCaseImpl() { + } + + @Override + public Callable getCallable() { + return () -> { + i = 0; + return method(); + }; + } + + @Override + public int method() { + ++i; + int result = RETURN_VALUE; + if (i < RECURSION_DEPTH) { + return result + method(); + } + return result; + } + + } + +} diff --git a/test/compiler/codecache/stress/OverloadCompileQueueTest.java b/test/compiler/codecache/stress/OverloadCompileQueueTest.java new file mode 100644 --- /dev/null +++ b/test/compiler/codecache/stress/OverloadCompileQueueTest.java @@ -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 /testlibrary/whitebox + * @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.WB.getBooleanVMFlag("TieredCompilation"); + private static final int TIERED_STOP_AT_LEVEL + = Helper.WB.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.WB.enqueueMethodForCompilation(mEnqueue, compLevel); + } + } + + private void lockUnlock() { + try { + Helper.WB.lockCompilation(); + Thread.sleep(Helper.R.nextInt(MAX_SLEEP)); + } catch (InterruptedException e) { + throw new Error("TESTBUG: lockUnlocker thread was unexpectedly interrupted", e); + } finally { + Helper.WB.unlockCompilation(); + } + } + +} diff --git a/test/compiler/codecache/stress/RandomAllocationTest.java b/test/compiler/codecache/stress/RandomAllocationTest.java new file mode 100644 --- /dev/null +++ b/test/compiler/codecache/stress/RandomAllocationTest.java @@ -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 /testlibrary/whitebox + * @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.WB.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 blobs = new ArrayList<>(); + @Override + public void run() { + boolean allocate = blobs.isEmpty() || Helper.R.nextBoolean(); + if (allocate) { + int type = Helper.R.nextInt(BLOB_TYPES.length); + long addr = Helper.WB.allocateCodeBlob( + Helper.R.nextInt(MAX_BLOB_SIZE), BLOB_TYPES[type].id); + if (addr != 0) { + blobs.add(addr); + } + } else { + int index = Helper.R.nextInt(blobs.size()); + Helper.WB.freeCodeBlob(blobs.remove(index)); + } + } + +} diff --git a/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java b/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java new file mode 100644 --- /dev/null +++ b/test/compiler/codecache/stress/UnexpectedDeoptimizationTest.java @@ -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 /testlibrary/whitebox + * @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.WB.deoptimizeFrames(Helper.R.nextBoolean()); + } + +}