From 0185a0214f790c6611b48b986e01ef97a399b6ae Mon Sep 17 00:00:00 2001 From: aclement Date: Mon, 21 Aug 2006 15:23:58 +0000 Subject: [PATCH] some updates to ClassLoaderRepository - tested by RontimeWeaving --- .../bcel/util/ClassLoaderRepository.java | 258 ++++++++++++------ .../tests/ClassloaderRepositoryTest.java | 38 ++- lib/bcel/bcel-src.zip | Bin 879171 -> 879912 bytes lib/bcel/bcel.jar | Bin 607821 -> 610327 bytes .../org/aspectj/weaver/bcel/BcelWeaver.java | 7 +- .../org/aspectj/weaver/bcel/BcelWorld.java | 4 +- .../src/org/aspectj/weaver/ltw/LTWWorld.java | 7 +- .../bcel/ClassLoaderRepositoryTests.java | 212 +++++++++++--- 8 files changed, 396 insertions(+), 130 deletions(-) diff --git a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassLoaderRepository.java b/bcel-builder/src/org/aspectj/apache/bcel/util/ClassLoaderRepository.java index 6c30dade8..2f7325186 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/util/ClassLoaderRepository.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/util/ClassLoaderRepository.java @@ -57,11 +57,15 @@ package org.aspectj.apache.bcel.util; import java.io.IOException; import java.io.InputStream; import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.net.URL; import java.net.URLClassLoader; +import java.util.AbstractMap; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import org.aspectj.apache.bcel.classfile.ClassParser; @@ -76,32 +80,35 @@ import org.aspectj.apache.bcel.classfile.JavaClass; * * @see org.aspectj.apache.bcel.Repository * - * @version $Id: ClassLoaderRepository.java,v 1.7 2006/08/18 14:51:00 acolyer Exp $ + * @version $Id: ClassLoaderRepository.java,v 1.8 2006/08/21 15:23:58 aclement Exp $ * @author M. Dahm * @author David Dixon-Peugh */ public class ClassLoaderRepository implements Repository { private static java.lang.ClassLoader bootClassLoader = null; private java.lang.ClassLoader loader; - private WeakHashMap /**/loadedClassesLocalCache = new WeakHashMap(); - private static Map /**/loadedUrlsSharedCache = new HashMap(); - public static boolean useSharedCache = true; - private static long timeManipulatingURLs = 0L; - private static long timeSpentLoading = 0L; - private static int classesLoadedCount = 0; + // Choice of cache... + private WeakHashMap /**/localCache = new WeakHashMap(); + private static SoftHashMap /**/sharedCache = new SoftHashMap(Collections.synchronizedMap(new HashMap())); + + // For fast translation of the classname *intentionally not static* + private SoftHashMap /**/ nameMap = new SoftHashMap(new HashMap(), false); + + public static boolean useSharedCache = + System.getProperty("org.aspectj.apache.bcel.useSharedCache","true").equalsIgnoreCase("true"); + private static int cacheHitsShared = 0; private static int missSharedEvicted = 0; // Misses in shared cache access due to reference GC - private static int misses = 0; + private long timeManipulatingURLs = 0L; + private long timeSpentLoading = 0L; + private int classesLoadedCount = 0; + private int misses = 0; private int cacheHitsLocal = 0; private int missLocalEvicted = 0; // Misses in local cache access due to reference GC - static { - useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache","true").equalsIgnoreCase("true"); - } - public ClassLoaderRepository( java.lang.ClassLoader loader ) { - this.loader = (loader != null) ? loader : getBootClassLoader(); + this.loader = (loader != null) ? loader : getBootClassLoader(); } private static synchronized java.lang.ClassLoader getBootClassLoader() { @@ -110,43 +117,113 @@ public class ClassLoaderRepository implements Repository { } return bootClassLoader; } + + // Can track back to its key + public static class SoftHashMap extends AbstractMap { + private Map map; + boolean recordMiss = true; // only interested in recording miss stats sometimes + private ReferenceQueue rq = new ReferenceQueue(); + + public SoftHashMap(Map map) { this.map = map; } + public SoftHashMap() { this(new HashMap()); } + public SoftHashMap(Map map, boolean b) { this(map); this.recordMiss=b;} + + class SpecialValue extends SoftReference { + private final Object key; + SpecialValue(Object k,Object v) { + super(v,rq); + this.key = k; + } + } + + private void processQueue() { + SpecialValue sv = null; + while ((sv = (SpecialValue)rq.poll())!=null) { + map.remove(sv.key); + } + } + + public Object get(Object key) { + SpecialValue value = (SpecialValue)map.get(key); + if (value==null) return null; + if (value.get()==null) { + // it got GC'd + map.remove(value.key); + if (recordMiss) missSharedEvicted++; + return null; + } else { + return value.get(); + } + } + + public Object put(Object k, Object v) { + processQueue(); + return map.put(k, new SpecialValue(k,v)); + } + + public Set entrySet() { + return map.entrySet(); + } + + public void clear() { + processQueue(); + map.clear(); + } + + public int size() { + processQueue(); + return map.size(); + } + + public Object remove(Object k) { + processQueue(); + SpecialValue value = (SpecialValue)map.remove(k); + if (value==null) return null; + if (value.get()!=null) { + return value.get(); + } + return null; + } + } /** * Store a new JavaClass into this repository as a soft reference and return the reference */ - private Reference storeClassAsReference( JavaClass clazz ) { - Reference ref = new SoftReference(clazz); - loadedClassesLocalCache.put( clazz.getClassName(), ref); - clazz.setRepository( this ); - return ref; + private void storeClassAsReference(URL url, JavaClass clazz ) { + if (useSharedCache) { + clazz.setRepository(null); // can't risk setting repository, we'll get in a pickle! + sharedCache.put(url, clazz); + } else { + clazz.setRepository(this); + localCache.put(url, new SoftReference(clazz)); + } } - /** - * Store a reference in the shared cache - */ - private void storeReferenceShared(URL url, Reference ref) { - if (useSharedCache) loadedUrlsSharedCache.put(url, ref); - } - /** * Store a new JavaClass into this Repository. */ public void storeClass( JavaClass clazz ) { - storeClassAsReference(clazz); + storeClassAsReference(toURL(clazz.getClassName()),clazz); } /** * Remove class from repository */ public void removeClass(JavaClass clazz) { - loadedClassesLocalCache.remove(clazz.getClassName()); + if (useSharedCache) sharedCache.remove(toURL(clazz.getClassName())); + else localCache.remove(toURL(clazz.getClassName())); } /** * Find an already defined JavaClass in the local cache. */ public JavaClass findClass( String className ) { - Object o = loadedClassesLocalCache.get( className ); + if (useSharedCache) return findClassShared(toURL(className)); + else return findClassLocal(toURL(className)); + } + + private JavaClass findClassLocal( URL url ) { + Object o = localCache.get(url); if (o != null) { o = ((Reference)o).get(); if (o != null) { @@ -162,55 +239,56 @@ public class ClassLoaderRepository implements Repository { * Find an already defined JavaClass in the shared cache. */ private JavaClass findClassShared(URL url) { - if (!useSharedCache) return null; - Object o = (Reference)loadedUrlsSharedCache.get(url); - if (o != null) { - o = ((Reference)o).get(); - if (o != null) { - return (JavaClass)o; - } else { - missSharedEvicted++; - } - } - return null; + return (JavaClass)sharedCache.get(url); } + private URL toURL(String className) { + URL url = (URL)nameMap.get(className); + if (url==null) { + String classFile = className.replace('.', '/'); + url = loader.getResource( classFile + ".class" ); + nameMap.put(className, url); + } + return url; + } /** * Lookup a JavaClass object from the Class Name provided. */ public JavaClass loadClass( String className ) throws ClassNotFoundException { - String classFile = className.replace('.', '/'); - - // Check the local cache - JavaClass clazz = findClass(className); - if (clazz != null) { cacheHitsLocal++; return clazz; } + + // translate to a URL + long time = System.currentTimeMillis(); + java.net.URL url = toURL(className); + timeManipulatingURLs += (System.currentTimeMillis() - time); + if (url==null) throw new ClassNotFoundException(className + " not found."); + + JavaClass clazz = null; - try { - // Work out the URL - long time = System.currentTimeMillis(); - java.net.URL url = (useSharedCache?loader.getResource( classFile + ".class" ):null); - if (useSharedCache && url==null) throw new ClassNotFoundException(className + " not found."); - InputStream is = (useSharedCache?url.openStream():loader.getResourceAsStream( classFile + ".class" )); - timeManipulatingURLs += (System.currentTimeMillis() - time); - - // Check the shared cache + // Look in the appropriate cache + if (useSharedCache) { clazz = findClassShared(url); - if (clazz != null) { cacheHitsShared++; timeSpentLoading+=(System.currentTimeMillis() - time); return clazz; } + if (clazz != null) { cacheHitsShared++; return clazz; } + } else { + clazz = findClassLocal(url); + if (clazz != null) { cacheHitsLocal++; return clazz; } + } + + // Didn't find it in either cache + misses++; - // Didn't find it in either cache - misses++; - - if (is == null) { // TODO move this up? - throw new ClassNotFoundException(className + " not found."); - } - - ClassParser parser = new ClassParser( is, className ); + try { + // Load it + String classFile = className.replace('.', '/'); + InputStream is = (useSharedCache?url.openStream():loader.getResourceAsStream( classFile + ".class" )); + if (is == null) { + throw new ClassNotFoundException(className + " not found."); + } + ClassParser parser = new ClassParser( is, className ); clazz = parser.parse(); - // Store it in both caches - Reference ref = storeClassAsReference( clazz ); - storeReferenceShared(url,ref); + // Cache it + storeClassAsReference(url, clazz ); timeSpentLoading += (System.currentTimeMillis() - time); classesLoadedCount++; @@ -221,27 +299,42 @@ public class ClassLoaderRepository implements Repository { } -/** + /** * Produce a report on cache usage. */ - public String reportAllStatistics() { + public String report() { StringBuffer sb = new StringBuffer(); sb.append("BCEL repository report."); - if (!useSharedCache) sb.append(" (Shared cache deactivated)"); + if (useSharedCache) sb.append(" (shared cache)"); + else sb.append(" (local cache)"); sb.append(" Total time spent loading: "+timeSpentLoading+"ms."); - sb.append(" Time manipulating URLs: "+timeManipulatingURLs+"ms."); + sb.append(" Time spent manipulating URLs: "+timeManipulatingURLs+"ms."); sb.append(" Classes loaded: "+classesLoadedCount+"."); - if (useSharedCache) sb.append(" URL cache (hits/missDueToEviction): ("+cacheHitsShared+"/"+missSharedEvicted+")."); - sb.append(" Local cache (hits/missDueToEviction): ("+cacheHitsLocal+"/"+missLocalEvicted+")."); + if (useSharedCache) { + sb.append(" Shared cache size: "+sharedCache.size()); + sb.append(" Shared cache (hits/missDueToEviction): ("+cacheHitsShared+"/"+missSharedEvicted+")."); + } else { + sb.append(" Local cache size: "+localCache.size()); + sb.append(" Local cache (hits/missDueToEviction): ("+cacheHitsLocal+"/"+missLocalEvicted+")."); + } return sb.toString(); } - public int reportLocalCacheHits() { - return cacheHitsLocal; - } - - public static int reportSharedCacheHits() { - return cacheHitsShared; + /** + * Returns an array of the stats, for testing, the order is fixed: + * 0=time spent loading (static) + * 1=time spent manipulating URLs (static) + * 2=classes loaded (static) + * 3=cache hits shared (static) + * 4=misses in shared due to eviction (static) + * 5=cache hits local + * 6=misses in local due to eviction + * 7=shared cache size + */ + public long[] reportStats() { + return new long[]{timeSpentLoading,timeManipulatingURLs,classesLoadedCount, + cacheHitsShared,missSharedEvicted,cacheHitsLocal,missLocalEvicted, + sharedCache.size()}; } /** @@ -257,7 +350,6 @@ public class ClassLoaderRepository implements Repository { missLocalEvicted = 0; misses = 0; clear(); - clearShared(); } @@ -267,12 +359,10 @@ public class ClassLoaderRepository implements Repository { /** Clear all entries from the local cache */ public void clear() { - loadedClassesLocalCache.clear(); - } - - /** Clear all entries from the shared cache */ - public static void clearShared() { - loadedUrlsSharedCache.clear(); + if (useSharedCache) sharedCache.clear(); + else localCache.clear(); } + } + diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ClassloaderRepositoryTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ClassloaderRepositoryTest.java index d9e0d6d58..7202be3fa 100644 --- a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ClassloaderRepositoryTest.java +++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/ClassloaderRepositoryTest.java @@ -26,20 +26,33 @@ public class ClassloaderRepositoryTest extends TestCase { // Retrieve string 5 times from same repository, 4 hits should be from local cache public void testLocalCacheWorks() throws ClassNotFoundException { + ClassLoaderRepository.useSharedCache=false; JavaClass jc = rep1.loadClass("java.lang.String"); jc = rep1.loadClass("java.lang.String"); jc = rep1.loadClass("java.lang.String"); jc = rep1.loadClass("java.lang.String"); jc = rep1.loadClass("java.lang.String"); - assertTrue("Should have used local cache 4 times: "+rep1.reportLocalCacheHits(),rep1.reportLocalCacheHits()==4); + assertTrue("Should have used local cache 4 times: "+reportLocalCacheHits(rep1),reportLocalCacheHits(rep1)==4); + } + + // Retrieve string 5 times from same repository, 4 hits should be from local cache + public void testSharedCacheWorksOnOne() throws ClassNotFoundException { + ClassLoaderRepository.useSharedCache=true; + JavaClass jc = rep1.loadClass("java.lang.String"); + jc = rep1.loadClass("java.lang.String"); + jc = rep1.loadClass("java.lang.String"); + jc = rep1.loadClass("java.lang.String"); + jc = rep1.loadClass("java.lang.String"); + assertTrue("Should have used local cache 4 times: "+reportSharedCacheHits(rep1),reportSharedCacheHits(rep1)==4); } // Retrieve String through one repository then load again through another, should be shared cache hit public void testSharedCacheWorks() throws ClassNotFoundException { + ClassLoaderRepository.useSharedCache=true; JavaClass jc = rep1.loadClass("java.lang.String"); jc = rep2.loadClass("java.lang.String"); - assertTrue("Should have retrieved String from shared cache: "+ClassLoaderRepository.reportSharedCacheHits(), - ClassLoaderRepository.reportSharedCacheHits()==1); + assertTrue("Should have retrieved String from shared cache: "+reportSharedCacheHits(rep1), + reportSharedCacheHits(rep1)==1); } // Shared cache OFF, shouldn't get a shared cache hit @@ -49,8 +62,8 @@ public class ClassloaderRepositoryTest extends TestCase { JavaClass jc = rep1.loadClass("java.lang.String"); jc = rep2.loadClass("java.lang.String"); assertTrue("Should not have retrieved String from shared cache: "+ - ClassLoaderRepository.reportSharedCacheHits(), - ClassLoaderRepository.reportSharedCacheHits()==0); + reportSharedCacheHits(rep1), + reportSharedCacheHits(rep1)==0); } finally { ClassLoaderRepository.useSharedCache=true; } @@ -58,10 +71,19 @@ public class ClassloaderRepositoryTest extends TestCase { public void tearDown() throws Exception { super.tearDown(); - System.err.println("Rep1: "+rep1.reportAllStatistics()); - System.err.println("Rep2: "+rep2.reportAllStatistics()); + System.err.println("Rep1: "+rep1.reportStats()); + System.err.println("Rep2: "+rep2.reportStats()); rep1.reset(); rep2.reset(); } - + + private long reportLocalCacheHits(ClassLoaderRepository rep) { + return rep.reportStats()[5]; + } + + private long reportSharedCacheHits(ClassLoaderRepository rep) { + return rep.reportStats()[3]; + } + } + diff --git a/lib/bcel/bcel-src.zip b/lib/bcel/bcel-src.zip index 1d7d84805e76678cfd398a566b81678847a70951..c1115a8864eb84e4666901e413f01aaebb771daa 100644 GIT binary patch delta 6413 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 delta 5699 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 diff --git a/lib/bcel/bcel.jar b/lib/bcel/bcel.jar index 493ffe6a2a13e8251ca6094502c99d6c3f329d19..7df53e5401d10976b7234e7c576a2368e044eabb 100644 GIT binary patch delta 18433 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 BsbByA delta 15537 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 diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 6a51fd484..38a56ef5b 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -187,7 +187,12 @@ public class BcelWeaver implements IWeaver { WeaverStateInfo wsi = type.getWeaverState(); if (wsi != null && wsi.isReweavable()) { BcelObjectType classType = getClassType(type.getName()); - classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); + JavaClass wovenJavaClass = classType.getJavaClass(); + JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(), + wsi.getUnwovenClassFileData(wovenJavaClass.getBytes())); + world.storeClass(unwovenJavaClass); + classType.setJavaClass(unwovenJavaClass); +// classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); } //TODO AV - happens to reach that a lot of time: for each type flagged reweavable X for each aspect in the weaverstate diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java index b0d5ce96a..2e13c5d54 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java @@ -81,7 +81,7 @@ import org.aspectj.weaver.patterns.SimpleScope; public class BcelWorld extends World implements Repository { private ClassPathManager classPath; - private Repository delegate; + protected Repository delegate; //private ClassPathManager aspectPath = null; @@ -644,7 +644,7 @@ public class BcelWorld extends World implements Repository { } public void storeClass(JavaClass clazz) { - throw new RuntimeException("Not implemented"); + // doesn't need to do anything } public void removeClass(JavaClass clazz) { diff --git a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java b/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java index ff6b7b727..a89dc6f77 100644 --- a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java +++ b/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.bridge.IMessageHandler; import org.aspectj.util.LangUtil; import org.aspectj.weaver.ICrossReferenceHandler; @@ -48,7 +49,6 @@ import org.aspectj.weaver.reflect.ReflectionWorld; */ public class LTWWorld extends BcelWorld implements IReflectionWorld { - private AnnotationFinder annotationFinder; private ClassLoader loader; // weavingContext? private IWeavingContext weavingContext; @@ -244,5 +244,10 @@ public class LTWWorld extends BcelWorld implements IReflectionWorld { ((ReferenceType)ret).setDelegate(rtd); return ret; } + + public void storeClass(JavaClass clazz) { + delegate.storeClass(clazz); + } + } diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/ClassLoaderRepositoryTests.java b/weaver/testsrc/org/aspectj/weaver/bcel/ClassLoaderRepositoryTests.java index c60f43d57..a6f9b0000 100644 --- a/weaver/testsrc/org/aspectj/weaver/bcel/ClassLoaderRepositoryTests.java +++ b/weaver/testsrc/org/aspectj/weaver/bcel/ClassLoaderRepositoryTests.java @@ -14,10 +14,12 @@ package org.aspectj.weaver.bcel; import java.io.File; -import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -27,43 +29,185 @@ import org.aspectj.apache.bcel.util.ClassLoaderRepository; /** NOT YET INCLUDED IN A FULL TEST RUN - WORK IN PROGRESS CHECKING CLASSLOADERREPOSITORY OPTIMIZATIONS */ public class ClassLoaderRepositoryTests extends TestCase { - - public void testRepositorySharing() throws Exception { - ClassLoaderRepository.useSharedCache=false; - File f = new File("../lib/aspectj/lib/aspectjtools.jar"); + private File f; + private ZipFile zf; + private Enumeration entries; + private Map map; + + public void setUp() throws Exception { + f = new File("../lib/aspectj/lib/aspectjtools.jar"); + assertTrue("Couldn't find aspectjtools to test. Tried: "+f.getAbsolutePath(),f.exists()); + zf = new ZipFile(f); + entries = zf.entries(); +// ClassLoaderRepository.sharedCacheCompactFrequency = 16384; + map = getSharedMap(); + } + + public void tearDown() { + new ClassLoaderRepository(null).reset(); + } + + private ClassLoaderRepository setupRepository() throws Exception { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - ClassLoader cl1 = new URLClassLoader(new URL[]{f.toURL()},cl); - ClassLoader cl2 = new URLClassLoader(new URL[]{f.toURL()},cl); - ClassLoaderRepository rep1 = new ClassLoaderRepository(cl1); - ClassLoaderRepository rep2 = new ClassLoaderRepository(cl2); - try { - assertTrue("Couldnt find aspectjtools to test. Tried: "+f.getAbsolutePath(),f.exists()); - ZipFile zf = new ZipFile(f); - int i = 0; - Enumeration entries = zf.entries(); - while (entries.hasMoreElements()) { - ZipEntry zfe = (ZipEntry)entries.nextElement(); - String classfileName = zfe.getName(); - if (classfileName.endsWith(".class")) { - String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.'); - - // twice by each - rep1.loadClass(clazzname); - rep1.loadClass(clazzname); - rep2.loadClass(clazzname); - rep2.loadClass(clazzname); - i++; - } + ClassLoader res = new URLClassLoader(new URL[]{f.toURL()},cl); + ClassLoaderRepository rep = new ClassLoaderRepository(res); + return rep; + } + + private void compareTwoRepositories() throws Exception { + ClassLoaderRepository rep1 = setupRepository(); + ClassLoaderRepository rep2 = setupRepository(); + int i = 0; + while (entries.hasMoreElements()) { + ZipEntry zfe = (ZipEntry)entries.nextElement(); + String classfileName = zfe.getName(); + if (classfileName.endsWith(".class")) { + String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.'); + + // twice by each + rep1.loadClass(clazzname); + rep1.loadClass(clazzname); + rep2.loadClass(clazzname); + rep2.loadClass(clazzname); + i++; + } + } + System.err.println("Successfully compared "+i+" entries!!"); + System.err.println(rep1.report()); + System.err.println(rep2.report()); + } + + private void loadOnce() throws Exception { + ClassLoaderRepository rep = setupRepository(); + while (entries.hasMoreElements()) { + ZipEntry zfe = (ZipEntry) entries.nextElement(); + String classfileName = zfe.getName(); + if (classfileName.endsWith(".class")) { + String clazzname = classfileName.substring(0, + classfileName.length() - 6).replace('/', '.'); + + rep.loadClass(clazzname); + } + } + } + + public void testMultiThreaded() throws Throwable { + ClassLoaderRepository.useSharedCache=true; +// ClassLoaderRepository.sharedCacheCompactFrequency = 200; + //loadOnce(); + TestThread threads[] = new TestThread[6]; + for (int i=0; i