diff -r 746229cc1ab0 -r cc29d7717e3a test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ClassLoadingController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/share/ClassLoadingController.java Wed May 02 16:43:56 2018 -0700 @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2003, 2018, 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 nsk.monitoring.share; + +import java.util.*; +import nsk.share.log.Log; +import nsk.share.ClassUnloader; +import nsk.share.CustomClassLoader; +import nsk.share.test.Stresser; + +/** + * The ClassLoadingController class allows to operate class + * loading/unloading process. + */ +public class ClassLoadingController extends StateControllerBase { + // Path and name of the classes to load + private static final String CLASSNAME_PATTERN = "nsk.monitoring.share.newclass.LoadableClass"; + + private int loadedClassCount = 100; + private int loaderCount = 1; + private boolean singleClass = true; + private String classDir; + private Hashtable classesTable = new Hashtable(); + private ClassUnloader[] unloaders; + + private Stresser stresser; + + /** + * Constructs a new ClassLoadingController with defined + * arguments. + * + * @param log Log to print log info to. + * @param loadedClassCount number of classes to load. + * @param loaderCount number of loaders to use. + * @param singleClass if class loaders are instances of the same class. + * @param classDir directory to load classes from. + */ + public ClassLoadingController( + Log log, + int loadedClassCount, + int loaderCount, + boolean singleClass, + String classDir, + Stresser stresser + ) { + super(log); + setLoadedClassCount(loadedClassCount); + setLoaderCount(loaderCount); + setClassDir(classDir); + singleClassLoaderClass(singleClass); + dump(); + preloadAllClasses(); + setStresser(stresser); + } + + private void setStresser(Stresser stresser) { + this.stresser = stresser; + } + + public ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser) { + this( + log, + argHandler.getLoadableClassesCount(), +// argHandler.getLoadersCount(), + (int)stresser.getMaxIterations(), + argHandler.singleClassloaderClass(), + argHandler.getRawArgument(0), + stresser + ); + } + + public void dump() { + log.debug("classes to be loaded:\t" + loadedClassCount); + log.debug("classloader instances:\t" + loaderCount); + if (singleClass) + log.debug("classloader class:\tsingle"); + else + log.debug("classloader class:\ttwo"); + log.debug("Class dir" + classDir); + + } + + private void setLoadedClassCount(int loadedClassCount) { + this.loadedClassCount = loadedClassCount; + } + + // Set loaderCount value + private void setLoaderCount(int loaderCount) { + this.loaderCount = loaderCount; + } + + // Set singleClass value + private void singleClassLoaderClass(boolean singleClass) { + this.singleClass = singleClass; + } + + // Set classDir value + private void setClassDir(String classDir) { + this.classDir = classDir; + } + + // Load classes + private void preloadAllClasses() { + log.debug("preloading all classes..."); + if (singleClass) + createUnloaders(1); + else + createUnloaders(2); + + for (int i = 0; i < unloaders.length; i++) { + loadClasses(unloaders[i], 1, false); + unloaders[i].unloadClass(); + } + } + + // Load classes + private boolean loadClasses(ClassUnloader unloader, int classCount, boolean doKeep) { + String newClassName; + String[] classNames = new String[classCount + 1]; + classNames[0] = unloader.getClassLoader().getClass().getName() + + "@" + + Integer.toHexString( + unloader.getClassLoader().hashCode() + ); + + + for (int i = 1; i <= classCount; i++) { + newClassName = CLASSNAME_PATTERN + int2Str(i); + classNames[i] = newClassName; + try { + unloader.loadClass(newClassName); + } catch (ClassNotFoundException e) { + log.error(e.toString()); + e.printStackTrace(); + return false; + } + } + if (doKeep) + classesTable.put(String.valueOf(unloader.hashCode()), classNames); + return true; + } // loadClasses() + + /** + * Loads all classes. + * + * @see ClassLoadingController#ClassLoadingController + */ + public int loadClasses() { + CustomClassLoader loader; + boolean res = true; + String loaderName; + + createUnloaders(loaderCount); + + int count = 0; + for (int i = 0; i < unloaders.length; i++) { + loaderName = unloaders[i].getClassLoader().getClass().getName() + + "@" + + Integer.toHexString( + unloaders[i].getClassLoader().hashCode() + ); + if (loadClasses(unloaders[i], loadedClassCount, true)) { + String[] values = (String[]) + classesTable.get(String.valueOf(unloaders[i].hashCode())); + int length = values.length - 1; + log.debug(loaderName + "(" + i + ")>>> " + length + + " classes have been loaded"); + count += length; + } + } + log.info("Total: loading is performed " + count + " times"); + + return count; + } + + // Unload classes + public int unloadClasses() { + String loaderName; + int count = 0; + long timeLeft = 0; + + for (int i = 0; i < loaderCount && (timeLeft = stresser.getTimeLeft()/1000) > 0; i++) { + loaderName = unloaders[i].getClassLoader().getClass().getName() + + "@" + + Integer.toHexString( + unloaders[i].getClassLoader().hashCode() + ); + String hashCode = String.valueOf(unloaders[i].hashCode()); + String[] values = (String[]) classesTable.get(hashCode); + + if (unloaders[i].unloadClass()) { + int length = values.length - 1; + count += length; + log.debug(loaderName + "(" + i + ")>>> " + length + + " classes have been unloaded (time left: "+timeLeft+" s)"); + classesTable.remove(hashCode); + } else { + log.debug(loaderName + "(" + i + ")>>> " + + "classes couldn't be unloaded (time left: "+timeLeft+" s)"); + } + } + + log.info("Total: unloading is performed " + count + " times"); + + return count; + } + + private void createUnloaders(int count) { + CustomClassLoader loader; + unloaders = new ClassUnloader[count]; + + for (int i = 0; i < count; i++) { + unloaders[i] = new ClassUnloader(); + if (singleClass) { + loader = unloaders[i].createClassLoader(); + } else { + if (i%2 == 0) + loader = new ClassLoaderA(); + else + loader = new ClassLoaderB(); + unloaders[i].setClassLoader(loader); + } + loader.setClassPath(classDir); + } // for + } + + /** + * Brings out VM into defined state. The method loads all classes via + * {@link ClassLoadingController#loadClasses}. + * + * @see ClassLoadingController#loadClasses + */ + public void run() { + loadClasses(); + } + + /** + * Tries to reclaim VM into initial state. The method tries to load all + * classes via {@link ClassLoadingController#unloadClasses}. + * + * @see ClassLoadingController#unloadClasses + */ + public void reset() { + unloadClasses(); + } + + // The class extends CustomClassLoader with specific implementation of + // toString() method + class ClassLoaderA extends CustomClassLoader { + public ClassLoaderA() { + super(); + } + + public String toString() { + return "ClassLoaderA"; + } + } // ClassLoaderA + + // The class extends CustomClassLoader with specific implementation of + // toString() method + class ClassLoaderB extends CustomClassLoader { + public ClassLoaderB() { + super(); + } + + public String toString() { + return "ClassLoaderB"; + } + } // ClassLoaderB +}