Re: [PATCH] possible speed enhancement to JspServlet.java
The numbers I got were for a fairly specific application. The page request I was making did includes of 10 jsp's in total (which would account for the difference in my results and yours I think). I really like the idea of having a server vs development setting. I'll take a look at that this morning. Might it be a good idea to have a manual way to force a JSP reload in a production environment? I see reading your comment that you can reload the JSP by reloading the web application, but I'm not sure the container I'm using has that option available in a straight forward manner. Something simple like a parameter in the URL like jasper_jsp_reload=true would make it relatively easy to modify a production system without taking it off-line even briefly. Remy Maucherat wrote: Thanks for the comments Kin-Man. Given those comments and a look at the jasper2 code I have come up with the patch below. After profiling jasper2 I saw that there was indeed a speed improvement over Jasper. However the excessive creation of File objects and getting files from URL's was still a problem. I did as you suggested and used the JspServletWrapper object to hold all of the required data. As well I set up this version to fall back to reading JSP's from a URL if reading the File object doesn't work. I found in my testing that the jasper engine used ~15% of the request time in loadJSP, jasper2 used ~12%, and my change uses ~1%. The only thing my code does not do is force a reload of the .class file if it is deleted. My code only causes a recompile if the jsp changes. I can look into modifying it to handle this situation as well if required. I look forward to your feedback. A much simpler solution would be to allow disabling reloading altogether for production systems. I've committed a patch which does that. That way, loadJSP can use 0% and everything stays very simple. What do you think ? Remy -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- Duncan McLean Hummingbird Ltd. 613-548-4355 x1539 http://www.hummingbird.com -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: [PATCH] possible speed enhancement to JspServlet.java
The numbers I got were for a fairly specific application. The page request I was making did includes of 10 jsp's in total (which would account for the difference in my results and yours I think). I really like the idea of having a server vs development setting. I'll take a look at that this morning. Might it be a good idea to have a manual way to force a JSP reload in a production environment? I see reading your comment that you can reload the JSP by reloading the web application, but I'm not sure the container I'm using has that option available in a straight forward manner. Something simple like a parameter in the URL like jasper_jsp_reload=true would make it relatively easy to modify a production system without taking it off-line even briefly. That kind of setting could be used for a DOS attack (making the server recompile pages all the time). It should rather be something like check_modified=true. Actually, I'll have to check what the precompile attribte does. It may already be doing that; otherwise, I'll probably add the other. Remy -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: [PATCH] possible speed enhancement to JspServlet.java
Thanks for the comments Kin-Man. Given those comments and a look at the jasper2 code I have come up with the patch below. After profiling jasper2 I saw that there was indeed a speed improvement over Jasper. However the excessive creation of File objects and getting files from URL's was still a problem. I did as you suggested and used the JspServletWrapper object to hold all of the required data. As well I set up this version to fall back to reading JSP's from a URL if reading the File object doesn't work. I found in my testing that the jasper engine used ~15% of the request time in loadJSP, jasper2 used ~12%, and my change uses ~1%. The only thing my code does not do is force a reload of the .class file if it is deleted. My code only causes a recompile if the jsp changes. I can look into modifying it to handle this situation as well if required. I look forward to your feedback. Kin-Man Chung wrote: Duncan, I looked at your patch carefully, looks like Remy's work on jasper2 already addressed the issues that you are trying to solved. In fact, Remy only creates a compiler for the container, whereas you would have created a compiler for each jsp page. OTOH, you save the modification date for each page in a hashtable, so is potentially faster when checking whether a jsp needs to be send to the compiler. I may incoporate your idea on this one later, maybe reusing the JspServletWrapper class instead of using another hashtabl, since that **IS** a per page object. Thanks again for the patch. If you wish, you should try running with japser2, and compare its performance with the one you patched. --- JspServlet.java.origMon Apr 29 20:50:33 2002 +++ JspServlet.java Mon Apr 29 17:34:28 2002 @@ -129,6 +129,11 @@ JspCompilationContext ctxt = null; String outDir = null; long available = 0L; + + FilejspFile = null; +long nLastModified = 0; +boolean bCompiling = false; + boolean bInWar = false; JspServletWrapper(String jspUri, boolean isErrorPage) { this.jspUri = jspUri; @@ -276,6 +281,103 @@ if (theServlet != null) theServlet.destroy(); } + + /** + * This function takes the relative name of a jsp file and tries + * to determine whether it has changed since the last time this + * was called. + */ + private boolean hasJspChanged() { + try { + //get the last time the file was modified and the + //last time it was modified that we compiled + long nMod = getModifiedTime(); + + //if we have not compiled before, or the file has changed. + if (nMod == 0 || (nLastModified != nMod !isCompiling(nMod))) { + return true; + } + + waitForCompile(); + + return false; + } catch(IOException ioEx) { + //ignore so that the normal logic will kick in. + } + + return true; + } + + /** + * Gets the time that a particular JSP file was last modified. + */ + private long getModifiedTime() + throws IOException { + if (bInWar) { + return nLastModified; + } + + if (jspFile == null) + { + //if is FAR faster to create a file object and get its + //last modified time than to open a URL connection to + //the file and get the last modified time that way. + String strPath = getServletConfig().getServletContext().getRealPath(jspUri); + jspFile = new File(strPath); + } + + try { + //this will return 0 if the file does not exist. + long nRet = jspFile.lastModified(); + + if (nRet != 0){ + return nRet; + } + } catch(Exception ex) { + //ignore and fall back. + } + + try { + URL jspUrl = ctxt.getResource(jspUri); + if (jspUrl != null) + { + bInWar = true; + return jspUrl.openConnection().getLastModified(); + } + } catch (Exception e) { + //ignore + } + + return 0;
Re: [PATCH] possible speed enhancement to JspServlet.java
Thanks for the comments Kin-Man. Given those comments and a look at the jasper2 code I have come up with the patch below. After profiling jasper2 I saw that there was indeed a speed improvement over Jasper. However the excessive creation of File objects and getting files from URL's was still a problem. I did as you suggested and used the JspServletWrapper object to hold all of the required data. As well I set up this version to fall back to reading JSP's from a URL if reading the File object doesn't work. I found in my testing that the jasper engine used ~15% of the request time in loadJSP, jasper2 used ~12%, and my change uses ~1%. The only thing my code does not do is force a reload of the .class file if it is deleted. My code only causes a recompile if the jsp changes. I can look into modifying it to handle this situation as well if required. I look forward to your feedback. I don't agree with those numbers. Accoding to my testing it is far less significant. I got some very significant increase in the throughtput numbers to confirm that (using index.jsp). Remy -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: [PATCH] possible speed enhancement to JspServlet.java
Thanks for the comments Kin-Man. Given those comments and a look at the jasper2 code I have come up with the patch below. After profiling jasper2 I saw that there was indeed a speed improvement over Jasper. However the excessive creation of File objects and getting files from URL's was still a problem. I did as you suggested and used the JspServletWrapper object to hold all of the required data. As well I set up this version to fall back to reading JSP's from a URL if reading the File object doesn't work. I found in my testing that the jasper engine used ~15% of the request time in loadJSP, jasper2 used ~12%, and my change uses ~1%. The only thing my code does not do is force a reload of the .class file if it is deleted. My code only causes a recompile if the jsp changes. I can look into modifying it to handle this situation as well if required. I look forward to your feedback. A much simpler solution would be to allow disabling reloading altogether for production systems. I've committed a patch which does that. That way, loadJSP can use 0% and everything stays very simple. What do you think ? Remy -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: [PATCH] possible speed enhancement to JspServlet.java
Duncan, I looked at your patch carefully, looks like Remy's work on jasper2 already addressed the issues that you are trying to solved. In fact, Remy only creates a compiler for the container, whereas you would have created a compiler for each jsp page. OTOH, you save the modification date for each page in a hashtable, so is potentially faster when checking whether a jsp needs to be send to the compiler. I may incoporate your idea on this one later, maybe reusing the JspServletWrapper class instead of using another hashtabl, since that **IS** a per page object. Thanks again for the patch. If you wish, you should try running with japser2, and compare its performance with the one you patched. Date: Fri, 19 Apr 2002 16:58:54 -0700 (PDT) From: Kin-Man Chung [EMAIL PROTECTED] Subject: Re: [PATCH] possible speed enhancement to JspServlet.java To: [EMAIL PROTECTED] MIME-version: 1.0 Content-transfer-encoding: 7BIT Content-MD5: Pd6UqZXWO7AIRUPw9V+AAQ== Delivered-to: mailing list [EMAIL PROTECTED] Mailing-List: contact [EMAIL PROTECTED]; run by ezmlm X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N List-Post: mailto:[EMAIL PROTECTED] List-Subscribe: mailto:[EMAIL PROTECTED] List-Unsubscribe: mailto:[EMAIL PROTECTED] List-Help: mailto:[EMAIL PROTECTED] List-Id: Tomcat Developers List tomcat-dev.jakarta.apache.org Thank you for the patch! It looks interesting! I'll definitely look at it carefully and apply it to jasper or jasper2 when I have time, most probably sometime next week. Date: Fri, 19 Apr 2002 17:09:49 -0400 From: Duncan McLean [EMAIL PROTECTED] Subject: [PATCH] possible speed enhancement to JspServlet.java To: Tomcat Developers List [EMAIL PROTECTED] MIME-version: 1.0 Content-transfer-encoding: 7bit X-Accept-Language: en,pdf Delivered-to: mailing list [EMAIL PROTECTED] Mailing-List: contact [EMAIL PROTECTED]; run by ezmlm User-Agent: Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2 X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N List-Post: mailto:[EMAIL PROTECTED] List-Subscribe: mailto:[EMAIL PROTECTED] List-Unsubscribe: mailto:[EMAIL PROTECTED] List-Help: mailto:[EMAIL PROTECTED] List-Id: Tomcat Developers List tomcat-dev.jakarta.apache.org I'm new to this list (and the jasper code), so please let me know if I've submitted this incorrectly. I was doing some profiling of the server side environment that I work on and noticed that quite a bit of time was being used in the JSP engine. After further investigation I noticed that each JSP request that comes into the jasper engine generates a new compiler object and attempt at compilation. As much as 15% of the time of a JSP request is wasted this way. The change I made attempts to read the last modified date from the JSP file being request. A comparison is made against known last modified time for the current compiled version, if they are different then the code flows as it used to. If the times are the same then the rest of loadJSP is skipped. In my test application which relies on calling ~10 jsp files to generate a single page I found a speed improvement of ~25-50ms (on a PIII 650). There may be better ways to do this. I concentrated my fix here because it is where the profiler said the problem was. One drawback of the code I'm submitting is that if there are a large number of JSP's the Hashtable I use to store information may get large. However I can't see that being a problem until a site has 10,000 jsp's. The change I'm submitting may not be the correct way to approach the problem. Either way I think this is an issue that deserves some attention so if someone can suggest a better fix please do. -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED] -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
Re: [PATCH] possible speed enhancement to JspServlet.java
I'm new to this list (and the jasper code), so please let me know if I've submitted this incorrectly. I was doing some profiling of the server side environment that I work on and noticed that quite a bit of time was being used in the JSP engine. After further investigation I noticed that each JSP request that comes into the jasper engine generates a new compiler object and attempt at compilation. As much as 15% of the time of a JSP request is wasted this way. The change I made attempts to read the last modified date from the JSP file being request. A comparison is made against known last modified time for the current compiled version, if they are different then the code flows as it used to. If the times are the same then the rest of loadJSP is skipped. In my test application which relies on calling ~10 jsp files to generate a single page I found a speed improvement of ~25-50ms (on a PIII 650). There may be better ways to do this. I concentrated my fix here because it is where the profiler said the problem was. One drawback of the code I'm submitting is that if there are a large number of JSP's the Hashtable I use to store information may get large. However I can't see that being a problem until a site has 10,000 jsp's. The change I'm submitting may not be the correct way to approach the problem. Either way I think this is an issue that deserves some attention so if someone can suggest a better fix please do. I did a lot of opimizations in the Jasper 2 (jakarta-tomcat-connectors/jasper2) JspServlet. I don't know how much is addressed by the patch that I already did. Could you check it out ? Thanks, Remy -- To unsubscribe, e-mail: mailto:[EMAIL PROTECTED] For additional commands, e-mail: mailto:[EMAIL PROTECTED]
[PATCH] possible speed enhancement to JspServlet.java
I'm new to this list (and the jasper code), so please let me know if I've submitted this incorrectly. I was doing some profiling of the server side environment that I work on and noticed that quite a bit of time was being used in the JSP engine. After further investigation I noticed that each JSP request that comes into the jasper engine generates a new compiler object and attempt at compilation. As much as 15% of the time of a JSP request is wasted this way. The change I made attempts to read the last modified date from the JSP file being request. A comparison is made against known last modified time for the current compiled version, if they are different then the code flows as it used to. If the times are the same then the rest of loadJSP is skipped. In my test application which relies on calling ~10 jsp files to generate a single page I found a speed improvement of ~25-50ms (on a PIII 650). There may be better ways to do this. I concentrated my fix here because it is where the profiler said the problem was. One drawback of the code I'm submitting is that if there are a large number of JSP's the Hashtable I use to store information may get large. However I can't see that being a problem until a site has 10,000 jsp's. The change I'm submitting may not be the correct way to approach the problem. Either way I think this is an issue that deserves some attention so if someone can suggest a better fix please do. - * The JSP engine (a.k.a Jasper). + * The JSP engine (a.k.a Jasper)! * * The servlet container is responsible for providing a * URLClassLoader for the web application context Jasper @@ -231,6 +232,32 @@ theServlet.destroy(); } } + + /** + * This class stores data on the last time a jsp was modified, and + * whether it is currently being compiled. + */ + class JspModfificationData { + longnLastModified = 0; + boolean bCompiling = false; + + /** + * This function determines if the jsp this represents is + * already being compiled. If it is not then the new modification + * time is saved, and false is returned meaning the caller is + * allowed to compile the JSP. + */ + synchronized boolean isCompiling(long nNewModTime) { + if (bCompiling) { + return true; + } + + nLastModified = nNewModTime; + bCompiling = true; + + return false; + } + } protected ServletContext context = null; @@ -242,6 +269,7 @@ protected String serverInfo; private PermissionCollection permissionCollection = null; private CodeSource codeSource = null; +private Hashtable htModificationData = new Hashtable(); static boolean firstTime = true; @@ -473,6 +501,9 @@ serviceJspFile(request, response, jspUri, null, precompile); } catch (RuntimeException e) { throw e; +} catch (JasperError ex) { +response.setContentType(text/html); +response.getWriter().print(ex.getMessage()); } catch (ServletException e) { throw e; } catch (IOException e) { @@ -509,86 +540,172 @@ boolean loadJSP(String jspUri, String classpath, boolean isErrorPage, HttpServletRequest req, HttpServletResponse res) throws JasperException, FileNotFoundException -{ - // First check if the requested JSP page exists, to avoid creating - // unnecessary directories and files. - if (context.getResourceAsStream(jspUri) == null) - throw new FileNotFoundException(jspUri); - - JspServletWrapper jsw=(JspServletWrapper) jsps.get(jspUri); - if( jsw==null ) { - throw new JasperException(Can't happen - JspServletWrapper=null); - } -File outDir = null; -try { -URL outURL = options.getScratchDir().toURL(); -String outURI = outURL.toString(); -if( outURI.endsWith(/) ) -outURI = outURI + jspUri.substring(1,jspUri.lastIndexOf(/)+1); -else -outURI = outURI + jspUri.substring(0,jspUri.lastIndexOf(/)+1);; -outURL = new URL(outURI); -outDir = new File(outURL.getFile()); -if( !outDir.exists() ) { -outDir.mkdirs(); -} -} catch(Exception e) { -throw new JasperException(No output directory: + e.getMessage()); -} - boolean firstTime = jsw.servletClass == null; -JspCompilationContext ctxt = new JspEngineContext(parentClassLoader, classpath, - context, jspUri, outDir.toString() + File.separator, - isErrorPage, options, - req, res); - boolean outDated