tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Berglas, Anthony" <aberg...@rsasecurity.com>
Subject Fix to Tomcat Jasper slow .tag compilation problem.
Date Mon, 29 Oct 2007 23:45:10 GMT
As described in a previous post to users list, Jasper is *extremely*
slow at compiling JSPs that reference .tag files packaged in a .jar.
Tens of seconds every time you touch a new .jsp for the first time.
Almost unusable if you use .tags extensively, as I do.

The following few lines is a simple hack to fix this.  The added code is
marked between // -------- AJB markers.  It effectively turns off the
timestamp checking on .jar files.

This does NOT actually introduce a bug.  There is an existing bug in
that .jsp files are not automatically recompiled if any .tags in .jars
are changed.  So you need to purge work/ when changing .tags in either
case.  A proper fix would be to check dependencies properly, at least to
the .jar file itself.  But the proposed fix is *much* better that the
existing behavior.

COULD SOMEBODY PLEASE ARRANGE FOR THIS CODE TO BE ADDED TO THE CURRENT
SUBVERSION REPOSITORY? 

Outstanding is to make the compilation of .tags themselves much faster,
not tens of seconds.  To do that one needs to call the Java compiler
once at the end for all the .tags, rather than once for each individual
.tag which is *much* slower.

I must admit that I got rather lost reading the Jasper source, with all
the contexts etc.  Some better comments on the classes describing their
relationships to each other would be most helpful.

Thanks,

Anthony

PS. Precompiling would not help.

1. Precompiling JSPs with .tag files is broken in Jasper, if tags call
other tags.

2. If it were fixed I would imagine that it would still recompile each
tag over and over again.  A precompile of a few dozen JSPs would then
take hours.

The next issue to fix is the very slow one tag at a time Java compiles.
Then the dependencies can be looked at, but the code is fairly complex.

My enthusiasm for addressing these issues is dependent on the community
being able to incorporate my fixes into the core.  Otherwise I fork
Tomcat, not a good idea.  



// Tomcat 6.0.10 Src deployed version.

public class JspCompilationContext {...

    public void compile() throws JasperException, FileNotFoundException
{
        createCompiler();

        // ------------ begin AJB
        // Hack to stop .tag files that are packaged in .jars being
recompiled for every single .jsp that uses them.
        // The hack means that .tag files will not be automatically
recompiled if they change -- you need to delete work area.
        // But that was actually an existing bug -- .jsps are not
dependent on the .tag .jars so the work area needed deleting anyway.
        // (Outstanding is to compile multiple .tags in one pass and so
make the process Much faster.)
        boolean outDated;
        if (isPackagedTagFile) outDated = ! new
File(getClassFileName()).exists();
        else outDated = jspCompiler.isOutDated();
//        AjbLog.log("### Compiler.compile " + jspUri + " pkgTagFile " +
isPackagedTagFile + " outDated " + outDated + " " + getClassFileName());
        if (outDated) {
//     if (isPackagedTagFile || jspCompiler.isOutDated()) {
//     ---------------- end AJB
            try {
                jspCompiler.removeGeneratedFiles();
                jspLoader = null;
                jspCompiler.compile();
                jsw.setReload(true);
                jsw.setCompilationException(null);
            } catch (JasperException ex) {
                // Cache compilation exception
                jsw.setCompilationException(ex);
                throw ex;
            } catch (Exception ex) {
                JasperException je = new JasperException(
 
Localizer.getMessage("jsp.error.unable.compile"),
                            ex);
                // Cache compilation exception
                jsw.setCompilationException(je);
                throw je;
            }
        }
    }



PREVIOUS PROBLEM DESCRITPIN POSTING FROM USER LIST

PROBLEM

JSPs that make use of custom .tag files can be very slow to compile --
several tens of seconds for each .jsp.  It takes longer to compile a
single .jsp than the entire Tomcat 6 & Jasper source. 

The application uses .tag files fairly heavily to provide boiler plate
text for headings, menus, buttons, input fields etc.  Works fairly well
apart from the painfully slow compiles. 

PROFILING AND TRACING RESULTS

1. Tomcat is recompiling all the .tags for each .jsp.  So the .tag
libraries are being needlessly recompiled many, many times.  (Ie. if
foo.jsp calls bar.tag once, and then baz.jsp calls bar.tag three times,
then bar.tag is compiled twice, not once or four times.) 

2. The javac compiles are very slow, despite there being relatively
little java code to compile.  (About60% of total time.) This is probably
because the compiler is being invoked once for each .tag, rather than
just once for all the generated .java files.

3. The parsing is relatively slow (20% of total time) but not the
bottleneck.  Other aspects such as generating the .java are very fast.

FIXES AND WORK AROUNDS 

The first recompiling problem only presents when the .tag files are
bundled in a .jar.  We want to separate the .tag library from the
application, and we get better IDE support from a .jar with a .tld.  
One approach is to just fix Jasper to look at the .jar time for
dependency checking.  But this is only useful if the fix would be back
ported to the main tree. 

Another is to unbundled the .tag files, and use more complex build
scripts to merge the library with the application.  Would prefer not to
do that.
For the compiles it should be possible to have Jasper pre-generate .java
files in one pass, and then compile explicitly in another.   

However there is a bug in Jasper that prevents pre-compilation of .tags
that call other .tags that also need to be compiled.  Apparently one
needs to write a dummy .jsp that calls the leaf .tags one at a time to
prevent this.  (Or fix Jasper.)Also, prefer not to do things that are
Tomcat specific, want a portable war file at the end of the day.

TRACE 

I have attached the trace of a run.  The page is a simple form with 8
fields.  Times in milli seconds from the beginning ofthe run.  The list
is indented per the call stack.  generate Class is the method that calls
the Javac compiler, and totals of this are collected at the end.  The
recursion is due to .tags calling .tags.  I can provide people with the
traced copy of Jasper source if they are interested to see exactly what
the traces mean.

--
Dr Anthony Berglas 
Ph. +61 7 3227 4410
Mob. +61 44 838 8874
ABerglas@RSA.com; Anthony@Berglas.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message