Re: [xsl] Slow XSLT

Subject: Re: [xsl] Slow XSLT
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Fri, 14 Mar 2008 17:12:30 +0100
Hi Jordan,

A lot has already been said and many suggestions have already been made in this thread to speed up the processing of your stylesheet, but since your stylesheet is rather straightforward I doubt if any of the suggestions really speed up the processing.

I'm afraid I haven't followed the discussion closely enough to know how you actually invoke the transformation in the browsers. If you use an XML with a PI, it will be hard to do good measurements of where the culprit may lie. If you use JavaScript + XMLHttpRequest (XHR) to load your XML and the XSLT (or when you do the same but by using Sarissa), it can be a bit easier to find out what the real transformation time is.

The problem I have with you 7 seconds is that I have only seen this kind of slow performance in rare corner cases that often have no place in a browser. These are, for instance, really large input documents or complex string handling through recursion. A typical time of, say, 10K input documents should rather be between 50 - 200 ms (of course, this is too rough to make a good guess). As a comparison, I have co-developed a rather large RIA platform on which a typical page build-up requires about 18 transformations (some are cyclic) which altogether take about 150ms. Of course, I reuse stylesheets, compiled stylesheets and XML sources as much as I can to achieve this performance. Rendering the complex pages takes far more time, unfortunately.

To measure the real transformation time you'll have to put timers after the stylesheet compilation and the moment the XML source has been received in full. Then, after the stylesheet transformation has completed, you stop the timer. This is your transformation time. This, however, will not work if you have external entities, external DTDs, xsl:import/include statements or document () calls, because the latency involved in downloading and parsing these external sources are hard to differentiate from you overall process. Best you can do is remove all external references from XML and XSLT.

If you still find yourself looking at a 7 seconds delay, I bet you hit some weird bug (though it is fairly odd to find that in both TransformIIX and MSXML). You can use the commandline version of MSXML 3.0 to find out what time the actual transformation takes (which will be a better comparison then using Saxon, for Saxon is a completely different processor).

In addition to all this: have you watched your processor and memory occupation during transformation time? Does the browser lock up, or is it still responsive? (IE usually locks up during the transformation phase, if it takes long, it is long locked up). Is the processor at 100% (if you have multiple cores, divide that number by the number of cores), is the memory vastly increasing? Running the transformation multiple times, how long does that take (when a second pass is significantly faster, then external sources might be the culprit).

