You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ho...@apache.org on 2006/05/24 12:23:46 UTC

svn commit: r409112 - in /geronimo/branches/1.1: assemblies/j2ee-jetty-server/ assemblies/j2ee-tomcat-server/ assemblies/minimal-jetty-server/ assemblies/minimal-tomcat-server/ assemblies/zzzzj2ee-installer/ configs/client-system/ configs/j2ee-system/ ...

Author: hogstrom
Date: Wed May 24 03:23:45 2006
New Revision: 409112

URL: http://svn.apache.org/viewvc?rev=409112&view=rev
Log:
BUG: This fix addresses an issue in RMIClassLoaderSpiImpl where a codebase is optionally passed for certain copy operations.  When profiling DayTrader our performance for PingServlet2Session was extremely poor relative to JBoss and WebSphere.  Our throughput on a 2-way 3.0 Ghz system was roughly 500 tps compared to 5400 and 4500 repsepctively.  (It appears that JBoss is not honoring pass-by-value semantics properly; thus the significantly higher throughput).  

I chased the degraded performance to RMIClassLoaderSPIImpl where we were spending nearly 70% of the system's time in normalizeCodebase for less than 1/8 of the requests being processed.  Here is some profiling data to show the degredation:

    =======   =====   =====   =====      =======      ======= ==========
     Parent    4610    0.71   70.54   1157864861 115775210210   28) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.loadClass(Ljava/lang/

       Self    4610    0.71   70.54   1157864861 115775210210 [29]  J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeCodebase(Lja

      Child   50550    0.34   61.97    555213244 101708338940   31) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.updateCodebase(Ljava/
      Child    4584    0.04    4.40     65515147   7224581400   30) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeURL(Ljava/ne
      Child   55136    0.46    2.71    758942891   4446465936   42) J:java/net/URL.<init>(Ljava/net/URL;Ljava/lang/String;Ljava/net/URLStreamHan      
      Child  234350    0.39    0.59    631910516    970672051   36) J:java/lang/String.indexOf(I)I

Note that of the 4610 requests were a subset of a total of 32000 transactions.  


Here is the  normalizeURL information:

    =======   =====   =====   =====      =======      ======= ==========
     Parent   50524    0.38   59.74    629510012  98041028811   30) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeURL(Ljava/ne

       Self   50524    0.38   59.74    629510012  98041028811 [32]  J:java/io/File.toURI()Ljava/net/URI;

      Child   50524    0.23   55.43    376226211  90981520312   33) J:java/net/URI.<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;
      Child   50524    0.12    3.14    189098774   5152641459   54) J:java/io/File.isDirectory()Z
      Child   50524    0.17    0.39    274629658    646476978  192) J:java/io/File.slashify(Ljava/lang/String;Z)Ljava/lang/String;
      Child   50524    0.14    0.29    224357024    473009995  210) J:java/io/File.<init>(Ljava/lang/String;)V
      Child   50524    0.05    0.05     88736649     88736649  386) J:java/lang/String.startsWith(Ljava/lang/String;I)Z
      Child   50524    0.04    0.04     69133406     69133406  408) J:java/io/Win32FileSystem.resolve(Ljava/io/File;)Ljava/lang/String;

I added a new method to inercept and cache calls to normalizeCodebase where I simply return a cached result.  This has resulted in a 6x+ performance improvement where we have gone from 500 tps to 3200+.   


Modified:
    geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml
    geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml
    geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml
    geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml
    geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml
    geronimo/branches/1.1/configs/client-system/project.properties
    geronimo/branches/1.1/configs/client-system/project.xml
    geronimo/branches/1.1/configs/j2ee-system/project.properties
    geronimo/branches/1.1/configs/j2ee-system/project.xml
    geronimo/branches/1.1/configs/rmi-naming/project.xml
    geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java

