Re: Speed of processing man pages

"Michael(tm) Smith" <[email protected]> Wed, 19 Apr 2006 13:06:29 +0900
Newsgroups gmane.text.docbook.docbook2x.general
Message-ID <[email protected]>
Steve Cheng <[email protected]> writes:

> To convert 187 pages:
> 
> xsltproc takes approx 41 seconds
> db2x_manxml takes approx 26.5 seconds without charset conversion
> (Haven't tested with charset conversion yet, however it does seem to
> be much faster
> than the first two stages.)
> 
> This is with obvious optimizations such as only loading the XSLT stylesheet once
> for the 187 documents, and also loading db2x_manxml once only.
> 
> So about .36 seconds to process one page.
> Or one hour to process 10000 pages. :-(
> 
> It would also be helpful to have some comparison with other
> DocBook-to-man solutions.

FWIW, here's output from time(1) for a run through the DocBook
project manpages stylesheets of all 187 refentry instances.

  real    1m17.942s

That's on a ThinkPad T42p with a 2GHz CPU, and using the attached
makefile.

Note that one of the things the makefile does is to first create a
number of "wrapper" files that combine the refentry instances into
groups of 20. Then it runs the transformation on those wrapper
files instead of the individual source files. The output is
exactly the same, but it's significantly faster.[1]

For the sake of comparison, here's time output for a run through
the HTML chunk stylesheet on the same set of files:

  real    0m59.359s

So the manpages stylesheet is measurably slower than the chunk
stylesheet, but not way far behind.

You can change the number of refentry instances per group by
setting CHUNKSIZE:

  make CHUNKSIZE=10

Here's output from time for a manpages run if I set that (10
refentry instances per file instead of 20):

  real    1m35.519s

And for chunked HTML:

  real    1m19.731s

To show how much of a difference it makes if the refentry
instances are not groupr, here's time output for a manpages run
with just one file per refentry:

  real    7m14.579s

And for (non-chunked) HTML with one file per refentry:

  real    6m32.523s

So it's quite slow doing it that way, but not too surprising,
since it's reloading the stylesheet and invoking xsltproc 187
separate times.

  --Mike

[1] Running the transformation against files that contain sets of
refentry instances (instead of one-file-per-refentry) also more
closely models the way that most users have their source files
organized. Most users don't maintain a separate source file for
each refentry -- especially if they are also generating print/PDF
and HTML output.  In my experiences, users typically maintain sets
of refentry instances instead -- or at least use XInclude or some
other mechanism to to group them before generating output.
Makefile (text/plain, 5.5 KB)
FILES=$(shell find . -maxdepth 1 -name "*.xml" | cut -c3-)

MAN_XSL = http://docbook.sourceforge.net/snapshots/xsl/tools/make/Makefile.DocBook

WGET=wget
WGET_FLAGS=

XSLTPROC=xsltproc
XSLTPROC_FLAGS=

SED=sed
SED_FLAGS=-i

CHUNKSIZE ?= 20

