blob: a48b106a2b6f022ecfe95666bc7c2d00846744f5 [file] [log] [blame]
/*
* 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 <code>ClassLoadingController</code> 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<String, String[]> classesTable = new Hashtable<String, String[]>();
private ClassUnloader[] unloaders;
private Stresser stresser;
/**
* Constructs a new <code>ClassLoadingController</code> with defined
* arguments.
*
* @param log <code>Log</code> 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
}