Modified: geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml (original)
+++ geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml Wed May 24 03:23:45 2006
@@ -760,6 +760,9 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.assemble>library</geronimo.assemble>
+            </properties>
         </dependency>
 
         <dependency>

Modified: geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml (original)
+++ geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml Wed May 24 03:23:45 2006
@@ -761,6 +761,9 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.assemble>library</geronimo.assemble>
+            </properties>
         </dependency>
 
         <dependency>

Modified: geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml (original)
+++ geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml Wed May 24 03:23:45 2006
@@ -446,6 +446,9 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.assemble>library</geronimo.assemble>
+            </properties>
         </dependency>
 
 <!-- geronimo jars -->

Modified: geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml (original)
+++ geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml Wed May 24 03:23:45 2006
@@ -446,6 +446,9 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.assemble>library</geronimo.assemble>
+            </properties>
         </dependency>
 
 <!-- geronimo jars -->

Modified: geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml (original)
+++ geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml Wed May 24 03:23:45 2006
@@ -951,6 +951,9 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.assemble>library</geronimo.assemble>
+            </properties>
         </dependency>
 
         <dependency>

Modified: geronimo/branches/1.1/configs/client-system/project.properties
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/client-system/project.properties?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/configs/client-system/project.properties (original)
+++ geronimo/branches/1.1/configs/client-system/project.properties Wed May 24 03:23:45 2006
@@ -34,6 +34,7 @@
     ../lib/cglib-nodep-${cglib_version}.jar \
     ../lib/commons-cli-${commons_cli_version}.jar \
     ../lib/commons-logging-${commons_logging_version}.jar \
+    ../lib/cooncurrent-${concurrent_version}.jar \
     ../lib/log4j-${log4j_version}.jar \
     ../lib/mx4j-${mx4j_version}.jar \
     ../lib/mx4j-remote-${mx4j_version}.jar \

Modified: geronimo/branches/1.1/configs/client-system/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/client-system/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/configs/client-system/project.xml (original)
+++ geronimo/branches/1.1/configs/client-system/project.xml Wed May 24 03:23:45 2006
@@ -76,6 +76,14 @@
              </properties>
         </dependency>
         <dependency>
+            <groupId>concurrent</groupId>
+            <artifactId>concurrent</artifactId>
+            <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.dependency>true</geronimo.dependency>
+            </properties>
+        </dependency>
+        <dependency>
             <groupId>commons-cli</groupId>
             <artifactId>commons-cli</artifactId>
             <version>${commons_cli_version}</version>

Modified: geronimo/branches/1.1/configs/j2ee-system/project.properties
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/j2ee-system/project.properties?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/configs/j2ee-system/project.properties (original)
+++ geronimo/branches/1.1/configs/j2ee-system/project.properties Wed May 24 03:23:45 2006
@@ -32,6 +32,7 @@
     ../lib/geronimo-system-${geronimo_version}.jar \
     ../lib/geronimo-util-${geronimo_version}.jar \
     ../lib/cglib-nodep-${cglib_version}.jar \
+    ../lib/concurrent-${concurrent_version}.jar \
     ../lib/commons-cli-${commons_cli_version}.jar \
     ../lib/commons-logging-${commons_logging_version}.jar \
     ../lib/log4j-${log4j_version}.jar \
@@ -44,4 +45,4 @@
 
 geronimo.packaging.mainClass=org.apache.geronimo.system.main.Daemon
 geronimo.packaging.endorsedDirs=lib/endorsed
-geronimo.packaging.extensionDirs=lib/ext
\ No newline at end of file
+geronimo.packaging.extensionDirs=lib/ext

Modified: geronimo/branches/1.1/configs/j2ee-system/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/j2ee-system/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/configs/j2ee-system/project.xml (original)
+++ geronimo/branches/1.1/configs/j2ee-system/project.xml Wed May 24 03:23:45 2006
@@ -76,6 +76,14 @@
             </properties>
         </dependency>
         <dependency>
