<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">The first issue
      (ObserverCaptureExtension.scan) is the easiest and most improving,
      it only needs your approval that it's really up to the point -
      it's just a few lines in fact.<br>
      I will provide a proposal in my clone at github and notify you.<br>
      <br>
      The Bootstrap redesign idea I will provide in a seperate branch in
      same repo.<br>
      The Jandex-idea would need also changes in the Weld-API, so they
      are somewhat theoretical :-/<br>
      <br>
      Regards,<br>
      Thomas<br>
      <br>
      Am 05.11.2012 01:27, schrieb Lincoln Baxter, III:<br>
    </div>
    <blockquote
cite="mid:CAEp_U4ER1UXKayKC0p8f1fSiBL9ogjnJQZ=dyK7CK2xFXG0JdA@mail.gmail.com"
      type="cite">I think performance improvements in Forge 1.x are very
      important even now!<br>
      <br>
      It's going to be around for a very long time and while we are
      working on Forge 2.0 now, the kinds of improvements you are
      talking about, Thomas, are very significant!<br>
      <br>
      How can we help? Do you think you could put this code into a
      branch with a single commit (or just one for each change) so that
      we can see just how much you had to change?<br>
      <br>
      The problem with the weld container is the Hibernate Tools plugin.
      If that one works, and the Openshift and AS7 plugins work, then
      it's safe to assume that it's working fine. It was a hack to solve
      a classloading problem, but if we can fix it now, that's great!<br>
      <br>
      ~Lincoln<br>
      <div class="gmail_extra"><br>
        <br>
        <div class="gmail_quote">On Sat, Nov 3, 2012 at 3:27 PM, George
          Gastaldi <span dir="ltr">&lt;<a moz-do-not-send="true"
              href="mailto:ggastald@redhat.com" target="_blank">ggastald@redhat.com</a>&gt;</span>
          wrote:<br>
          <blockquote class="gmail_quote" style="margin:0 0 0
            .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Thomas,<br>
            <br>
            Nice to know that you've found some improvements for Forge
            1.x startup time. However, we are rewriting Forge in 2.x
            from the ground up and we're focusing on performance and
            flexibility in first place.<br>
            <br>
            We encourage you to try the 2.0 branch and help us on
            finding some possible performance problems if you feel so.<br>
            <br>
            As for now, we are avoiding any major changes and updates to
            1.x.<br>
            <br>
            Best Regards,<br>
            <br>
            George Gastaldi<br>
            <br>
            Em 03/11/2012, às 15:41, Thomas Frühbeck &lt;<a
              moz-do-not-send="true" href="mailto:fruehbeck@aon.at">fruehbeck@aon.at</a>&gt;
            escreveu:<br>
            <div class="HOEnZb">
              <div class="h5"><br>
                &gt; Hi,<br>
                &gt;<br>
                &gt; following the discussions about boot-up performance
                of Forge I made some<br>
                &gt; investigations using a profiler.<br>
                &gt; After testing a lot of different scenarios I would
                like to share my<br>
                &gt; results and ask for your opinion on it.<br>
                &gt;<br>
                &gt;
