summary.xsl: Introduce maps for l:dep and preproc:symtable

This begins to chip away at the terrible performance of this system by using
maps where linear scans of the symbol table were otherwise taking place.

This does not yet touch `preproc:sym-deps`, which has the same problem.

Further, we may be able to get rid of symbol table maps per package by
utilizing `l:dep`; more to come.

This trims ~40s off of one of our larger programs (3m -> 2m20s), which is a
start, but there's still a ton of room for improvement.  I don't expect it
to be blazingly fast after all the optimization attempts---this has the same
problem as the XSLT-based linker did, which ended up being reimplemented in
Rust as TAMER---but it'll help to improve times in the meantime.

DEV-15153
main
Mike Gerwitz 2023-10-13 16:02:42 -04:00
parent 297bf4a506
commit 0928896935
1 changed files with 63 additions and 46 deletions

View File

@ -27,6 +27,7 @@
xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:lv="http://www.lovullo.com/rater" xmlns:lv="http://www.lovullo.com/rater"
xmlns:lvp="http://www.lovullo.com" xmlns:lvp="http://www.lovullo.com"
xmlns:c="http://www.lovullo.com/calc" xmlns:c="http://www.lovullo.com/calc"
@ -64,6 +65,14 @@
<xsl:variable name="program" select="/lv:package" /> <xsl:variable name="program" select="/lv:package" />
<xsl:variable name="program-symtable" as="element( l:dep )"
select="$program/l:dep" />
<xsl:variable name="program-symtable-map"
as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $program-symtable/preproc:sym
return map{ string( $sym/@name ) : $sym } )" />
<!-- <!--
Generate HTML page for a given rater/package Generate HTML page for a given rater/package
@ -115,7 +124,7 @@
<!-- intentional newline --> <!-- intentional newline -->
<xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html&gt; <xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html&gt;
</xsl:text> </xsl:text>
<html> <html>
<head> <head>
@ -144,30 +153,45 @@
<xsl:variable name="pkg-self" select=" <xsl:variable name="pkg-self" select="
document( concat( @__rootpath, @name, '.xmlo' ), . )/lv:* document( concat( @__rootpath, @name, '.xmlo' ), . )/lv:*
" /> " />
<xsl:apply-templates
select="$pkg-self/lv:*" /> <xsl:variable name="symtable-self" as="element( preproc:symtable )"
select="$pkg-self/preproc:symtable" />
<xsl:variable name="symtable-self-map" as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $symtable-self/preproc:sym
return map{ string( $sym/@name ) : $sym } )" />
<xsl:apply-templates select="$pkg-self/lv:*">
<xsl:with-param name="symtable-map" tunnel="yes"
select="$symtable-self-map" />
</xsl:apply-templates>
<!-- get a list of unique packages and typeset them --> <!-- get a list of unique packages and typeset them -->
<!-- TODO: this logic is duplicated; see gen-pkg-menu --> <!-- TODO: this logic is duplicated; see gen-pkg-menu -->
<xsl:for-each select=" <xsl:for-each-group select="$program-symtable/preproc:sym[
/lv:*/l:dep/preproc:sym[ @src and not( @src='' ) ]"
@src group-by="@src">
and not( @src='' )
and not(
@src=preceding-sibling::preproc:sym/@src
)
]
">
<xsl:message> <xsl:message>
<xsl:text>[summary] typesetting package </xsl:text> <xsl:text>[summary] typesetting package </xsl:text>
<xsl:value-of select="@src" /> <xsl:value-of select="@src" />
<xsl:text>...</xsl:text> <xsl:text>...</xsl:text>
</xsl:message> </xsl:message>
<xsl:apply-templates <xsl:variable name="pkg" as="element()"
select="document( concat( @src, '.xmlo' ), . )/lv:*/lv:*" /> select="document( concat( @src, '.xmlo' ), . )/lv:*" />
</xsl:for-each> <xsl:variable name="symtable" as="element( preproc:symtable )"
select="$pkg/preproc:symtable" />
<xsl:variable name="symtable-map" as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $symtable/preproc:sym
return map{ string( $sym/@name ) : $sym } )" />
<xsl:apply-templates select="$pkg/lv:*">
<xsl:with-param name="symtable-map" tunnel="yes"
select="$symtable-map" />
</xsl:apply-templates>
</xsl:for-each-group>
<!-- some general information --> <!-- some general information -->
<xsl:call-template name="summary-info" /> <xsl:call-template name="summary-info" />
@ -317,16 +341,9 @@
</xsl:apply-templates> </xsl:apply-templates>
<!-- get a list of unique packages --> <!-- get a list of unique packages -->
<xsl:for-each select=" <xsl:for-each-group select="$program-symtable/preproc:sym[
/lv:*/l:dep/preproc:sym[ @src and not( @src='' ) ]"
@src group-by="@src">
and not( @src='' )
and not(
@src=preceding-sibling::preproc:sym/@src
)
]
">
<!-- build package menu --> <!-- build package menu -->
<xsl:variable name="result"> <xsl:variable name="result">
<xsl:apply-templates select="$self" mode="gen-menu"> <xsl:apply-templates select="$self" mode="gen-menu">
@ -344,7 +361,7 @@
<xsl:copy-of select="$result" /> <xsl:copy-of select="$result" />
</xsl:if> </xsl:if>
</xsl:for-each> </xsl:for-each-group>
</div> </div>
</xsl:template> </xsl:template>
@ -628,6 +645,8 @@
FIXME: this is broken! FIXME: this is broken!
--> -->
<xsl:template match="lv:param|lv:const|lv:item" priority="1"> <xsl:template match="lv:param|lv:const|lv:item" priority="1">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:variable name="class"> <xsl:variable name="class">
<xsl:text>param</xsl:text> <xsl:text>param</xsl:text>
@ -656,10 +675,7 @@
local-name()" /> local-name()" />
<legend class="sym-{$type}"> <legend class="sym-{$type}">
<xsl:variable name="sym" <xsl:variable name="sym" select="$symtable-map( $name )" />
select="/lv:*/preproc:symtable
/preproc:sym[ @name=$name ]" />
<xsl:variable name="tex" select="$sym/@tex" /> <xsl:variable name="tex" select="$sym/@tex" />
<!-- only show symbol if it is defined (no need for a default since <!-- only show symbol if it is defined (no need for a default since
@ -1168,12 +1184,12 @@
@return anyOf match HTML @return anyOf match HTML
--> -->
<xsl:template match="lv:match[@anyOf]" mode="match-desc"> <xsl:template match="lv:match[@anyOf]" mode="match-desc">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:variable name="anyOf" select="@anyOf" /> <xsl:variable name="anyOf" select="@anyOf" />
<!-- attempt to locate the typedef --> <!-- attempt to locate the typedef -->
<xsl:variable name="typedef" select=" <xsl:variable name="typedef" select="$symtable-map( $anyOf )" />
/lv:*/preproc:symtable/preproc:sym[ @name=$anyOf ]
" />
<xsl:text>match any value in </xsl:text> <xsl:text>match any value in </xsl:text>
@ -1227,10 +1243,11 @@
@return match HTML @return match HTML
--> -->
<xsl:template match="lv:match[@value]" mode="match-desc"> <xsl:template match="lv:match[@value]" mode="match-desc">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:variable name="value" select="@value" /> <xsl:variable name="value" select="@value" />
<xsl:variable name="sym" <xsl:variable name="sym" select="$symtable-map( $value )" />
select="/lv:*/preproc:symtable/preproc:sym[ @name=$value ]" />
<xsl:text>= </xsl:text> <xsl:text>= </xsl:text>
@ -1255,11 +1272,13 @@
<xsl:template match="c:value-of" mode="match-desc" priority="5"> <xsl:template match="c:value-of" mode="match-desc" priority="5">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:variable name="name" <xsl:variable name="name"
select="@name" /> select="@name" />
<xsl:variable name="sym" as="element( preproc:sym )" <xsl:variable name="sym" as="element( preproc:sym )"
select="/lv:*/preproc:symtable/preproc:sym[ @name=$name ]" /> select="$symtable-map( $name )" />
<a href="#{$name}" class="sym-ref sym-{$sym/@type}"> <a href="#{$name}" class="sym-ref sym-{$sym/@type}">
<xsl:value-of select="$name" /> <xsl:value-of select="$name" />
@ -1387,6 +1406,8 @@
</xsl:template> </xsl:template>
<xsl:template match="lv:rate" mode="gen-rate-block"> <xsl:template match="lv:rate" mode="gen-rate-block">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:variable name="root" select="/" /> <xsl:variable name="root" select="/" />
<xsl:variable name="name" select="@yields" /> <xsl:variable name="name" select="@yields" />
@ -1401,9 +1422,7 @@
</xsl:attribute> </xsl:attribute>
<legend class="sym-rate"> <legend class="sym-rate">
<xsl:variable name="tex" select=" <xsl:variable name="tex" select="$symtable-map( $name )/@tex" />
/lv:*/preproc:symtable/preproc:sym[ @name=$name ]/@tex
" />
<!-- only show symbol if it is defined (no need for a default since <!-- only show symbol if it is defined (no need for a default since
defaults are specific to a given block) --> defaults are specific to a given block) -->
@ -1647,6 +1666,8 @@
</xsl:template> </xsl:template>
<xsl:template name="ultra-breakdown-set" match="c:*" mode="ultra-breakdown" priority="1"> <xsl:template name="ultra-breakdown-set" match="c:*" mode="ultra-breakdown" priority="1">
<xsl:param name="symtable-map" as="map(*)" tunnel="yes" />
<xsl:param name="label" select="if ( @label ) then @label else @desc" /> <xsl:param name="label" select="if ( @label ) then @label else @desc" />
<xsl:param name="c" select="." /> <xsl:param name="c" select="." />
@ -1691,9 +1712,7 @@
<xsl:if test="@name"> <xsl:if test="@name">
<xsl:variable name="name" select="@name" /> <xsl:variable name="name" select="@name" />
<xsl:variable name="sym" <xsl:variable name="sym" select="$symtable-map( $name )" />
select="/lv:*/preproc:symtable
/preproc:sym[ @name=$name ]" />
<xsl:variable name="ref" <xsl:variable name="ref"
select="if ( $sym/@parent ) then select="if ( $sym/@parent ) then
@ -2102,9 +2121,7 @@
<xsl:function name="preproc:sym-lookup" as="element( preproc:sym )?"> <xsl:function name="preproc:sym-lookup" as="element( preproc:sym )?">
<xsl:param name="name" as="xs:string" /> <xsl:param name="name" as="xs:string" />
<!-- XXX: There's a linker bug where there may be duplicate symbols in <xsl:sequence select="$program-symtable-map( $name )" />
l:dep! -->
<xsl:sequence select="$program/l:dep/preproc:sym[ @name=$name ][1]" />
</xsl:function> </xsl:function>