This is now solved.<br><br>I noticed that the problem became worse the bigger the classpath was, even if the extra jars contained totally irrellevant classes.<br><br>Profiling revealed that the rule compilation generated an enomous amount of IO traffic from ClassLoader.loadClass originating from <br>
org.mvel.ParserContext.checkForDynamicImport and org.drools.rule.PackageCompilationData$PackageClassLoader.<br><br>In both these places Drools generates a lot of loadClass calls for classes that does not exist.<br>It seems like the Sun classloaders does not cache the result of failed class lookups, but scans the whole classpath again and again looking for these non-existing classes.<br>
That is why the problem gets bigger the larger your classpath is. Our classpath contains 100+ jars, so we got hit pretty bad.<br><br>I solved the problem by creating a caching classloader that also caches the result of failed lookups. When I added this as the context classloader scoped around all my compilation I saw a performance increase of a factor of 10 - 20 in our various environments.<br>
<br>Here are the stats from the caching classloader after compiling 850 rules:<br><br>Caching loader called 200608 times<br>119 actual successful loads<br>
932 actual failed loads<br>73738 cache hits for successfull loads<br>125819 cache hits for failed loads<br><br>In other words: Drools generated 126751 loads for 932 non-existing classes. We saved 125819 full classapth scans by caching the failed lookups.<br>
<br>As mentioned above the caching classloader can be hooked into the system by setting it at the context classloader.<br>org.mvel.ParserContext.checkForDynamicImport uses the context classloader directly.<br>org.drools.rule.PackageCompilationData$PackageClassLoader uses the classloader configured in PackageBuilderConfiguration which is the context classloader by default.<br>
This means you get the full effect only when you scope the caching class loader around all your PackageBuilderConfiguration and PackageBuilder usage.<br><br>Below is the code for our caching classloader for the reference of anybody else who might encounter this problem.<br>
<br>Regards<br>Chr<br><br>PS Edson:<br>This problem is related to compilation. The RETE building is usually very fast.<br><br>----------------------------------------------<br>
package domain.rules;<br><br>import java.util.HashMap;<br>import java.util.Map;<br><br>/**<br> * Classloader that intercepts calls to the current context class loader and caches the result of the calls to {@link #loadClass}<br>
 * on it.<br> * &lt;p/&gt;<br> * The interception will start automagically when this class is instantiated. Make sure that you call {@link #stop()} from a finally<br> * block when you want the loader interception to stop, to avoid unnecessary caching.<br>
 *<br> * @author Christian Nedregård<br> * @see Thread#getContextClassLoader()<br> */<br>public class CachingContextClassLoader extends ClassLoader {<br>    private Map classLoaderResultMap = new HashMap();<br>    private ClassLoader originalClassLoader;<br>
    private int successfulCalls = 0;<br>    private int failedCalls = 0;<br>    private int cacheHits = 0;<br>    private int successfulLoads = 0;<br>    private int failedLoads = 0;<br><br>    /**<br>     * Create an instance. The instance will automagically start intercepting {@link #loadClass(String)} calls to the current<br>
     * context class loader.<br>     *<br>     * @see Thread#getContextClassLoader()<br>     */<br>    CachingContextClassLoader() {<br>        super(Thread.currentThread().getContextClassLoader());<br>        this.originalClassLoader = Thread.currentThread().getContextClassLoader();<br>
        Thread.currentThread().setContextClassLoader(this);<br>    }<br><br>    /**<br>     * Try to load the class from the original context class loader and chache the result (also &lt;code&gt;ClassNotFoundException&lt;/code&gt;s).<br>
     * Subsequent calls for the same class name will return the cached version, or throw a cached ClassNotFoundException if it was<br>     * not found initially.<br>     *<br>     * @param name the name of the class to find.<br>
     * @return the cached result of a call to &lt;code&gt;loadClass&lt;/code&gt; on the original context class loader.<br>     * @throws ClassNotFoundException when the class of the given name could not be found.<br>     */<br>
    public Class loadClass(String name) throws ClassNotFoundException {<br>        Object result;<br>        if (classLoaderResultMap.containsKey(name)) {<br>            ++cacheHits;<br>            result = classLoaderResultMap.get(name);<br>
        } else {<br>            try {<br>                result = super.loadClass(name);<br>                ++successfulLoads;<br>            } catch (ClassNotFoundException e) {<br>                ++failedLoads;<br>                result = e;<br>
            }<br>            classLoaderResultMap.put(name, result);<br>        }<br>        if (result instanceof ClassNotFoundException) {<br>            ++failedCalls;<br>            throw (ClassNotFoundException) result;<br>
        } else {<br>            ++successfulCalls;<br>            return (Class) result;<br>        }<br>    }<br><br>    /**<br>     * Stop intercepting by resetting the original context classloader using {@link Thread#setContextClassLoader(ClassLoader)}.<br>
     */<br>    public void stop() {<br>        Thread.currentThread().setContextClassLoader(originalClassLoader);<br>    }<br><br>    /**<br>     * Get a textual report of the caching that was performed.<br>     *<br>     * @return a textual report of the caching that was performed.<br>
     */<br>    public String getReport() {<br>        return new StringBuffer(&quot;Loader called &quot;).append(successfulCalls + failedCalls).append(&quot; times, &quot;).append(successfulCalls)<br>                .append(&quot; successfull, &quot;).append(failedCalls).append(&quot; failed. Cache hits: &quot;).append(cacheHits)<br>
                .append(&quot;, successful loads:  &quot;).append(successfulLoads).append(&quot;, Failed loads: &quot;).append(failedLoads)<br>                .append(&#39;.&#39;).toString();<br>    }<br>}<br><br>----------------------------------------------<br>

<br><br><div class="gmail_quote">2009/4/17 Edson Tirelli <span dir="ltr">&lt;<a href="mailto:tirelli@post.com">tirelli@post.com</a>&gt;</span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>   Christian,<br><br>   Can you break down this performance into 2 steps?<br><br>1. COMPILE: this is the step where textual information is parsed and compiled into binary data. This is done by the PackageBuilder.addPackageFromDrl() method.<br>

<br>2. RETE BUILDING: this is the step where the binary data is assembled into the rete network. This is done by RuleBase.addPackage() method.<br><br>    These two processes are mostly independent and it would be good to know what is the relative time spent in each.<br>

<br>    After that, we will need to get a few rule samples from you with a test case so that we can investigate. <br><br>     Thanks,<br>        Edson<br><br><div class="gmail_quote">2009/4/17 Christian Nedregård <span dir="ltr">&lt;<a href="mailto:christian_nedregaard@email.com" target="_blank">christian_nedregaard@email.com</a>&gt;</span><div>
<div></div><div class="h5"><br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Thank you for the quick reply and the tip Ingomar.<br><br>Since our rules are template based I was able to merge them into 30 drls (850 before). This gave a 30% perfomance improvement, but we are still not able to compile more than 2 rules per second. I also tried to execute in with jdk 1.6.0_03 instead of 1.4.2_11. This only gave a small performance increase.<br>


<br>We are also seing the same slow performance in our production environment wich is JDK 1.4.2_11 on Solaris, so this is not a OS spesific problem.<br><br>I addition I tried to run the compilation in a dedicated process with 1G available memory with no performance increase, so it is not related to memory restrictions either.<br>


<br>From our experimentation I see that the compile time, unsurpisingly, is directly connectet to the complexity of the rule. If i strip away he LHS and RHS of the rules and only keep the imports and global definitions I am able to get a compilation throughput at 24 rules per second.<br>


<br>Are your rules much simpler than ours? Can you think of any other reason why you are seeing a much better compiler throughput?<br><br>Regards<br>Chr<div><div></div><div><br><br><br><div class="gmail_quote">
On Fri, Apr 17, 2009 at 10:34 AM, Ingomar Otter <span dir="ltr">&lt;<a href="mailto:iotter@mac.com" target="_blank">iotter@mac.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Christian,<br>
with our app, we see a compile performance which is at least an order of magnitude higher.<br>
I would assume that in your case the extreme fine granularity of your DRLs may be slowing things down.<br>
Have you tried to consolidate these in bigger but fewer DRls?<br>
<br>
If you need that granualarity, you still have the option of joining these together before running it with the help of perl and the likes.<br>
<br>
--I<br>
_______________________________________________<br>
rules-users mailing list<br>
<a href="mailto:rules-users@lists.jboss.org" target="_blank">rules-users@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
<br>
</blockquote></div><br>
</div></div><br>_______________________________________________<br>
rules-users mailing list<br>
<a href="mailto:rules-users@lists.jboss.org" target="_blank">rules-users@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
<br></blockquote></div></div></div><font color="#888888"><br><br clear="all"><br>-- <br>  Edson Tirelli<br>  JBoss Drools Core Development<br>  JBoss, a division of Red Hat @ <a href="http://www.jboss.com" target="_blank">www.jboss.com</a><br>

</font><br>_______________________________________________<br>
rules-users mailing list<br>
<a href="mailto:rules-users@lists.jboss.org">rules-users@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/rules-users" target="_blank">https://lists.jboss.org/mailman/listinfo/rules-users</a><br>
<br></blockquote></div><br>