By the way ...

Cool beans!

geir


Kent Johnson wrote:
> 
> I am taking a stab at profiling Velocity using Jinsight (from IBM alphaWorks).
> 
> For a test case, I basically turned Jon's speed test servlet into a
> standalone program by liberally cutting and pasting from
> Example.java. Output goes to a StringWriter. I call the whole mess
> twice so the second time Velocity.init() should be fast and all the
> templates should be cached. I am focusing on the second-time
> performance.
> 
> I have some preliminary results and some questions.
> 
> - The big news is that nothing jumps out as a major time sink. This
> is good because it means there are no major bloopers, but bad because
> there is nothing to cherry pick.
> 
> - ASTReference.render() is called a lot (I guess that's no surprise).
> It builds its output by using String concatenation, for example
>    writer.write(NodeUtils.specialText(getFirstToken()) + prefix +
> value.toString());
> 
> This creates a temp StringBuffer, appends three strings to it and
> converts using toString().
> 
> Changing that one line to the three separate writes
>              writer.write(NodeUtils.specialText(getFirstToken()));
>              writer.write(prefix);
>              writer.write(value.toString());
> 
> saves about 17% of the time spent in this method. All the other uses
> of + in this method can be changed too.
> 
> This assumes that writes are fast, for StringWriter they are,
> probably for BufferedWriter too.
> 
> Some minor improvements:
> 
> - In Parse.render(), the check of the template stack depth is pretty
> expensive. It takes about 20% of the time of the whole method! The
> time is split between
> InternalContextAdapterImpl.getTemplateNameStack() and
> Runtime.getInt(). I rewrote Configuration.getInteger() to avoid
> creating an Integer and that helps a little.
> 
> - ResourceManager.getResource() calls
> globalCache.containsKey(resourceName) followed by globalCache.get()
> if the containsKey succeeds. I replaced these with just a get().
> 
> OK, those are the easy ones. Here are some other possibilities:
> 
> - About 40% of the time is spent in ASTReference.execute(), any
> improvements here could have a big effect. One thing that stands out
> here is the overhead of layering through InternalContextAdapter ->
> AbstractContext -> VelocityContext -> HashMap to actually get a value
> or a method.
> 
> - I am seeing a few places where caching a value in a node could be
> beneficial. For example, ASTNumberLiteral.value() parses its integer
> value on each call. This is a relatively expensive operation. Another
> example is ASTSetDirective.render() which calls String.substring() to
> get the identifier name.
> 
> I know that caching can be problematic in multi-threaded code, so I'm
> not comfortable caching a value in a node at render time. I was
> wondering if there is any time during parsing where the cached value
> can be computed? It would have to be after the child nodes have been
> added.
> 
> ASTNumberLiteral could cache the integer value, that at least avoids
> the issues with cached references. Can anyone tell me if this code is
> thread-safe? Or how to make it thread-safe?
> 
>      private boolean cached = false;
>      private int cachedValue;
> 
>      public Object value( InternalContextAdapter context)
>      {
>         if (!cached) {
>                 cachedValue = Integer.parseInt(getFirstToken().image);
>                 cached = true;
>         }
>          return new Integer(cachedValue);
>      }
> 
> Finally, here are diffs for ASTReferenceNode.java, Configuration.java
> and ResourceManager.java.
> 
> Kent Johnson                   Transparent Language, Inc.
> [EMAIL PROTECTED]       http://www.transparent.com
> 
> --- d:/dev/jakarta-velocity/old/ASTReference.java   Wed Apr 18 12:03:15 2001
> +++ ASTReference.java   Wed Apr 18 14:51:45 2001
> @@ -215,10 +215,19 @@
>           if ( escaped )
>           {
>               if ( value == null )
> -                writer.write( NodeUtils.specialText(getFirstToken())
> + prefix + "\\" +  nullString );
> +            {
> +                writer.write( NodeUtils.specialText(getFirstToken()) );
> +                writer.write( prefix );
> +                writer.write( "\\" );
> +                writer.write( nullString );
> +            }
>               else
> -                writer.write( NodeUtils.specialText(getFirstToken())
> + prefix + nullString );
> -
> +            {
> +                writer.write( NodeUtils.specialText(getFirstToken()) );
> +                writer.write( prefix );
> +                writer.write( nullString );
> +            }
> +
>               return true;
>           }
> 
> @@ -232,14 +241,19 @@
>                *  write prefix twice, because it's shmoo, so the \
> don't escape each other...
>                */
> 
> -            writer.write(NodeUtils.specialText(getFirstToken()) +
> prefix + prefix + nullString);
> +           writer.write( NodeUtils.specialText(getFirstToken()) );
> +           writer.write( prefix );
> +           writer.write( prefix );
> +           writer.write( nullString );
> 
>               if (referenceType != QUIET_REFERENCE &&
> Runtime.getBoolean(
> RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, true) )
>                   Runtime.warn(new ReferenceException("reference :
> template = " + context.getCurrentTemplateName(), this));
>           }
>           else
>           {
> -            writer.write(NodeUtils.specialText(getFirstToken()) +
> prefix + value.toString());
> +            writer.write(NodeUtils.specialText(getFirstToken()));
> +            writer.write(prefix);
> +            writer.write(value.toString());
>           }
> 
>           return true;
> 
> --- d:/dev/jakarta-velocity/old/Configuration.java  Wed Apr 18 13:52:53 2001
> +++ Configuration.java  Wed Apr 18 13:58:05 2001
> @@ -1485,7 +1485,10 @@
>       public int getInteger(String key,
>                             int defaultValue)
>       {
> -        return getInteger(key, new Integer(defaultValue)).intValue();
> +        Integer i = getInteger(key, null);
> +        if (i == null)
> +           return defaultValue;
> +        return i.intValue();
>       }
> 
>       /**
> 
> --- d:/dev/jakarta-velocity/old/ResourceManager.java    Wed Apr 18
> 14:19:48 2001
> +++ ResourceManager.java    Wed Apr 18 14:23:07 2001
> @@ -218,8 +218,6 @@
>       public static Resource getResource(String resourceName, int resourceType)
>           throws ResourceNotFoundException, ParseErrorException, Exception
>       {
> -        Resource resource = null;
> -
>           /*
>            * Check to see if the resource was placed in the cache.
>            * If it was placed in the cache then we will use
> @@ -227,10 +225,9 @@
>            * will load it.
>            */
> 
> -        if (globalCache.containsKey(resourceName))
> +        Resource resource = (Resource) globalCache.get(resourceName);
> +        if (resource != null)
>           {
> -            resource = (Resource) globalCache.get(resourceName);
> -
>               /*
>                * The resource knows whether it needs to be checked
>                * or not, and the resource's loader can check to

-- 
Geir Magnusson Jr.                               [EMAIL PROTECTED]
Developing for the web?  See http://jakarta.apache.org/velocity/

Reply via email to