Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e830674

Browse files
committed
doc: Speed up XSLT builds
The upstream XSLT stylesheets use some very general XPath expressions in some places that end up being very slow. We can optimize them with knowledge about the DocBook document structure and our particular use thereof. For example, when counting preceding chapters to get a number for the current chapter, we only need to count preceding sibling nodes (more or less) instead of searching through the entire node tree for chapter elements. This change attacks the slowest pieces as identified by xsltproc --profile. This makes the HTML build roughly 10 times faster, resulting in the new total build time being about the same as the old DSSSL-based build. Some of the non-HTML build targets (especially FO) will also benefit a bit, but they have not been specifically analyzed. With this, also remove the pg.fast parameter, which was previously a hack to get the build to a manageable speed. Alexander Lakhin <a.lakhin@postgrespro.ru>, with some additional tweaking by me
1 parent 8019b5a commit e830674

File tree

4 files changed

+350
-5
lines changed

4 files changed

+350
-5
lines changed

doc/src/sgml/stylesheet-common.xsl

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
all output formats (HTML, HTML Help, XSL-FO, etc.).
88
-->
99

10+
<xsl:include href="stylesheet-speedup-common.xsl" />
1011

1112
<!-- Parameters -->
1213

13-
<xsl:param name="pg.fast" select="'0'"/>
14-
1514
<!--
1615
<xsl:param name="draft.mode">
1716
<xsl:choose>
@@ -31,9 +30,8 @@
3130
<xsl:param name="callout.graphics" select="'0'"></xsl:param>
3231
<xsl:param name="toc.section.depth">2</xsl:param>
3332
<xsl:param name="linenumbering.extension" select="'0'"></xsl:param>
34-
<xsl:param name="generate.index" select="1 - $pg.fast"></xsl:param>
35-
<xsl:param name="section.autolabel" select="1 - $pg.fast"></xsl:param>
36-
<xsl:param name="section.label.includes.component.label" select="1 - $pg.fast"></xsl:param>
33+
<xsl:param name="section.autolabel" select="1"></xsl:param>
34+
<xsl:param name="section.label.includes.component.label" select="1"></xsl:param>
3735
<xsl:param name="refentry.xref.manvolnum" select="0"/>
3836
<xsl:param name="formal.procedures" select="0"></xsl:param>
3937
<xsl:param name="punct.honorific" select="''"></xsl:param>
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3+
version='1.0'>
4+
5+
<!-- Performance-optimized versions of some upstream templates from common/
6+
directory -->
7+
8+
<!-- from common/labels.xsl -->
9+
10+
<xsl:template match="chapter" mode="label.markup">
11+
<xsl:choose>
12+
<xsl:when test="@label">
13+
<xsl:value-of select="@label"/>
14+
</xsl:when>
15+
<xsl:when test="string($chapter.autolabel) != 0">
16+
<xsl:if test="$component.label.includes.part.label != 0 and
17+
ancestor::part">
18+
<xsl:variable name="part.label">
19+
<xsl:apply-templates select="ancestor::part"
20+
mode="label.markup"/>
21+
</xsl:variable>
22+
<xsl:if test="$part.label != ''">
23+
<xsl:value-of select="$part.label"/>
24+
<xsl:apply-templates select="ancestor::part"
25+
mode="intralabel.punctuation">
26+
<xsl:with-param name="object" select="."/>
27+
</xsl:apply-templates>
28+
</xsl:if>
29+
</xsl:if>
30+
<xsl:variable name="format">
31+
<xsl:call-template name="autolabel.format">
32+
<xsl:with-param name="format" select="$chapter.autolabel"/>
33+
</xsl:call-template>
34+
</xsl:variable>
35+
<xsl:choose>
36+
<xsl:when test="$label.from.part != 0 and ancestor::part">
37+
<xsl:number from="part" count="chapter" format="{$format}" level="any"/>
38+
</xsl:when>
39+
<xsl:otherwise>
40+
<!-- Optimization for pgsql-docs: When counting to get label for
41+
this chapter, preceding chapters can only be our siblings or
42+
children of a preceding part, so only count those instead of
43+
scanning the entire node tree. -->
44+
<!-- <xsl:number from="book" count="chapter" format="{$format}" level="any"/> -->
45+
<xsl:number value="count(../preceding-sibling::part/chapter) + count(preceding-sibling::chapter) + 1" format="{$format}"/>
46+
</xsl:otherwise>
47+
</xsl:choose>
48+
</xsl:when>
49+
</xsl:choose>
50+
</xsl:template>
51+
52+
<xsl:template match="appendix" mode="label.markup">
53+
<xsl:choose>
54+
<xsl:when test="@label">
55+
<xsl:value-of select="@label"/>
56+
</xsl:when>
57+
<xsl:when test="string($appendix.autolabel) != 0">
58+
<xsl:if test="$component.label.includes.part.label != 0 and
59+
ancestor::part">
60+
<xsl:variable name="part.label">
61+
<xsl:apply-templates select="ancestor::part"
62+
mode="label.markup"/>
63+
</xsl:variable>
64+
<xsl:if test="$part.label != ''">
65+
<xsl:value-of select="$part.label"/>
66+
<xsl:apply-templates select="ancestor::part"
67+
mode="intralabel.punctuation">
68+
<xsl:with-param name="object" select="."/>
69+
</xsl:apply-templates>
70+
</xsl:if>
71+
</xsl:if>
72+
<xsl:variable name="format">
73+
<xsl:call-template name="autolabel.format">
74+
<xsl:with-param name="format" select="$appendix.autolabel"/>
75+
</xsl:call-template>
76+
</xsl:variable>
77+
<xsl:choose>
78+
<xsl:when test="$label.from.part != 0 and ancestor::part">
79+
<xsl:number from="part" count="appendix" format="{$format}" level="any"/>
80+
</xsl:when>
81+
<xsl:otherwise>
82+
<!-- Optimization for pgsql-docs: When counting to get label for
83+
this appendix, preceding appendixes can only be our siblings or
84+
children of a preceding part, so only count those instead of
85+
scanning the entire node tree. -->
86+
<!-- <xsl:number from="book|article" count="appendix" format="{$format}" level="any"/> -->
87+
<xsl:number value="count(../preceding-sibling::part/appendix) + count(preceding-sibling::appendix) + 1" format="{$format}"/>
88+
</xsl:otherwise>
89+
</xsl:choose>
90+
</xsl:when>
91+
</xsl:choose>
92+
</xsl:template>
93+
94+
</xsl:stylesheet>
+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3+
xmlns="http://www.w3.org/1999/xhtml"
4+
version='1.0'>
5+
6+
<!-- Performance-optimized versions of some upstream templates from xhtml/
7+
directory -->
8+
9+
<!-- from xhtml/autoidx.xsl -->
10+
11+
<xsl:template match="indexterm" mode="reference">
12+
<xsl:param name="scope" select="."/>
13+
<xsl:param name="role" select="''"/>
14+
<xsl:param name="type" select="''"/>
15+
<xsl:param name="position"/>
16+
<xsl:param name="separator" select="''"/>
17+
18+
<xsl:variable name="term.separator">
19+
<xsl:call-template name="index.separator">
20+
<xsl:with-param name="key" select="'index.term.separator'"/>
21+
</xsl:call-template>
22+
</xsl:variable>
23+
24+
<xsl:variable name="number.separator">
25+
<xsl:call-template name="index.separator">
26+
<xsl:with-param name="key" select="'index.number.separator'"/>
27+
</xsl:call-template>
28+
</xsl:variable>
29+
30+
<xsl:variable name="range.separator">
31+
<xsl:call-template name="index.separator">
32+
<xsl:with-param name="key" select="'index.range.separator'"/>
33+
</xsl:call-template>
34+
</xsl:variable>
35+
36+
<xsl:choose>
37+
<xsl:when test="$separator != ''">
38+
<xsl:value-of select="$separator"/>
39+
</xsl:when>
40+
<xsl:when test="$position = 1">
41+
<xsl:value-of select="$term.separator"/>
42+
</xsl:when>
43+
<xsl:otherwise>
44+
<xsl:value-of select="$number.separator"/>
45+
</xsl:otherwise>
46+
</xsl:choose>
47+
48+
<xsl:choose>
49+
<xsl:when test="@zone and string(@zone)">
50+
<xsl:call-template name="reference">
51+
<xsl:with-param name="zones" select="normalize-space(@zone)"/>
52+
<xsl:with-param name="position" select="position()"/>
53+
<xsl:with-param name="scope" select="$scope"/>
54+
<xsl:with-param name="role" select="$role"/>
55+
<xsl:with-param name="type" select="$type"/>
56+
</xsl:call-template>
57+
</xsl:when>
58+
<xsl:otherwise>
59+
<a>
60+
<xsl:apply-templates select="." mode="class.attribute"/>
61+
<xsl:variable name="title">
62+
<xsl:choose>
63+
<xsl:when test="$index.prefer.titleabbrev != 0">
64+
<xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="titleabbrev.markup"/>
65+
</xsl:when>
66+
<xsl:otherwise>
67+
<xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="title.markup"/>
68+
</xsl:otherwise>
69+
</xsl:choose>
70+
</xsl:variable>
71+
72+
<xsl:attribute name="href">
73+
<xsl:choose>
74+
<xsl:when test="$index.links.to.section = 1">
75+
<xsl:call-template name="href.target">
76+
<xsl:with-param name="object" select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]"/>
77+
<!-- Optimization for pgsql-docs: We only have an index as a
78+
child of book, so look that up directly instead of
79+
scanning the entire node tree. Also, don't look for
80+
setindex. -->
81+
<!-- <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/> -->
82+
<xsl:with-param name="context" select="(/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
83+
</xsl:call-template>
84+
</xsl:when>
85+
<xsl:otherwise>
86+
<xsl:call-template name="href.target">
87+
<xsl:with-param name="object" select="."/>
88+
<xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
89+
</xsl:call-template>
90+
</xsl:otherwise>
91+
</xsl:choose>
92+
93+
</xsl:attribute>
94+
95+
<xsl:value-of select="$title"/> <!-- text only -->
96+
</a>
97+
98+
<xsl:variable name="id" select="(@id|@xml:id)[1]"/>
99+
<xsl:if test="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))]">
100+
<xsl:apply-templates select="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][last()]" mode="reference">
101+
<xsl:with-param name="position" select="position()"/>
102+
<xsl:with-param name="scope" select="$scope"/>
103+
<xsl:with-param name="role" select="$role"/>
104+
<xsl:with-param name="type" select="$type"/>
105+
<xsl:with-param name="separator" select="$range.separator"/>
106+
</xsl:apply-templates>
107+
</xsl:if>
108+
</xsl:otherwise>
109+
</xsl:choose>
110+
</xsl:template>
111+
112+
<xsl:template name="reference">
113+
<xsl:param name="scope" select="."/>
114+
<xsl:param name="role" select="''"/>
115+
<xsl:param name="type" select="''"/>
116+
<xsl:param name="zones"/>
117+
118+
<xsl:choose>
119+
<xsl:when test="contains($zones, ' ')">
120+
<xsl:variable name="zone" select="substring-before($zones, ' ')"/>
121+
<xsl:variable name="target" select="key('sections', $zone)"/>
122+
123+
<a>
124+
<xsl:apply-templates select="." mode="class.attribute"/>
125+
<xsl:call-template name="id.attribute"/>
126+
<xsl:attribute name="href">
127+
<xsl:call-template name="href.target">
128+
<xsl:with-param name="object" select="$target[1]"/>
129+
<xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
130+
</xsl:call-template>
131+
</xsl:attribute>
132+
<xsl:apply-templates select="$target[1]" mode="index-title-content"/>
133+
</a>
134+
<xsl:text>, </xsl:text>
135+
<xsl:call-template name="reference">
136+
<xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
137+
<xsl:with-param name="position" select="position()"/>
138+
<xsl:with-param name="scope" select="$scope"/>
139+
<xsl:with-param name="role" select="$role"/>
140+
<xsl:with-param name="type" select="$type"/>
141+
</xsl:call-template>
142+
</xsl:when>
143+
<xsl:otherwise>
144+
<xsl:variable name="zone" select="$zones"/>
145+
<xsl:variable name="target" select="key('sections', $zone)"/>
146+
147+
<a>
148+
<xsl:apply-templates select="." mode="class.attribute"/>
149+
<xsl:call-template name="id.attribute"/>
150+
<xsl:attribute name="href">
151+
<xsl:call-template name="href.target">
152+
<xsl:with-param name="object" select="$target[1]"/>
153+
<!-- Optimization for pgsql-docs: Only look for index under book
154+
instead of searching the whole node tree. -->
155+
<!-- <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/> -->
156+
<xsl:with-param name="context" select="/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
157+
</xsl:call-template>
158+
</xsl:attribute>
159+
<xsl:apply-templates select="$target[1]" mode="index-title-content"/>
160+
</a>
161+
</xsl:otherwise>
162+
</xsl:choose>
163+
</xsl:template>
164+
165+
166+
<!-- from xhtml/chunk-common.xsl -->
167+
168+
<xsl:template name="chunk-all-sections">
169+
<xsl:param name="content">
170+
<xsl:apply-imports/>
171+
</xsl:param>
172+
173+
<!-- Optimization for pgsql-docs: Since we set a fixed $chunk.section.depth,
174+
we can do away with a bunch of complicated XPath searches for the
175+
previous and next sections at various levels. -->
176+
177+
<xsl:if test="$chunk.section.depth != 1">
178+
<xsl:message terminate="yes">
179+
<xsl:text>Error: If you change $chunk.section.depth, then you must update the performance-optimized chunk-all-sections-template.</xsl:text>
180+
</xsl:message>
181+
</xsl:if>
182+
183+
<xsl:variable name="prev"
184+
select="(preceding::book[1]
185+
|preceding::preface[1]
186+
|preceding::chapter[1]
187+
|preceding::appendix[1]
188+
|preceding::part[1]
189+
|preceding::reference[1]
190+
|preceding::refentry[1]
191+
|preceding::colophon[1]
192+
|preceding::article[1]
193+
|preceding::topic[1]
194+
|preceding::bibliography[parent::article or parent::book or parent::part][1]
195+
|preceding::glossary[parent::article or parent::book or parent::part][1]
196+
|preceding::index[$generate.index != 0]
197+
[parent::article or parent::book or parent::part][1]
198+
|preceding::setindex[$generate.index != 0][1]
199+
|ancestor::set
200+
|ancestor::book[1]
201+
|ancestor::preface[1]
202+
|ancestor::chapter[1]
203+
|ancestor::appendix[1]
204+
|ancestor::part[1]
205+
|ancestor::reference[1]
206+
|ancestor::article[1]
207+
|ancestor::topic[1]
208+
|preceding::sect1[1]
209+
|ancestor::sect1[1])[last()]"/>
210+
211+
<xsl:variable name="next"
212+
select="(following::book[1]
213+
|following::preface[1]
214+
|following::chapter[1]
215+
|following::appendix[1]
216+
|following::part[1]
217+
|following::reference[1]
218+
|following::refentry[1]
219+
|following::colophon[1]
220+
|following::bibliography[parent::article or parent::book or parent::part][1]
221+
|following::glossary[parent::article or parent::book or parent::part][1]
222+
|following::index[$generate.index != 0]
223+
[parent::article or parent::book][1]
224+
|following::article[1]
225+
|following::topic[1]
226+
|following::setindex[$generate.index != 0][1]
227+
|descendant::book[1]
228+
|descendant::preface[1]
229+
|descendant::chapter[1]
230+
|descendant::appendix[1]
231+
|descendant::article[1]
232+
|descendant::topic[1]
233+
|descendant::bibliography[parent::article or parent::book][1]
234+
|descendant::glossary[parent::article or parent::book or parent::part][1]
235+
|descendant::index[$generate.index != 0]
236+
[parent::article or parent::book][1]
237+
|descendant::colophon[1]
238+
|descendant::setindex[$generate.index != 0][1]
239+
|descendant::part[1]
240+
|descendant::reference[1]
241+
|descendant::refentry[1]
242+
|following::sect1[1]
243+
|descendant::sect1[1])[1]"/>
244+
245+
<xsl:call-template name="process-chunk">
246+
<xsl:with-param name="prev" select="$prev"/>
247+
<xsl:with-param name="next" select="$next"/>
248+
<xsl:with-param name="content" select="$content"/>
249+
</xsl:call-template>
250+
</xsl:template>
251+
252+
</xsl:stylesheet>

doc/src/sgml/stylesheet.xsl

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
88
<xsl:include href="stylesheet-common.xsl" />
9+
<xsl:include href="stylesheet-speedup-xhtml.xsl" />
910

1011

1112
<!-- Parameters -->

0 commit comments

Comments
 (0)