[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Performance improvement for a recursive function?


Subject: Re: [xsl] Performance improvement for a recursive function?
From: Andrew Welch <andrew.j.welch@xxxxxxxxx>
Date: Tue, 13 Dec 2011 09:52:49 +0000

fwiw, there are further slight tweaks of use xsl:sequence instead of
xsl:value-of (to avoid the text node creation and then atomization to
a string), and moving the sequences into variables, eg change

$cmd = (' ', 'M', 'l', 'm')

to

$cmd = $seq

where $seq is <xsl:variable name="seq" select="(' ', 'M', 'l', 'm')"
as="xs:string+"/>

To tweak that a bit more, you could use the code points instead of the
characters... but it might not be worth it.



On 13 December 2011 09:44, Manfred Staudinger
<manfred.staudinger@xxxxxxxxx> wrote:
> Hi Wolfgang,
>
> What a great solution: execution time is down to 7 sec (from 14 minutes).
> Thanks a lot,
>
> Manfred
>
> On 13/12/2011, Wolfgang Laun <wolfgang.laun@xxxxxxxxx> wrote:
>> I forgot to mention that the result of this function must be processed
with
>>    string-join(my:compose-path-data($Data),'')
>> -W
>>
>> On 13 December 2011 08:46, Wolfgang Laun <wolfgang.laun@xxxxxxxxx> wrote:
>>> This function permits processing of all contained commands.
>>>
>>> I don't have the time to analyze what should be done for each; I saw
>>> that m0,0 was dropped.
>>>
>>> It's fast enough now :-)
>>>
>>> -W
>>>
>>> <xsl:function name="my:compose-path-data" as="xs:string*">
>>>        <xsl:param name="data" as="xs:string*"/>
>>>    <xsl:analyze-string select = "$data"
>>>                        regex = "[ Mlm](\d+),(\d+)|[hv](\d+)|z">
>>>       <xsl:matching-substring>
>>>          <xsl:variable name="cmd"
select="substring(regex-group(0),1,1)"/>
>>>          <xsl:choose>
>>>             <xsl:when test="$cmd = (' ', 'M', 'l', 'm')">
>>>               <xsl:value-of
>>> select="concat($cmd,regex-group(1),',',regex-group(2))"/>
>>>             </xsl:when>
>>>             <xsl:when test="$cmd = ('h', 'v')">
>>>               <xsl:value-of select="concat($cmd,regex-group(3))"/>
>>>             </xsl:when>
>>>             <xsl:when test="$cmd = 'z'">
>>>               <xsl:value-of select="$cmd"/>
>>>             </xsl:when>
>>>          </xsl:choose>
>>>       </xsl:matching-substring>
>>>    </xsl:analyze-string>
>>> </xsl:function>
>>>
>>>
>>> On 13 December 2011 01:07, Manfred Staudinger
>>> <manfred.staudinger@xxxxxxxxx> wrote:
>>>> Hi,
>>>>
>>>> I need some help to improve the performance of a function, as I have
>>>> run out of ideas what to change!
>>>>
>>>> In the process to convert some data to SVG I transform (or even break
>>>> up) @Data attribute of the Path element and then use the function
>>>> my:compose-path-data [1] to put the parts together into a string
>>>> again. The attribute string is a succession of path commands, where
>>>> each path command  (see the global variable below) consists of a one
>>>> byte character followed by zero, one, or two integers. Having about
>>>> 2200 Path elements, most of them have a @Data attribute with between 5
>>>> an 50 path commands.
>>>>
>>>> A few attribute strings are bigger (up to 1MB) and contain up to
>>>> 100000 path commands. As the function is called for each path command
>>>> it is tail recursive, but the performance is still a big problem: to
>>>> process 41337 path commands it takes 861 sec! The first 5000 path
>>>> commands are processed in 14 sec (at 355.87 per sec) the last 5000
>>>> take 671 sec (only at 7.5 per sec).
>>>>
>>>> What Saxon reports [2] is consistent with the above. In case you want
>>>> to try it, I have uploaded the specific test case here:
>>>>   http:///test.rudolphina.org/test01-perform-data.xsl
>>>>   http:///test.rudolphina.org/test01-perform-data-org.xml
>>>>
>>>> Using Saxon-HE 9.3.0.5J and Java version 1.6.0_14 on Windows. XP Home.
>>>> Hardware ASUS Eee PC 1000H with Intel. Atom N270 (1.60 GHz)
>>>>
>>>> Regards,
>>>> Manfred
>>>>
>>>> [1]
>>>> <xsl:function name="my:compose-path-data" as="xs:string*">
>>>>   <xsl:param name="c" as="xs:integer*"/>
>>>>   <xsl:param name="i-c" as="xs:integer"/>
>>>>   <xsl:param name="xy" as="xs:integer*"/>
>>>>   <xsl:param name="i-xy" as="xs:integer"/>
>>>>   <xsl:param name="i-end" as="xs:integer"/>
>>>>   <xsl:param name="result" as="xs:string?"/>
>>>>   <xsl:variable name="cmd" select="key('path', $c[$i-c], $path-cmd)"
>>>> as="element()?"/>
>>>>   <xsl:sequence select="if ($i-c gt $i-end)
>>>>      then $result
>>>>      else my:compose-path-data($c, $i-c + 1,
>>>>         $xy, $i-xy + xs:integer($cmd/n),
>>>>         $i-end,
>>>>         concat($result, $cmd/@char, if ($cmd/n=2)
>>>>            then (: M, m, l, (blank) :) concat($xy[$i-xy], ',',
>>>> $xy[$i-xy+1])
>>>>            else  if ($cmd/n=1)
>>>>               then (: h, v :) string($xy[$i-xy])
>>>>               else (: z :) ())
>>>>         )"/>
>>>> </xsl:function>
>>>>
>>>> and on the stylesheet level
>>>> <xsl:variable name="path-cmd">
>>>>   <path>
>>>>      <cmd char=" "><n>2</n><code>32</code></cmd>
>>>>      <cmd char="M"><n>2</n><code>77</code></cmd>
>>>>      <cmd char="l"><n>2</n><code>108</code></cmd>
>>>>      <cmd char="m"><n>2</n><code>109</code></cmd>
>>>>      <cmd char="h"><n>1</n><code>104</code></cmd>
>>>>      <cmd char="v"><n>1</n><code>118</code></cmd>
>>>>      <cmd char="z"><n>0</n><code>122</code></cmd>
>>>>   </path>
>>>> </xsl:variable>
>>>> <xsl:key name="path" match="cmd" use="xs:integer(code)"/><!-- $path-cmd
>>>> -->
>>>>
>>>> [2]
>>>> Stylesheet compilation time: 4218 milliseconds
>>>> Using parser org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser
>>>> net.sf.saxon.tree.tiny.TinyBuilder
>>>> Tree built in 1375 milliseconds
>>>> Tree size: 4 nodes, 0 characters, 11 attributes
>>>> Execution time: 14m 31.579s (871579ms)
>>>> Memory used: 36559128
>>>> NamePool contents: 33 entries in 33 chains. 8 prefixes, 8 URIs
>



--
Andrew Welch
http://andrewjwelch.com


Current Thread
Keywords
svg