Hi All,
For those who are interested I ran Wicket examples through a profiler (YourKit Java Profiler) this morning to see if there were any obvious bottlenecks. In particular I focused on the hangman application as this has a lot of dynamic images. I did two passes, the first directly before first accessing the application so that all the images required generating and then again once the application had stabilized a bit. Each run spanned an entire game, from creation of the first screen through to successful guess of the word.
Technical spec: Pentium M 1.7GHz laptop, 1GB ram, JDK 1.4.2, Tomcat 5.0.28
All percentages listed below are percentages of the TOTAL processing time used by the JVM. This time includes that used by Tomcat, garbage collector and the profiler runtime itself.
Initial Game
For the first game Wicket spent 8.9 seconds processing - 67% of the entire time spent by the application (the other 33% was used by Tomcat/jvm/profiler).
Of this figure, 39% (5.2 seconds) was spent on handling the requests and 25% (3.4 seconds) was spent rendering the responses.
Of the 39% spent handling the requests, the vast majority (36% / 4.7 seconds) was spent dealing with the images. This was broken down as 23% (3 seconds) generating the dynamic images and 9% (1.2 seconds) copying the data from the resource stream to the response output stream. Of the 23% spent generating the images, the vast majority (19%) was spent in the javax.imageio.ImageWriter.write(RenderedImage) method.
Of the 25% spent on rendering the pages, the vast majority, 20% (2.6 seconds) was spent recursively rendering all of the components. This was spread out pretty evenly over the whole process although around 7% of the time (0.8 seconds) was spent in String.replaceAll() calls!
Second Game
For the second game Wicket spent 2.95 seconds processing - 57% of the entire time spent by the application (the other 43% was used by Tomcat/jvm/profiler).
Of this figure, 24% (1.2 seconds) was spent on handling the requests and 30% (1.6 seconds) was spent rendering the responses.
Of the 24% spent handlings the request, the vast majority (20% / 1 second) was spent dealing with the images. As the images were already generated, the majority of the processing (14% / 0.7 seconds) was spent copying the data from the resource stream to the response output stream.
Of the 30% spent on rendering the pages, the vast majority (26% / 1.35 seconds) was spent recursively rendering all of the components. Drilling down further, a fairly large proportion of this time (12% / 0.6 seconds) was again spent in String.replaceAll() calls.
Conclusions
Overall I think the performance of Wicket was fairly sound. There were no obvious bottlenecks in the main processing code. Generating images is always going to be costly, but this is only a one-off hit for applications like hangman. However, I would make the following two recommendations:
1) We look at the code that moves content from a stream for a resource into the response stream and see if we can improve the performance of this in any way as a fairly significant amount of processing time is being spent in this area. This would certainly speed up applications like hangman or Gili's application which are heavy users of resources.
2) We revisit everywhere where calls are made to String.replaceAll() and implement our own more efficient version that works on raw character data and doesn't rely on regexp pattern generation and so on. Far too much time is being spent doing regexp pattern creation and matching for what are essentially very simple replacements. For Hangman, the obvious candidates are:
wicket.markup.html.image.resource.LocalizedImageResource.setSrcAttribute(ComponentTag) - line 270
wicket.markup.parser.XmlTag.toXmlString(String) - line 545
wicket.markup.html.link.Link.onComponentTag(ComponentTag) - line 352
Regards,
Chris