+            <groupId>concurrent</groupId>
+            <artifactId>concurrent</artifactId>
+            <version>${concurrent_version}</version>
+            <properties>
+                <geronimo.dependency>true</geronimo.dependency>
+            </properties>
+        </dependency>
+        <dependency>
             <groupId>commons-cli</groupId>
             <artifactId>commons-cli</artifactId>
             <version>${commons_cli_version}</version>

Modified: geronimo/branches/1.1/configs/rmi-naming/project.xml
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/rmi-naming/project.xml?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/configs/rmi-naming/project.xml (original)
+++ geronimo/branches/1.1/configs/rmi-naming/project.xml Wed May 24 03:23:45 2006
@@ -277,9 +277,6 @@
             <groupId>concurrent</groupId>
             <artifactId>concurrent</artifactId>
             <version>${concurrent_version}</version>
-            <properties>
-                 <geronimo.dependency>true</geronimo.dependency>
-             </properties>
         </dependency>
     <!--transaction module requires tranql for cache class -->
 <!-- TODO this is false.  tranql should not be needed here -->

Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java
URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java?rev=409112&r1=409111&r2=409112&view=diff
==============================================================================
--- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java (original)
+++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java Wed May 24 03:23:45 2006
@@ -26,6 +26,7 @@
 
 import java.rmi.server.RMIClassLoader;
 import java.rmi.server.RMIClassLoaderSpi;
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
 
 /**
  * An implementation of {@link RMIClassLoaderSpi} which provides normilzation
@@ -37,12 +38,16 @@
     extends RMIClassLoaderSpi
 {
     private RMIClassLoaderSpi delegate = RMIClassLoader.getDefaultProviderInstance();
-    
+
+    //TODO: Not sure of the best initial size.  Starting with 100 which should be reasonable.
+    private ConcurrentReaderHashMap cachedCodebases = new ConcurrentReaderHashMap(100, 0.75F);
+
+
     public Class loadClass(String codebase, String name, ClassLoader defaultLoader)
         throws MalformedURLException, ClassNotFoundException
     {
         if (codebase != null) {
-            codebase = normalizeCodebase(codebase);
+            codebase = getNormalizedCodebase(codebase);
         }
         
         return delegate.loadClass(codebase, name, defaultLoader);
@@ -52,7 +57,7 @@
         throws MalformedURLException, ClassNotFoundException
     {
         if (codebase != null) {
-            codebase = normalizeCodebase(codebase);
+            codebase = getNormalizedCodebase(codebase);
         }
         
         return delegate.loadProxyClass(codebase, interfaces, defaultLoader);
@@ -62,7 +67,7 @@
         throws MalformedURLException
     {
         if (codebase != null) {
-            codebase = normalizeCodebase(codebase);
+            codebase = getNormalizedCodebase(codebase);
         }
         
         return delegate.getClassLoader(codebase);
@@ -89,13 +94,37 @@
         
         return delegate.getClassAnnotation(type);
     }
-    
+
+    /**
+     * Uses a ConcurrentReaderHashmap to save the contents of previous parses.
+     *
+     * @param codebase
+     * @return
+     * @throws MalformedURLException
+     */
+    private String getNormalizedCodebase(String codebase)
+            throws MalformedURLException {
+        String cachedCodebase = (String)cachedCodebases.get(codebase);
+        if (cachedCodebase != null)
+            return cachedCodebase;
+
+        String normalizedCodebase = normalizeCodebase(codebase);
+        String oldValue = (String)cachedCodebases.put(codebase, normalizedCodebase);
+
+        // If there was a previous value remove the one we just added to make sure the
+        // cache doesn't grow.
+        if (oldValue != null) {
+            cachedCodebases.remove(codebase);
+        }
+        return normalizedCodebase;  // We can use the oldValue
+    }
+
+
     static String normalizeCodebase(String input)
         throws MalformedURLException
     {
         assert input != null;
-        // System.out.println("Input codebase: " + input);
-        
+
         StringBuffer codebase = new StringBuffer();
         StringBuffer working = new StringBuffer();
         StringTokenizer stok = new StringTokenizer(input, " \t\n\r\f", true);
@@ -169,4 +198,4 @@
     public interface ClassLoaderServerAware {
         public URL[] getClassLoaderServerURLs();
     }
-        }
+}