*************************************************************************************<br>
                &gt; Issue 1.: hot spot inv.<br>
                &gt;
                org.jboss.forge.bus.cdi.ObserverCaptureExtension.scan<br>
                &gt;     profiling shows that 37% CPU time are used in
                firing<br>
                &gt; ProcessAnnotatedType events, which are AFAICS only
                used to filter old<br>
                &gt; event types<br>
                &gt;     "37,2% - 13.442 ms - 1.866 inv.<br>
                &gt;
                org.jboss.weld.bootstrap.events.ProcessAnnotatedTypeImpl.fire"<br>
                &gt;<br>
                &gt;     By introducing a preparatory check in
                ObserverCaptureExtension like<br>
                &gt;&gt;   if (isMethodsAnnotated(originalType,
                Observes.class)) {<br>
                &gt;&gt;   ....<br>
                &gt;&gt;   }<br>
                &gt;<br>
                &gt; and something like:<br>
                &gt;&gt;  private boolean
                isMethodsAnnotated(AnnotatedType&lt;?&gt; type,
                Class&lt;?<br>
                &gt; extends Annotation&gt; annotation) {<br>
                &gt;&gt;      if
                (type.getClass().isAnnotationPresent(annotation))<br>
                &gt;&gt;         return true;<br>
                &gt;&gt;      for (Method m :
                type.getClass().getMethods()) {<br>
                &gt;&gt;          if (m.isAnnotationPresent(annotation))<br>
                &gt;&gt;              return true;<br>
                &gt;&gt;          for (Annotation[] arr :
                m.getParameterAnnotations()) {<br>
                &gt;&gt;             for (Annotation a : arr) {<br>
                &gt;&gt;                 if (a.equals(annotation))<br>
                &gt;&gt;                     return true;<br>
                &gt;&gt;             }<br>
                &gt;&gt;          }<br>
                &gt;&gt;      }<br>
                &gt;&gt;      return false;<br>
                &gt;&gt;  }<br>
                &gt;<br>
                &gt;     we could reduce startup by 20%<br>
                &gt;     "13,8% - 2.438 ms - 1.798 inv.<br>
                &gt;
                org.jboss.weld.bootstrap.events.ProcessAnnotatedTypeImpl.fire<br>
                &gt;<br>
                &gt; Test: call Forge with commands "list-plugins" and
                "exit", like ~&gt; time<br>
                &gt; ((echo forge list-plugins; echo exit;)| bin/forge)<br>
                &gt;<br>
                &gt; Before optimization:<br>
                &gt; ~/forge&gt; time ((echo forge list-plugins
                &amp;&amp; echo exit)| bin/forge )<br>
                &gt;     _____<br>
                &gt;    |  ___|__  _ __ __ _  ___<br>
                &gt;    | |_ / _ \| `__/ _` |/ _ \  \\<br>
                &gt;    |  _| (_) | | | (_| |  __/  //<br>
                &gt;    |_|  \___/|_|  \__, |\___|<br>
                &gt;                    |___/<br>
                &gt;<br>
                &gt; [no project] forge-distribution-1.1.1-SNAPSHOT $
                forge list-plugins<br>
                &gt;
org.richfaces.forge.richfaces-forge-plugin:1.0.5.Final:1.0.0-SNAPSHOT-b1a6ebed-462f-40e1-ac08-82f927489301<br>
                &gt;
com.ocpsoft.forge.prettyfaces-plugin:1.0.2.Final:1.0.0-SNAPSHOT-c6b071ad-a6df-4112-8fff-82ecccd003fb<br>
                &gt;
org.jboss.hibernate.forge.hibernate-tools-plugin:1.0.5.Final:1.0.0-SNAPSHOT-afb1da29-a99f-4dd7-b020-5f3ba6073cde<br>
                &gt;
org.arquillian.forge.arquillian-plugin:1.0.3-SNAPSHOT:1.0.0-SNAPSHOT-42907982-d02e-4a1d-8ea5-8e66c8013fde<br>
                &gt; [no project] forge-distribution-1.1.1-SNAPSHOT $
                exit<br>
                &gt;<br>
                &gt;<br>
                &gt; real    0m9.721s<br>
                &gt; user    0m26.533s<br>
                &gt; sys     0m0.433s<br>
                &gt;<br>
                &gt; After optimization:<br>
                &gt; ~forge1.1.1-weld1.2&gt; time ((echo forge
                list-plugins; echo exit;)| bin/forge)<br>
                &gt; Using Forge at
                /raid/home/thomas/java/forge1.1.1-weld1.2<br>
                &gt;     _____<br>
                &gt;    |  ___|__  _ __ __ _  ___<br>
                &gt;    | |_ / _ \| `__/ _` |/ _ \  \\<br>
                &gt;    |  _| (_) | | | (_| |  __/  //<br>
                &gt;    |_|  \___/|_|  \__, |\___|<br>
                &gt;                    |___/<br>
                &gt;<br>
                &gt; [no project] forge1.1.1-weld1.2 $ forge
                list-plugins<br>
                &gt;
org.richfaces.forge.richfaces-forge-plugin:1.0.5.Final:1.0.0-SNAPSHOT-b1a6ebed-462f-40e1-ac08-82f927489301<br>
                &gt;
com.ocpsoft.forge.prettyfaces-plugin:1.0.2.Final:1.0.0-SNAPSHOT-c6b071ad-a6df-4112-8fff-82ecccd003fb<br>
                &gt;
org.jboss.hibernate.forge.hibernate-tools-plugin:1.0.5.Final:1.0.0-SNAPSHOT-afb1da29-a99f-4dd7-b020-5f3ba6073cde<br>
                &gt;
org.arquillian.forge.arquillian-plugin:1.0.3-SNAPSHOT:1.0.0-SNAPSHOT-42907982-d02e-4a1d-8ea5-8e66c8013fde<br>
                &gt; [no project] forge1.1.1-weld1.2 $ exit<br>
                &gt;<br>
                &gt;<br>
                &gt; real    0m6.016s<br>
                &gt; user    0m14.482s<br>
                &gt; sys     0m0.449s<br>
                &gt;<br>
                &gt;<br>
                &gt;
*************************************************************************************<br>
                &gt; Issue 2.: double starting of Weld container<br>
                &gt; I admit that I do not fully understand, what I did
                and if this really<br>
                &gt; provides the full solution, but it worked and
                produced a fully<br>
                &gt; functional Forge instance.<br>
                &gt;<br>
                &gt; I tried to restructure the Bootstrap logic a bit:<br>
                &gt;<br>
                &gt;                initializeClassloader();<br>
                &gt;                WeldContainer container =
                weld.initialize();<br>
                &gt;                manager =
                container.getBeanManager();<br>
                &gt;<br>
                &gt;                try<br>
                &gt;                {<br>
                &gt;                   loadPlugins();<br>
                &gt;                   weld.reInitialize();<br>
                &gt;<br>
                &gt; where initializeClassloader already uses the
                CompositeClassloader:<br>
                &gt;<br>
                &gt;    private static void initializeClassloader() {<br>
                &gt;        ModuleLoader moduleLoader =
                Module.getBootModuleLoader();<br>
                &gt;<br>
                &gt;        CompositeClassLoader composite = new
                CompositeClassLoader();<br>
                &gt;
                composite.add(Module.forClassLoader(Bootstrap.class.getClassLoader(),<br>
                &gt; true).getClassLoader());<br>
                &gt;<br>
                &gt;      
                 Thread.currentThread().setContextClassLoader(composite);<br>
                &gt;    }<br>
                &gt;<br>
                &gt; and loadPlugins simply adds more classloaders:<br>
                &gt;<br>
                &gt;          CompositeClassLoader composite =<br>
                &gt;
                (CompositeClassLoader)Thread.currentThread().getContextClassLoader();<br>
                &gt;          for (PluginEntry plugin : toLoad)<br>
                &gt;          {<br>
                &gt;                Module module =<br>
                &gt;
moduleLoader.loadModule(ModuleIdentifier.fromString(plugin.toModuleId()));<br>
                &gt;              
                 composite.add(module.getClassLoader());<br>
                &gt;<br>
                &gt;<br>
                &gt; This way the classes are already available in the
                correct classloader<br>
                &gt; for the later ModularWeld.reInitialize():<br>
                &gt;<br>
                &gt;     public void reInitialize() {<br>
                &gt;         bootstrap.revisit();<br>
                &gt;         bootstrap.validateBeans();<br>
                &gt;         bootstrap.endInitialization();<br>
                &gt;     }<br>
                &gt;<br>
                &gt; Where Bootstrap.revisit simply revisits the
                BeanDeployments which have<br>
                &gt; been newly found:<br>
                &gt;<br>
                &gt;     private static class DeploymentVisitor {<br>
                &gt; .....<br>
                &gt;         public Map&lt;BeanDeploymentArchive,
                BeanDeployment&gt; revisit() {<br>
                &gt;             for (BeanDeploymentArchive archvive :<br>
                &gt; deployment.getBeanDeploymentArchives()) {<br>
                &gt;                 if<br>
                &gt;
                (!managerAwareBeanDeploymentArchives.containsKey(archvive))
                {<br>
                &gt;                     visit(archvive,
                managerAwareBeanDeploymentArchives,<br>
                &gt; new HashSet&lt;BeanDeploymentArchive&gt;(), true);<br>
                &gt;                     BeanDeployment bd =<br>
                &gt; managerAwareBeanDeploymentArchives.get(archvive);<br>
                &gt;                     bd.createBeans(environment);<br>
                &gt;                     bd.deployBeans(environment);<br>
                &gt;                 }<br>
                &gt;             }<br>
                &gt;             return
                managerAwareBeanDeploymentArchives;<br>
                &gt;         }<br>
                &gt;<br>
                &gt;<br>
                &gt;
*************************************************************************************<br>
                &gt; Issue 3.: invocation of potentially expensive
                operations on<br>
                &gt; non-annotated or annotation-relevant classes<br>
                &gt; The current BeanDeployer simply invokes
                ProcessAnnotatedType on any<br>
                &gt; class, w/o checking, if this class is used by any
                annotation anywhere.<br>
                &gt; By jandexing all jars and assembling the dispersed
                Jandex indices during<br>
                &gt; URLScanning we could reduce the expensive WeldClass
                conversion.<br>
                &gt;<br>
                &gt; Original:<br>
                &gt;     11.108 ms - 2.024 inv.
                org.jboss.weld.bootstrap.BeanDeployer.addClass<br>
                &gt; Jandex-aware:<br>
                &gt;     4.721 ms - 990 inv.
                org.jboss.weld.bootstrap.BeanDeployer.addClass<br>
                &gt;<br>
                &gt; Possible solution:<br>
                &gt;     - 1. URLHandler scans Jandex file locations<br>
                &gt;<br>
                &gt;     protected void addToDiscovered(String name, URL
                url) {<br>
                &gt; ...<br>
                &gt;         } else if (name.endsWith(JANDEX_IDX)) {<br>
                &gt;             discoveredJandexIndexUrls.add(url);<br>
                &gt;         }<br>
                &gt;     }<br>
                &gt;<br>
                &gt;     - 2. URLScanner assembles all found Jandex
                indices:<br>
                &gt;<br>
                &gt;         List&lt;Index&gt; jandexIndexes = new
                ArrayList&lt;Index&gt;();<br>
                &gt;         for (URL jandexUrl :
                handler.getDiscoveredJandexIndexUrls()) {<br>
                &gt;                 jandexIndexes.add(new<br>
                &gt; IndexReader(jandexUrl.openStream()).read());<br>
                &gt;         }<br>
                &gt;<br>
                &gt;     - 3. BeanDeployer does expensive WeldClass
                loading only if class is<br>
                &gt; mentioned in the Jandex indices<br>
                &gt;     - 3.a. first collapse the Jandex-indices to a
                simple list of class<br>
                &gt; names:<br>
                &gt;         for (Index jandexIndex : jandexIndexes) {<br>
                &gt;             for (List&lt;AnnotationInstance&gt;
                aiList :<br>
                &gt; jandexIndex.getAnnotations().values()) {<br>
                &gt;                 for (AnnotationInstance ai :
                aiList) {<br>
                &gt;                     AnnotationTarget at =
                ai.target();<br>
                &gt;                     if (at instanceof ClassInfo) {<br>
                &gt;
                jandexAnnotated.add(((ClassInfo)at).name().toString());<br>
                &gt;                     } else if (at instanceof
                MethodInfo) {<br>
                &gt;
jandexAnnotated.add(((MethodInfo)at).declaringClass().name().toString());<br>
                &gt;                     } else if (at instanceof
                MethodParameterInfo) {<br>
                &gt;
jandexAnnotated.add(((MethodParameterInfo)at).method().declaringClass().name().toString());<br>
                &gt;                     } else if (at instanceof
                FieldInfo) {<br>
                &gt;
                jandexAnnotated.add(((FieldInfo)at).declaringClass().name().toString());<br>
                &gt;                     }<br>
                &gt;                 }<br>
                &gt;             }<br>
                &gt;         }<br>
                &gt;<br>
                &gt;     - 3.b. query the aggregated list of
                Jandex-aware classes<br>
                &gt;<br>
                &gt;     public BeanDeployer addClass(String className)
                {<br>
                &gt;         Class&lt;?&gt; clazz =
                loadClass(className);<br>
                &gt;         if (clazz != null &amp;&amp;
                isBeanCandidate(clazz) &amp;&amp;<br>
                &gt; jandexContains(className)) {<br>
                &gt;             WeldClass&lt;?&gt; weldClass =
                loadWeldClass(clazz);<br>
                &gt;<br>
                &gt;<br>
                &gt; Yet unsolved issue is the question, wheter an index
                is found in the<br>
                &gt; corresponding Archive or not, so not to enforce
                Jandexing _all_ jars for<br>
                &gt; Forge.<br>
                &gt; Jandexing is very easy though: jandex -m
                &lt;jar&gt;<br>
                &gt;<br>
                &gt; The abovementioned solutions have been implemented
                and produced a<br>
                &gt; functional and correctly working Forge instance.<br>
                &gt; AFAICS the solution for issue 2 could be a means to
                solve the reloading<br>
                &gt; of plugins too, but I didn't implement and verify
                this.<br>
                &gt;<br>
                &gt; The sources are not available online, because the
                current implementation<br>
                &gt; is highly fragile and not safe for simple usage -
                too many changes in<br>
                &gt; APIs, dependencies, etc.<br>
                &gt;<br>
                &gt; Comments welcome!<br>
                &gt;<br>
                &gt; Regards,<br>
                &gt; Thomas<br>
                &gt;<br>
                &gt; _______________________________________________<br>
                &gt; forge-dev mailing list<br>
                &gt; <a moz-do-not-send="true"
                  href="mailto:forge-dev@lists.jboss.org">forge-dev@lists.jboss.org</a><br>
                &gt; <a moz-do-not-send="true"
                  href="https://lists.jboss.org/mailman/listinfo/forge-dev"
                  target="_blank">https://lists.jboss.org/mailman/listinfo/forge-dev</a><br>
                <br>
                _______________________________________________<br>
                forge-dev mailing list<br>
                <a moz-do-not-send="true"
                  href="mailto:forge-dev@lists.jboss.org">forge-dev@lists.jboss.org</a><br>
                <a moz-do-not-send="true"
                  href="https://lists.jboss.org/mailman/listinfo/forge-dev"
                  target="_blank">https://lists.jboss.org/mailman/listinfo/forge-dev</a><br>
              </div>
            </div>
          </blockquote>
        </div>
        <br>
        <br clear="all">
        <br>
        -- <br>
        Lincoln Baxter, III<br>
        <a moz-do-not-send="true" href="http://ocpsoft.org"
          target="_blank">http://ocpsoft.org</a><br>
        "Simpler is better."<br>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
forge-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:forge-dev@lists.jboss.org">forge-dev@lists.jboss.org</a>
<a class="moz-txt-link-freetext" href="https://lists.jboss.org/mailman/listinfo/forge-dev">https://lists.jboss.org/mailman/listinfo/forge-dev</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>