Tuesday, March 3, 2009

Using Precompiled XSLT in .NET

Using XSLT in .NET

If you specify a file using

XSLCompiledTranform.Load(string filename)

the first thing XSLCompiledTranform is going to do is to emit/compile a set of unloadable DynamicMethods.

Although this is going really fast this overhead costs around 50 - 200ms. So if total time for your conversion is around that time, using precompiled XSLT's can really improve things quite a bit. We use this scenario to do high performance yet standard translations in WCF-Services.

To precompile your XSLT's you have 2 options:

The XSLTCompiler XSLTC.exe

First option is shipped with .NET 3.5 there and is a tool called XSLTC.exe which is basically a wrapper around the static XSLCompiledTransform.CompileToType() function. There is an excellent article by Anton Lapounov. It even gives you some tips to speed things further up using ngen.


I previously stated that XSLTC.exe can only compile one XSLT per assembly, but Andrew proved me wrong.
I tried:

XSLTC.exe *.xslt

which won't work but if you take a closer look at the options

xsltc [options] [/class:] [[/class:] ...]


XSLTC.exe /out:MyXSLT.dll a.xslt b.xslt c.xslt

should compile the XSLT's into a single assembly.

IronXSLT

Second option for this job is called IronXSLT. It is a Visual Studio plug in, that allows you to create a XSLT Library Project. You simply add your XSLT's to the project and after you build the solution they will be compiled into one DLL assembly. I installed it and it works fine with Visual Studio 2008 SP1. After you installed it you have a new project type called XSLT - XSLT Library. To configure it right click it in the solution explorer and select "Properties".

The problem. Unfortunately it seems that its creator Oleg Tkachenko has abandoned his project and no download is working anymore on the projects website.

I found one of the last working IronXSLT downloads here . I will try to contact Oleg in order to get the source published somewhere.

Performance Comparison

Attached to the already above mentioned article of Anton Lapounov there is some test code attached.

I ran a couple of test and got the following results:

using XSLTranform class

XSLTranform
.Load(string filename)


Load time: 35,86 ms
Load time: 1,533 ms
Load time: 1,450 ms
Load time: 1,441 ms
Load time: 1,504 ms
------------------------
Transform time: 51,94 ms
Transform time: 51,29 ms
Transform time: 49,46 ms
Transform time: 51,10 ms
Transform time: 48,77 ms

using XSLCompiledTranform loading tranformation from file

XSLCompiledTranform
.Load(string filename)


Load time: 51,86 ms

Load time: 2,640 ms
Load time: 2,556 ms
Load time: 2,704 ms
Load time: 2,644 ms
------------------------
Transform time: 56,89 ms
Transform time: 1,909 ms
Transform time: 1,680 ms
Transform time: 4,948 ms
Transform time: 1,427 ms

using XSLCompiledTranform loading XSLTC precompiled Transformation

XSLCompiledTranform.Load(type T)

Load time: 5,252 ms
Load time: 0,057 ms
Load time: 0,034 ms
Load time: 0,061 ms
Load time: 0,031 ms
------------------------
Transform time: 8,936 ms
Transform time: 2,302 ms
Transform time: 1,545 ms
Transform time: 1,457 ms
Transform time: 1,505 ms

using XSLCompiledTranform loading XSLTC precompiled and ngen'd Transformation

XSLCompiledTranform
.Load(type T)

Load time: 4,596 ms
Load time: 0,052 ms
Load time: 0,035 ms
Load time: 0,032 ms
Load time: 0,031 ms
------------------------
Transform time: 2,917 ms
Transform time: 2,446 ms
Transform time: 1,584 ms
Transform time: 1,457 ms
Transform time: 1,472 ms

1 comment:

elLoco said...

The reply from Anton Lapounov to my first post.

"Hello,

Thank you for the article and perf numbers. I have a couple of comments on the article:

>> the first thing XSLCompiledTranform is going to do is to call XslCompiledTransform.CompileToType() to compile the XSLT into a temporary assembly. <<

This is technically not true: CompileToType() will not be called and no temporary assembly will be created. Citing my blog post,

Another limitation is that while XslCompiledTransform compiles a stylesheet to a set of unloadable DynamicMethods, an assembly generated by xsltc.exe cannot be unloaded until you shut down all AppDomains that used it (an infamous CLR limitation).

Rephrasing, XslCompiledTransform has two different compilation modes. CompileToType (used by xsltc.exe) creates “normal” methods, which can be saved to the disk as a part of an assembly. Once generated or loaded, they cannot be unloaded without unloading the whole AppDomain. To the contrary, XslCompiledTranform.Load() creates DynamicMethods, which are always static, do not belong to any particular type, cannot be saved, but, in exchange for that, fully unloadable.

>> XSLTC.exe can only compile one XSLT per Assembly which really sucks if you have a certain number of XSLT's. <<

Using xsltc.exe you can compile multiple stylesheet into the same assembly. Just look at its command line:

C:\>xsltc.exe /?

xsltc [options] [/class:<name>] &ltsource file> [[/class:&ltname>] &ltsource file>...]

I have mentioned that in the very beginning of my blog post:

The good news is we are providing the XSLT Compiler command-line utility xsltc.exe (announced here) that can be used to compile multiple stylesheets into one assembly.

Best regards,

Anton