Re: svn commit: r409112 - EJB Performance Improvement of 6x (did I miss something ?)!

Posted by Matt Hogstrom <ma...@hogstrom.org>.
According to the ConcurrentReaderHashMap doc a Null value is returned if this value was added and 
there are no dups.  If there was a dup (meaning you did a get and on null a put in the example 
below) then you'll get non-null value in return (meaning you now have more than one).  If its now 
positive then my put caused the cache to grow (simple race condition) so I remove it.  Subsequent 
get's will succeed and no more puts will be done.  I think that net's out to a single entry and the 
additional code is simply managing a race condition for the first to add to the Map.

Am I mis interpreting the code?  I ran a test for 30 minutes and did not see the heap growing but 
could add some diagnostic code to dump the count on every 1000n requests.

Matt

Dain Sundstrom wrote:
> On May 24, 2006, at 3:30 AM, Matt Hogstrom wrote:
> 
>>> +    private String getNormalizedCodebase(String codebase)
>>> +            throws MalformedURLException {
>>> +        String cachedCodebase = (String)cachedCodebases.get(codebase);
>>> +        if (cachedCodebase != null)
>>> +            return cachedCodebase;
>>> +
>>> +        String normalizedCodebase = normalizeCodebase(codebase);
>>> +        String oldValue = (String)cachedCodebases.put(codebase, 
>>> normalizedCodebase);
>>> +
>>> +        // If there was a previous value remove the one we just 
>>> added to make sure the
>>> +        // cache doesn't grow.
>>> +        if (oldValue != null) {
>>> +            cachedCodebases.remove(codebase);
>>> +        }
>>> +        return normalizedCodebase;  // We can use the oldValue
>>> +    }
> 
> I don't get what you are trying to do here.  It appears that you add the 
> value but if the map already contained the value you turn around and 
> remove it.  I don't see how that stops the cache from growing.  If you 
> want to prevent the cache from growing I think you need something like 
> this:
> 
>     if (cache.size < CACHE_LIMIT) {
>         cachedCodeBases.put(codebase, normalizedCodebase);
>     }
> 
> That isn't absolutely safe but is most likely good enough.  The problem 
> is once the cache is full, you will never add another value.  
> Alternatively, you could drop something from the cache once it is full, 
> but you would have to figure out how to do it randomly since, you don't 
> have any data the entries.
> 
> You may want to consider switching the implementation to use a 
> LinkedHashMap with a size limit, so old values are pushed out.  The 
> problem with a LinkedHashMap is you need to synchronize access.  This 
> shouldn't be a big problem as long as you keep the synchronized blocks 
> small.  I'd synchronized, check if the value exists, and if it didn't 
> add a future object to the map.  Then you exist the synchronized block 
> and call get() on the future object.  This causes the expensive 
> operation normalizedCodebase(codebase) to happen outside of the main 
> synchronize block.
> 
> Regardless, I'm +1 to this patch because it will work as it stands, 
> although with a small and very slow memory leak of one string per class 
> loader, and it is way better then what we had before which was nothing :)
> 
> -dain
> 
> 
> 

Re: svn commit: r409112 - EJB Performance Improvement of 6x (did I miss something ?)!

Posted by Dain Sundstrom <da...@iq80.com>.
On May 24, 2006, at 3:30 AM, Matt Hogstrom wrote:

>> +    private String getNormalizedCodebase(String codebase)
>> +            throws MalformedURLException {
>> +        String cachedCodebase = (String)cachedCodebases.get 
>> (codebase);
>> +        if (cachedCodebase != null)
>> +            return cachedCodebase;
>> +
>> +        String normalizedCodebase = normalizeCodebase(codebase);
>> +        String oldValue = (String)cachedCodebases.put(codebase,  
>> normalizedCodebase);
>> +
>> +        // If there was a previous value remove the one we just  
>> added to make sure the
>> +        // cache doesn't grow.
>> +        if (oldValue != null) {
>> +            cachedCodebases.remove(codebase);
>> +        }
>> +        return normalizedCodebase;  // We can use the oldValue
>> +    }

I don't get what you are trying to do here.  It appears that you add  
the value but if the map already contained the value you turn around  
and remove it.  I don't see how that stops the cache from growing.   
If you want to prevent the cache from growing I think you need  
something like this:

     if (cache.size < CACHE_LIMIT) {
         cachedCodeBases.put(codebase, normalizedCodebase);
     }

That isn't absolutely safe but is most likely good enough.  The  
problem is once the cache is full, you will never add another value.   
Alternatively, you could drop something from the cache once it is  
full, but you would have to figure out how to do it randomly since,  
you don't have any data the entries.

You may want to consider switching the implementation to use a  
LinkedHashMap with a size limit, so old values are pushed out.  The  
problem with a LinkedHashMap is you need to synchronize access.  This  
shouldn't be a big problem as long as you keep the synchronized  
blocks small.  I'd synchronized, check if the value exists, and if it  
didn't add a future object to the map.  Then you exist the  
synchronized block and call get() on the future object.  This causes  
the expensive operation normalizedCodebase(codebase) to happen  
outside of the main synchronize block.

Regardless, I'm +1 to this patch because it will work as it stands,  
although with a small and very slow memory leak of one string per  
class loader, and it is way better then what we had before which was  
nothing :)

-dain

Re: svn commit: r409112 - EJB Performance Improvement of 6x (did I miss something ?)!

Posted by Matt Hogstrom <ma...@hogstrom.org>.
All,

I have committed a bug fix to improve performance of DayTrader for EJB transactions that has 
improved our performance from 500 TPS to 3200 TPS for PingServlet2Session (*a 6x improvement in EJB 
performance!*).  This also includes an uncommitted (and independent) fix to OpenEJB to improve EJB 
copy performance.

This change required me to add the concurrent jar to the MANIFEST classpath on the server.jar.  I 
worked with DJencks on crafting the beast but wanted Dain, et all, to take a peak and make sure that 
I didn't miss something.

This closes a significant performance gap for Geronimo when compared to other OpenSource and 
Commercial AppServers :)

Cheers,

Matt