COMBINE_XSL = <?xml version="1.0"?> \
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" \
                xmlns:exsl="http://exslt.org/common" \
                xmlns:xi="http://www.w3.org/2001/XInclude" \
                exclude-result-prefixes="exsl xi" \
                extension-element-prefixes="exsl" \
                version="1.0"> \
  <xsl:param name="files"/> \
  <xsl:param name="chunk.size"/> \
  <xsl:template match="/"> \
    <xsl:call-template name="make.file"/> \
  </xsl:template> \
 \
  <xsl:template name="make.file"> \
    <xsl:param name="count" select="1"/> \
    <xsl:param name="current.files" select="concat(normalize-space($$files), ^^ ^^)"/> \
    <xsl:param name="more.files" \
               select="concat(normalize-space(substring-after($$current.files, ^^ ^^)),^^ ^^)"/> \
    <xsl:param name="file.number" select="1"/> \
    <xsl:param name="filename" select="concat(^^./build/^^,$$file.number,^^.xml^^)"/> \
 \
    <xsl:choose> \
      <xsl:when test="$$more.files = ^^ ^^"/> \
      <xsl:when test="$$count mod $$chunk.size = 0"> \
        <xsl:variable name="fileset" select="concat($$current.files, ^^ ^^, \
          substring-before($$more.files, ^^ ^^))"/> \
        <exsl:document href="{$$filename}" \
                       method="xml" \
                       encoding="UTF-8" \
                       indent="yes" \
                       omit-xml-declaration="yes" \
                       media-type="" \
                       standalone="no"> \
          <reference> \
            <title>foo</title> \
            <xsl:call-template name="make.xinclude"> \
              <xsl:with-param name="file"> \
                <xsl:choose> \
                  <xsl:when test="contains($$fileset, ^^ ^^)"> \
                    <xsl:value-of \
                        select="normalize-space(substring-before($$fileset, ^^ ^^))"/> \
                  </xsl:when> \
                  <xsl:otherwise> \
                    <xsl:value-of select="$$fileset"/> \
                  </xsl:otherwise> \
                </xsl:choose> \
              </xsl:with-param> \
              <xsl:with-param \
                  name="remaining.files" \
                  select="concat(normalize-space(substring-after($$fileset, ^^ ^^)),^^ ^^)"/> \
            </xsl:call-template> \
          </reference> \
        </exsl:document> \
        <xsl:call-template name="make.file"> \
          <xsl:with-param name="count" select="1"/> \
          <xsl:with-param name="current.files"  \
                          select="$$more.files"/> \
          <xsl:with-param name="file.number" select="number($$file.number) + 1"/> \
          <xsl:with-param name="filename" select="concat(^^./build/^^,$$file.number,^^.xml^^)"/> \
        </xsl:call-template> \
      </xsl:when> \
      <xsl:otherwise> \
        <xsl:call-template name="make.file"> \
          <xsl:with-param name="count" select="$$count + 1"/> \
          <xsl:with-param name="current.files"> \
            <xsl:choose> \
              <xsl:when test="$$count = 1 and $$file.number = 1"> \
                <xsl:value-of  \
                    select="concat(substring-before($$current.files, ^^ ^^), \
                            ^^ ^^, \
                            substring-before($$more.files, ^^ ^^))"/> \
              </xsl:when> \
              <xsl:when test="$$count = 1"> \
                <xsl:value-of  \
                    select="substring-before($$more.files, ^^ ^^)"/> \
              </xsl:when> \
              <xsl:otherwise> \
                <xsl:value-of  \
                    select="concat($$current.files, ^^ ^^, \
                            substring-before($$more.files, ^^ ^^))"/> \
              </xsl:otherwise> \
            </xsl:choose> \
          </xsl:with-param> \
          <xsl:with-param name="more.files" \
                          select="substring-after($$more.files, ^^ ^^)"/> \
          <xsl:with-param name="file.number" select="$$file.number"/> \
        </xsl:call-template> \
      </xsl:otherwise> \
    </xsl:choose> \
  </xsl:template> \
 \
  <xsl:template name="make.xinclude"> \
    <xsl:param name="file"/> \
    <xsl:param name="remaining.files"/> \
    <xsl:param name="count" select="1"/> \
    <xsl:if test="not($$file = ^^^^)"> \
      <xi:include href="../{$$file}"/> \
      <xsl:call-template name="make.xinclude"> \
        <xsl:with-param \
            name="file" \
            select="substring-before($$remaining.files, ^^ ^^)"/> \
        <xsl:with-param \
            name="remaining.files" \
            select="substring-after($$remaining.files, ^^ ^^)"/> \
        <xsl:with-param name="count" select="$$count + 1"/> \
      </xsl:call-template> \
    </xsl:if> \
  </xsl:template> \
 \
</xsl:stylesheet>

all: man

man: build/man

build/Makefile:
	if [ ! -d build ]; then mkdir build; fi
	$(WGET) $(WGET_FLAGS) -O $@ $(MAN_XSL)

combine.xsl: Makefile
	@echo '$(COMBINE_XSL)' > $@
	$(SED) $(SED_FLAGS) "s/\^\^/'/g" $@

build/1.xml: combine.xsl
	$(XSLTPROC) $(XSLTPROC_FLAGS) \
	--stringparam files "$(FILES)" \
	--stringparam chunk.size $(CHUNKSIZE) \
	$< $<

build/man: build/Makefile build/1.xml
	time $(MAKE) -C build man \
		MAN_PARAMS="--stringparam man.output.quietly 1 \
		   --stringparam refentry.meta.get.quietly 1 \
		   --stringparam man.charmap.enabled 0"

debug:

clean:
	$(RM) -r build