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/