hogstrom@apache.org wrote:
> Author: hogstrom
> Date: Wed May 24 03:23:45 2006
> New Revision: 409112
> 
> URL: http://svn.apache.org/viewvc?rev=409112&view=rev
> Log:
> BUG: This fix addresses an issue in RMIClassLoaderSpiImpl where a codebase is optionally passed for certain copy operations.  When profiling DayTrader our performance for PingServlet2Session was extremely poor relative to JBoss and WebSphere.  Our throughput on a 2-way 3.0 Ghz system was roughly 500 tps compared to 5400 and 4500 repsepctively.  (It appears that JBoss is not honoring pass-by-value semantics properly; thus the significantly higher throughput).  
> 
> I chased the degraded performance to RMIClassLoaderSPIImpl where we were spending nearly 70% of the system's time in normalizeCodebase for less than 1/8 of the requests being processed.  Here is some profiling data to show the degredation:
> 
>     =======   =====   =====   =====      =======      ======= ==========
>      Parent    4610    0.71   70.54   1157864861 115775210210   28) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.loadClass(Ljava/lang/
> 
>        Self    4610    0.71   70.54   1157864861 115775210210 [29]  J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeCodebase(Lja
> 
>       Child   50550    0.34   61.97    555213244 101708338940   31) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.updateCodebase(Ljava/
>       Child    4584    0.04    4.40     65515147   7224581400   30) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeURL(Ljava/ne
>       Child   55136    0.46    2.71    758942891   4446465936   42) J:java/net/URL.<init>(Ljava/net/URL;Ljava/lang/String;Ljava/net/URLStreamHan      
>       Child  234350    0.39    0.59    631910516    970672051   36) J:java/lang/String.indexOf(I)I
> 
> Note that of the 4610 requests were a subset of a total of 32000 transactions.  
> 
> 
> Here is the  normalizeURL information:
> 
>     =======   =====   =====   =====      =======      ======= ==========
>      Parent   50524    0.38   59.74    629510012  98041028811   30) J:org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.normalizeURL(Ljava/ne
> 
>        Self   50524    0.38   59.74    629510012  98041028811 [32]  J:java/io/File.toURI()Ljava/net/URI;
> 
>       Child   50524    0.23   55.43    376226211  90981520312   33) J:java/net/URI.<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;
>       Child   50524    0.12    3.14    189098774   5152641459   54) J:java/io/File.isDirectory()Z
>       Child   50524    0.17    0.39    274629658    646476978  192) J:java/io/File.slashify(Ljava/lang/String;Z)Ljava/lang/String;
>       Child   50524    0.14    0.29    224357024    473009995  210) J:java/io/File.<init>(Ljava/lang/String;)V
>       Child   50524    0.05    0.05     88736649     88736649  386) J:java/lang/String.startsWith(Ljava/lang/String;I)Z
>       Child   50524    0.04    0.04     69133406     69133406  408) J:java/io/Win32FileSystem.resolve(Ljava/io/File;)Ljava/lang/String;
> 
> I added a new method to inercept and cache calls to normalizeCodebase where I simply return a cached result.  This has resulted in a 6x+ performance improvement where we have gone from 500 tps to 3200+.   
> 
> 
> Modified:
>     geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml
>     geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml
>     geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml
>     geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml
>     geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml
>     geronimo/branches/1.1/configs/client-system/project.properties
>     geronimo/branches/1.1/configs/client-system/project.xml
>     geronimo/branches/1.1/configs/j2ee-system/project.properties
>     geronimo/branches/1.1/configs/j2ee-system/project.xml
>     geronimo/branches/1.1/configs/rmi-naming/project.xml
>     geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java
> 
> Modified: geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml (original)
> +++ geronimo/branches/1.1/assemblies/j2ee-jetty-server/project.xml Wed May 24 03:23:45 2006
> @@ -760,6 +760,9 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.assemble>library</geronimo.assemble>
> +            </properties>
>          </dependency>
>  
>          <dependency>
> 
> Modified: geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml (original)
> +++ geronimo/branches/1.1/assemblies/j2ee-tomcat-server/project.xml Wed May 24 03:23:45 2006
> @@ -761,6 +761,9 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.assemble>library</geronimo.assemble>
> +            </properties>
>          </dependency>
>  
>          <dependency>
> 
> Modified: geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml (original)
> +++ geronimo/branches/1.1/assemblies/minimal-jetty-server/project.xml Wed May 24 03:23:45 2006
> @@ -446,6 +446,9 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.assemble>library</geronimo.assemble>
> +            </properties>
>          </dependency>
>  
>  <!-- geronimo jars -->
> 
> Modified: geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml (original)
> +++ geronimo/branches/1.1/assemblies/minimal-tomcat-server/project.xml Wed May 24 03:23:45 2006
> @@ -446,6 +446,9 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.assemble>library</geronimo.assemble>
> +            </properties>
>          </dependency>
>  
>  <!-- geronimo jars -->
> 
> Modified: geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml (original)
> +++ geronimo/branches/1.1/assemblies/zzzzj2ee-installer/project.xml Wed May 24 03:23:45 2006
> @@ -951,6 +951,9 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.assemble>library</geronimo.assemble>
> +            </properties>
>          </dependency>
>  
>          <dependency>
> 
> Modified: geronimo/branches/1.1/configs/client-system/project.properties
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/client-system/project.properties?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/configs/client-system/project.properties (original)
> +++ geronimo/branches/1.1/configs/client-system/project.properties Wed May 24 03:23:45 2006
> @@ -34,6 +34,7 @@
>      ../lib/cglib-nodep-${cglib_version}.jar \
>      ../lib/commons-cli-${commons_cli_version}.jar \
>      ../lib/commons-logging-${commons_logging_version}.jar \
> +    ../lib/cooncurrent-${concurrent_version}.jar \
>      ../lib/log4j-${log4j_version}.jar \
>      ../lib/mx4j-${mx4j_version}.jar \
>      ../lib/mx4j-remote-${mx4j_version}.jar \
> 
> Modified: geronimo/branches/1.1/configs/client-system/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/client-system/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/configs/client-system/project.xml (original)
> +++ geronimo/branches/1.1/configs/client-system/project.xml Wed May 24 03:23:45 2006
> @@ -76,6 +76,14 @@
>               </properties>
>          </dependency>
>          <dependency>
> +            <groupId>concurrent</groupId>
> +            <artifactId>concurrent</artifactId>
> +            <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.dependency>true</geronimo.dependency>
> +            </properties>
> +        </dependency>
> +        <dependency>
>              <groupId>commons-cli</groupId>
>              <artifactId>commons-cli</artifactId>
>              <version>${commons_cli_version}</version>
> 
> Modified: geronimo/branches/1.1/configs/j2ee-system/project.properties
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/j2ee-system/project.properties?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/configs/j2ee-system/project.properties (original)
> +++ geronimo/branches/1.1/configs/j2ee-system/project.properties Wed May 24 03:23:45 2006
> @@ -32,6 +32,7 @@
>      ../lib/geronimo-system-${geronimo_version}.jar \
>      ../lib/geronimo-util-${geronimo_version}.jar \
>      ../lib/cglib-nodep-${cglib_version}.jar \
> +    ../lib/concurrent-${concurrent_version}.jar \
>      ../lib/commons-cli-${commons_cli_version}.jar \
>      ../lib/commons-logging-${commons_logging_version}.jar \
>      ../lib/log4j-${log4j_version}.jar \
> @@ -44,4 +45,4 @@
>  
>  geronimo.packaging.mainClass=org.apache.geronimo.system.main.Daemon
>  geronimo.packaging.endorsedDirs=lib/endorsed
> -geronimo.packaging.extensionDirs=lib/ext
> \ No newline at end of file
> +geronimo.packaging.extensionDirs=lib/ext
> 
> Modified: geronimo/branches/1.1/configs/j2ee-system/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/j2ee-system/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/configs/j2ee-system/project.xml (original)
> +++ geronimo/branches/1.1/configs/j2ee-system/project.xml Wed May 24 03:23:45 2006
> @@ -76,6 +76,14 @@
>              </properties>
>          </dependency>
>          <dependency>
> +            <groupId>concurrent</groupId>
> +            <artifactId>concurrent</artifactId>
> +            <version>${concurrent_version}</version>
> +            <properties>
> +                <geronimo.dependency>true</geronimo.dependency>
> +            </properties>
> +        </dependency>
> +        <dependency>
>              <groupId>commons-cli</groupId>
>              <artifactId>commons-cli</artifactId>
>              <version>${commons_cli_version}</version>
> 
> Modified: geronimo/branches/1.1/configs/rmi-naming/project.xml
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/configs/rmi-naming/project.xml?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/configs/rmi-naming/project.xml (original)
> +++ geronimo/branches/1.1/configs/rmi-naming/project.xml Wed May 24 03:23:45 2006
> @@ -277,9 +277,6 @@
>              <groupId>concurrent</groupId>
>              <artifactId>concurrent</artifactId>
>              <version>${concurrent_version}</version>
> -            <properties>
> -                 <geronimo.dependency>true</geronimo.dependency>
> -             </properties>
>          </dependency>
>      <!--transaction module requires tranql for cache class -->
>  <!-- TODO this is false.  tranql should not be needed here -->
> 
> Modified: geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java
> URL: http://svn.apache.org/viewvc/geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java?rev=409112&r1=409111&r2=409112&view=diff
> ==============================================================================
> --- geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java (original)
> +++ geronimo/branches/1.1/modules/system/src/java/org/apache/geronimo/system/rmi/RMIClassLoaderSpiImpl.java Wed May 24 03:23:45 2006
> @@ -26,6 +26,7 @@
>  
>  import java.rmi.server.RMIClassLoader;
>  import java.rmi.server.RMIClassLoaderSpi;
> +import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
>  
>  /**
>   * An implementation of {@link RMIClassLoaderSpi} which provides normilzation
> @@ -37,12 +38,16 @@
>      extends RMIClassLoaderSpi
>  {
>      private RMIClassLoaderSpi delegate = RMIClassLoader.getDefaultProviderInstance();
> -    
> +
> +    //TODO: Not sure of the best initial size.  Starting with 100 which should be reasonable.
> +    private ConcurrentReaderHashMap cachedCodebases = new ConcurrentReaderHashMap(100, 0.75F);
> +
> +
>      public Class loadClass(String codebase, String name, ClassLoader defaultLoader)
>          throws MalformedURLException, ClassNotFoundException
>      {
>          if (codebase != null) {
> -            codebase = normalizeCodebase(codebase);
> +            codebase = getNormalizedCodebase(codebase);
>          }
>          
>          return delegate.loadClass(codebase, name, defaultLoader);
> @@ -52,7 +57,7 @@
>          throws MalformedURLException, ClassNotFoundException
>      {
>          if (codebase != null) {
> -            codebase = normalizeCodebase(codebase);
> +            codebase = getNormalizedCodebase(codebase);
>          }
>          
>          return delegate.loadProxyClass(codebase, interfaces, defaultLoader);
> @@ -62,7 +67,7 @@
>          throws MalformedURLException
>      {
>          if (codebase != null) {
> -            codebase = normalizeCodebase(codebase);
> +            codebase = getNormalizedCodebase(codebase);
>          }
>          
>          return delegate.getClassLoader(codebase);
> @@ -89,13 +94,37 @@
>          
>          return delegate.getClassAnnotation(type);
>      }
> -    
> +
> +    /**
> +     * Uses a ConcurrentReaderHashmap to save the contents of previous parses.
> +     *
> +     * @param codebase
> +     * @return
> +     * @throws MalformedURLException
> +     */
> +    private String getNormalizedCodebase(String codebase)
> +            throws MalformedURLException {
> +        String cachedCodebase = (String)cachedCodebases.get(codebase);
> +        if (cachedCodebase != null)
> +            return cachedCodebase;
> +
> +        String normalizedCodebase = normalizeCodebase(codebase);
> +        String oldValue = (String)cachedCodebases.put(codebase, normalizedCodebase);
> +
> +        // If there was a previous value remove the one we just added to make sure the
> +        // cache doesn't grow.
> +        if (oldValue != null) {
> +            cachedCodebases.remove(codebase);
> +        }
> +        return normalizedCodebase;  // We can use the oldValue
> +    }
> +
> +
>      static String normalizeCodebase(String input)
>          throws MalformedURLException
>      {
>          assert input != null;
> -        // System.out.println("Input codebase: " + input);
> -        
> +
>          StringBuffer codebase = new StringBuffer();
>          StringBuffer working = new StringBuffer();
>          StringTokenizer stok = new StringTokenizer(input, " \t\n\r\f", true);
> @@ -169,4 +198,4 @@
>      public interface ClassLoaderServerAware {
>          public URL[] getClassLoaderServerURLs();
>      }
> -        }
> +}
> 
> 
> 
> 
>