Project

Profile

Help

Support #6642

closed

Is there a faster way to compile an XSLT Stylesheet? I'm only interested in errors, I won't run the transformation

Added by Gerben Abbink 17 days ago. Updated 13 days ago.

Status:
Resolved
Priority:
Low
Assignee:
-
Category:
-
Sprint/Milestone:
-
Start date:
2025-01-12
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
Fixed in Maintenance Release:
Platforms:

Description

I have two (demo) stylesheets of about the same size. Saxonica.xsl and Saxonica-with-error.xsl. Both files are almost the same: Saxonica.xsl has no errors, Saxonica-with-error.xsl has a single XPath error at the end of the file.

If I compile Saxonica.xsl using S9Api XsltCompiler, it takes 6 seconds to compile. If I compile Saxonica-with-error.xsl it takes only 2 seconds to compile (4 seconds faster).

In my application I need to compile and display XSLT errors as fast as possible. I don't actually have to run the transformation; I only need to display possible errors.

I can imagine that the compiler has to do a lot of things, besides error checking when compiling an XSLT stylesheet. But is there a way to tell the compiler I'm not interested in "these other things".

I know there's a function setFastCompilation(), but if true XPath errors are not detected. That's not what I need.


Files

Saxonica.xsl (41.2 MB) Saxonica.xsl Gerben Abbink, 2025-01-12 18:49
Saxonica-with-error.xsl (41.2 MB) Saxonica-with-error.xsl Gerben Abbink, 2025-01-12 18:49
Actions #1

Updated by Michael Kay 16 days ago

I ran this with a switch set to get timing information for the phases of compilation. (You can enable this by running with -repeat:x -nogo -t) The results are:

SaxonJ-EE 13.0 from Saxonica
Java version 18.0.2
Using license serial number V011879
Built stylesheet documents 716.688916ms
Preparing package 83.476042ms
spliceIncludes 0.388ms
importSchemata 0.066542ms
buildIndexes 0.146666ms
checkForSchemaAwareness 0.033834ms
processAllAttributes 178.912916ms
collectNamespaceAliases 0.111542ms
fixupReferences 75.361458ms
validate 138.269542ms
Register output formats 0.527333ms
Index character maps 0.07575ms
Fixup 0.028209ms
Combine attribute sets 0.029208ms
fixup Query functions 1.265208ms
register templates 12.807125ms
adjust exposed visibility 0.086084ms
compile top-level objects (1) 1912.674208ms
typeCheck functions (0) 0.265125ms
optimize top level 4307.704958ms
optimize functions 0.1125ms
check decimal formats 0.138ms
build template rule tables 1.858167ms
build runtime function tables 0.270208ms
allocate binding slots to named templates 0.038834ms
allocate binding slots to component references 130.339666ms
allocate binding slots to key definitions 0.189542ms
allocate binding slots to accumulators 0.071667ms
Completion 0.629791ms
Streaming fallback 0.051459ms
Stylesheet compilation time: 7.564654792s (7564.654792ms)

So the most expensive phase by far is "optimize top level". You can cut out this phase by running with -opt:0. For me that reduces the compile time from around 7.5s to around 5s.

The other expensive phase is "compile top level objects" and that can't be switched off.

That message tells us that there is only one top-level component in the stylesheet - this is a completely artificial stylesheet so the actual performance numbers aren't going to extrapolate to more realistic code. I seem to recall from previous investigations that compilation time increases linearly with the number of components, but the time for an individual component can sometimes increase quadratically with the size of the component - though that's probably not the case for a situation like this where the component consists entirely of literal result elements.

The processAllAttributes phase will normally account for a much larger proportion of the time. This phase compiles all the XPath expressions. It's very fast in this case because there aren't any XPath expressions.

I'm tempted to ask, why does it take so long to do the optimization phase for code that's quite so trivial? However, I was taught a good principle many years ago: focus your optimization efforts on code that users actually write, not on artificial test cases.

Actions #2

Updated by Michael Kay 16 days ago

Slightly against my better judgement, I did take a look at profile data to see in more details where the time is going. 64.8% in optimizeTopLevel, including 26.3% in OptimizerEE.promoteExpressionsToGlobal (of which 21.9% is in GlobalExtractor.markIneligibleExpressions), and 18.7% in LoopLifter.process (of which 129% is in LoopLifter.gatherInfo).

Both these methods are putting in a lot of effort deciding to do nothing.

One possibility is to attempt some commoning-up of the logic here, since many of the conditions that allow/disallow promoting an expression to be global are the same as the conditions that allow/disallow loop-lifting.

Another thing that comes to mind is that the choice whether to do JIT compilation of template rules is perhaps a bit stark. Perhaps we should be doing eager error checking and lazy optimization. However, this stylesheet is so untypical that we shouldn't draw any conclusions from it.

Actions #3

Updated by Michael Kay 13 days ago

  • Status changed from New to Resolved

So, I'm closing this with the response; switch optimization off. The benefit from this will vary a lot with the actual stylesheet, and this sample is very untypical.

Please register to edit this issue

Also available in: Atom PDF