If you do take the downloadtime in your measurements (which you shouldn't) or the XML-to-string-to-DOM conversion (which is required in MS IE to get from a freethreaded DOM object to a normally threaded DOM object which can be parsed in the browser) then you may look at significantly higher times. On a side note: in both IE and FF some DOM operations are much slower then adding stringized XML as the innerHTML of some element instead (may differ a factor of 20 according to some reports!).

Last q.: can you put your page and your XML/XSLT online on a working web page? Maybe we can see something that otherwise wouldn't easily be seen by only talking abstractly about it.

Cheers,
-- Abel Braaksma


Cleyton Jordan wrote:
Hi Tony,

Thanks for your input.

I am trying to digest all the suggestions you made in
your post. Thanks.

Meanwhile I have made some changes to my mrs template
as per your suggestion. I did not quite understand the
bit you said I do not need to use the 'if' statement.
Can you please elaborate on that?

This is what I have changed:

<xsl:template match="Msr">
    <xsl:variable name="numberVal" select="@val"/>
    <xsl:choose>
      <!--<xsl:when test="string(number(@val))
='NaN'">-->
      <xsl:when test="not(number($numberVal))">
        <td align="left" style="overflow:none">
          <nobr>
            <div style="width:80px;overflow:none">
              <xsl:value-of select="$numberVal"/>
            </div>
          </nobr>
        </td>
      </xsl:when>
      <xsl:otherwise>
        <td align="right" style="overflow:none">
          <nobr>
            <div style="width:80px;overflow:none">
              <xsl:variable name="style"
select="@class"/>
              <xsl:if test="$numberVal != ''">
                <xsl:choose>
                  <xsl:when test="$style='num1'">
                    <xsl:value-of
select="format-number($numberVal,'###,')"/>
                  </xsl:when>
                  <xsl:when test="$style='cur1'">
                    <xsl:value-of
select="format-number($numberVal,$ltCurFormat)"/>
                  </xsl:when>
                  <!--<xsl:when test="$numberVal =
'-1' or $numberVal = '0'">
                    <xsl:text
xml:space="preserve">-</xsl:text>
                  </xsl:when>-->
                  <xsl:when test="$numberVal = '-1' or
$numberVal = '0'">
                    <xsl:text
xml:space="preserve">-</xsl:text>
                  </xsl:when>
                  <xsl:when test="$style='percent'">
                    <xsl:value-of
select="format-number($numberVal * 100,'0.00')"/>
                    <xsl:text>%</xsl:text>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of
select="format-number($numberVal,$ltNumFormat)"/>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:if>
              <xsl:if test="$numberVal = ''">
                <xsl:text
xml:space="preserve">-</xsl:text>
              </xsl:if>
            </div>
          </nobr>
        </td>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

--- Tony Graham <Tony.Graham@xxxxxxxxxxxxxxxxxxxxxx>
wrote:

On Thu, Mar 13 2008 16:33:02 +0000,
cleytonjordan@xxxxxxxxxxx wrote:
Here is the latest working XSLT however it is slow
_________________________________________________

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:strip-space elements="*"/>

<xsl:decimal-format name="fd1"
decimal-separator="."
grouping-separator="," NaN=" \"/>
fd1 appears to be unused.

<xsl:param name="axisHeads" select="'false'"/>
<xsl:param name="sortCol" select="'0'"/>
<xsl:param name="sortCell" select="'0'"/>
<xsl:param name="dataType" select="'text'"/>
<xsl:param name="sortOrder"
select="'ascending'"/>
<xsl:param name="ltCurFormat"
select="'$##,###.00'"/>
<xsl:param name="ltNumFormat"
select="'###,.00'"/>
Saxon 6.5.5 objects to this number format.

  <xsl:param name="heading"/>
  <xsl:param name="height" select="'500'"/>
  <xsl:param name="width" select="'880'"/>
  <xsl:param name="id" select="'audit'"/>


<xsl:template match="Report">
<html>
<head>
<title>report</title>
</head>
<body>
<table border="1">
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Row">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="Msr">
Considering the number of times @val is used, you
could make a variable
for it before this xsl:choose instead of making
$numberVal below.

<xsl:choose>
<xsl:when test="string(number(@val))
='NaN'">

boolean(NaN) is not true [1], so you could do
"not(number(@val))".

Considering that your most common NaN case appears
to be 'val=""', it
might be quicker to do "$val = '' or
not(number($val)".

Judging by your sample data, the NaN is the most
common case.  If it
isn't, you could try reversing the sense of the test
and exchanging the
contents of the xsl:when and the xsl:otherwise to
see if that made any
difference.

If you had the option, it might be better to just
omit @val from your
XML when it doesn't have a useful value.  Checking
for the existence of
an attribute has to be quicker than checking that
the attribute's value
is not a number.

<td align="left" style="overflow:none">
<nobr>
<div style="width:80px;overflow:none">
<xsl:value-of select="@val"/>
</div>
</nobr>
</td>
</xsl:when>
<xsl:otherwise>
<td align="right" style="overflow:none">
<nobr>
<div style="width:80px;overflow:none">
<xsl:variable name="numberVal"
select="@val"/>
<xsl:variable name="style"
select="@class"/>
This xsl:if and xslchoose could be one xsl:choose.

You could experiment with putting the most
frequently true xsl:when
cases first in the xsl:choose to see if that makes
any difference to the
speed.

<xsl:if test="$numberVal != ''">
<xsl:choose>
<xsl:when test="$numberVal =
'-1' or
$numberVal = '0'">
<xsl:text
xml:space="preserve">-</xsl:text>
</xsl:when>
This xsl:when is identical to the one above:

<xsl:when test="$numberVal =
'-1' or
$numberVal = '0'">
<xsl:text
xml:space="preserve">-</xsl:text>
</xsl:when>
<xsl:when
test="$style='wholeNum'">
<xsl:value-of
select="format-number($numberVal,'###,')"/>
</xsl:when>
<xsl:when
test="$style='currency'">
<xsl:value-of
select="format-number($numberVal,$ltCurFormat)"/>
</xsl:when>
<xsl:when
test="$style='percent'">
<xsl:value-of
select="format-number($numberVal * 100,'0.00')"/>
<xsl:text>%</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of
select="format-number($numberVal,$ltNumFormat)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="$numberVal = ''">
How can this ever happen since the xsl:when above in
the outermost
xsl:choose would have been chosen when @val is ''?

                <xsl:text
xml:space="preserve">-</xsl:text>
              </xsl:if>
            </div>
          </nobr>
        </td>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

<xsl:template match="Cell[not(*)]">
<xsl:for-each
select="/Report/Measures/Measure">
<td> </td>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Regards,


Tony Graham.


======================================================================
Tony.Graham@xxxxxxxxxxxxxxxxxxxxxx http://www.menteithconsulting.com

Menteith Consulting Ltd             Registered in
Ireland - No. 428599
Registered Office: 13 Kelly's Bay Beach, Skerries,
Co. Dublin, Ireland

----------------------------------------------------------------------
Menteith Consulting -- Understanding how markup
works

======================================================================
[1]
http://www.w3.org/TR/xpath#section-Boolean-Functions

Current Thread