Jeremias Maerki wrote:
As you probably noticed, I'm looking again into improving the
performance of the intermediate format:
Thanks for that. Looks good so far!
+ very good performance when rendering from IF
+ simpler IF format (easier to write by hand)
+ IFPainters are much easier to implement than Renderers
+ preserved backwards compatibility
+ parallel development possible without endangering stability
+ output formats can be switched individually when each IFPainter is
o No benefit for the non-IF use case which is the usual way to run FOP
- added complexity
- a lot of work
- a lot of new code is added
- added risk that some output format specialities cannot be mapped as
well with IFPainter as with Renderer. (mainly PCL comes to mind here
although there's a work-around available (text as bitmaps))
A simple test, count the pros and cons and add the counts together = +6
-4 = +2
Improving the area tree:
+ similar performance gain might be possible
+ small performance gain possible for non-IF use case
+ chance to revisit the area tree structure and to simplify it a bit
- the old IF remains difficult to handle for people who write IF by hand
- the amount of source code in the area package increases
- backwards compatibility for renderers is not preserved. All renderers
need to be touched.
- Old intermediate format will be changed which could make adjusting
many test cases necessary.
That is a simplistic way of looking at at but at least its objective
rather than subjective. My personal preferrence is for the first
approach because it will remain so difficult to write/modify IF XML in
Regardless of the change:
* Preparation for a structure tree and tagged PDF will have to be done
at some point which has an impact on the area tree, the IF and the
* Impact of full writing mode support is still unknown.
In contrast to the above, there's an additional way to increase
performance without much work:
We just make use of modern multi-core CPUs. FOP is mostly
single-threaded. If you look at the CPU usage in a dual-core machine,
you'll see that it will stay at about 50% when rendering. If we do area
tree parsing in the main thread and rendering in another we can do both
at the same time. That's an easy way to decouple the two tasks. There's
also no fine-grained synchronization as it could be done per page which
is coarse enough not to create a performance problem. The only risk I
see is memory consumption as the layout engine or the area tree parser
might be faster to build pages than the renderers can render them. But
if that happens we could probably add a setting that blocks the page
source if the renderer is too far behind. Based on my profiling I would
estimate the performance improvement to be in the area of 50-60%, even
for the non-IF case, on multi-core CPUs. Single core CPUs will probably
not profit but also not suffer.
-1 to this approach for several reasons:
1) Anyone integrating FOP via the API will not be able to plug into a
J2EE container because spawning threads is not allowed in a EJB.
2) Keeping FOP single threaded means the choice to multi-thread is left
with the API Integrator. It is very easy to get FOP to use the full CPU
power of multi-cores. I have a test app which is only about 100 lines of
code which starts multiple threads. Each thread pulls documents from a pool.
3) Code maintenance becomes a nightmare in a multi threaded application.
The synchronization might look simple at first but it quickly becomes
v.v.difficult. 3 of us at my company recently spent 3 months
troubleshooting the bugs out of a multithreaded application which is
somewhat smaller and less complex than FOP. This point is re-iterated by
Andreas' recent efforts to fix synchronization of the Cache Cleaner
threads in the Property Cache. It looks simple in theory but in practise
turns out to be more trouble than its worth.