Path: blob/master/test/hotspot/jtreg/vmTestbase/metaspace/stressDictionary/StressDictionary.java
41153 views
/*1* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @key randomness26*27* @summary converted from VM Testbase metaspace/stressDictionary.28* VM Testbase keywords: [nonconcurrent, javac]29*30* @library /vmTestbase /test/lib31* @run main/othervm/timeout=600 metaspace.stressDictionary.StressDictionary -stressTime 3032*/3334package metaspace.stressDictionary;3536import java.util.*;37import java.lang.management.ManagementFactory;38import java.lang.reflect.InvocationTargetException;39import java.lang.reflect.Method;40import java.util.concurrent.*;41import java.util.concurrent.atomic.AtomicLong;4243import nsk.share.gc.GCTestBase;44import nsk.share.test.*;45import vm.share.InMemoryJavaCompiler;4647/**48* There is a data structure named "dictionary" in class BlockFreelist. It stores49* information about free memory blocks for further reusing. Allocation of new block goes50* from dictionary only if dictionary is fat enough. (At the moment of test creation this limit is 64K.)51* So to stress dictionary we should fill it permanently. The easiest way to fill the dictionary52* is to fail class loading. This failed action will return allocated blocks to dictionary.53*54* There are two type of threads in this test: threads, failing classloading and threads,55* loading regular classes and checking they work properly.56*/57public class StressDictionary extends GCTestBase {5859private static byte[] bytecode;6061private class FillingDictionaryWorker implements Callable<Object> {62private final Random random;63public FillingDictionaryWorker(long seed) {64this.random = new Random(seed);65}66@Override67public Object call() throws Exception {68while (stresser.continueExecution()) {69try {70byte[] badBytecode = bytecode.clone();71badBytecode[random.nextInt(badBytecode.length)] = (byte) 42;72classloader.define(badBytecode);73} catch (Throwable e) {74// We can get ClassFormatError, ClassNotFoundException or anything else here75}76}77return null;78}79}8081private class RegularWorker implements Callable<Object> {82@Override83public Object call() throws Exception {84while (stresser.continueExecution()) {85Class<?> c = classloader.define(bytecode);86testClass(c);87}88return null;89}90}9192private static String[] args;9394private static final String methodName = "myMethod";9596private static final int NUMBER_OF_CORRUPTING_THREADS = 10;9798private static final int NUMBER_OF_METHOD_CALLS = 50;99100private static final int NUMBER_OF_NOT_CORRUPTING_THREADS = 10;101102private AtomicLong classesCounter = new AtomicLong(0);103104private volatile ClassloaderUnderTest classloader = new ClassloaderUnderTest();105106private Random random;107108private ExecutionController stresser;109110public static void main(String[] args) {111StressDictionary.args = args;112Tests.runTest(new StressDictionary(), args);113}114115public void run() {116random = new Random(runParams.getSeed());117stresser = new Stresser(args);118stresser.start(1);119// Generate some bytecodes.120bytecode = generateAndCompile();121List<Callable<Object>> tasks = new LinkedList<Callable<Object>>();122for (int i = 0; i < NUMBER_OF_CORRUPTING_THREADS; i++) {123tasks.add(this.new FillingDictionaryWorker(random.nextLong()));124}125for (int i = 0; i < NUMBER_OF_NOT_CORRUPTING_THREADS; i++) {126tasks.add(this.new RegularWorker());127}128ExecutorService executorService = Executors.newCachedThreadPool();129List<Future<Object>> results = null;130try {131results = executorService.invokeAll(tasks);132} catch (InterruptedException e) {133e.printStackTrace();134}135136int act_results = results.size();137int exp_results = NUMBER_OF_CORRUPTING_THREADS +138NUMBER_OF_NOT_CORRUPTING_THREADS;139if (act_results == exp_results) {140System.err.println("INFO: There are " + act_results + " results.");141} else {142throw new RuntimeException("Wrong # of results from invokeAll(); "143+ "exp_results=" + exp_results + "; "144+ "act_results=" + act_results + ".");145}146147int cancelled_cnt = 0;148int not_done_cnt = 0;149for (int i = 0; i < act_results; i++) {150if (!results.get(i).isDone()) {151not_done_cnt++;152System.err.println("ERROR: task #" + i + " is not done.");153}154if (results.get(i).isCancelled()) {155cancelled_cnt++;156System.err.println("ERROR: task #" + i + " was canceled.");157}158}159160if (cancelled_cnt == 0) {161System.err.println("INFO: no tasks were cancelled.");162}163if (not_done_cnt == 0) {164System.err.println("INFO: all tasks are done.");165}166if (cancelled_cnt != 0 && not_done_cnt != 0) {167throw new RuntimeException(cancelled_cnt168+ " tasks were cancelled and "169+ not_done_cnt170+ " tasks are not done.");171} else if (cancelled_cnt != 0) {172throw new RuntimeException(cancelled_cnt173+ " tasks were cancelled.");174} else if (not_done_cnt != 0) {175throw new RuntimeException(not_done_cnt + " tasks are not done.");176}177}178179private byte[] generateAndCompile() {180Map<String, CharSequence> sources = new HashMap<String, CharSequence>();181String className = "MyClass" + classesCounter.incrementAndGet();182sources.put(className, generateSource(className));183return InMemoryJavaCompiler.compile(sources).values().iterator().next();184}185186private CharSequence generateSource(String className) {187return "public class " + className + " { " +188"public static String s1 = \"s1" + random.nextInt() + "\"; " +189"public String s2 = \"s2" + random.nextInt() + "\"; " +190"public String " + methodName + "() {return s1 + s2; } " +191"}";192}193194private void testClass(Class<?> clazz) {195try {196for (Method m : clazz.getMethods()) {197if (m.getName().equals(methodName)) {198for (int j = 0; j < NUMBER_OF_METHOD_CALLS; j++) {199m.invoke(clazz.newInstance());200}201}202}203} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {204log.error("Class check failed: " + e.getMessage());205e.printStackTrace();206setFailed(true);207}208209}210211}212213214