linker: Use sequences for stacks (instead of trees)

This has a significant performance impact: processing time is cut in about
half and memory usage is reduced by more than 50%.  For example, a
package that previously took 30s and 2.1GiB of memory to link now takes
14s and less than 900MiB of memory.

I had tried to perform this optimization a couple years ago but was
thwarted (I think) by the classifier markers.  The previous commit did away
with those.  I'm encouraged by the gains from the low-hanging fruit.

* src/current/compiler/linker.xsl
  (l:process-empty, l:stack-empty): Convert from l:pstack and
    l:sym-stack (respectively) to empty preproc:sym sequences.
  (l:depgen-process-sym)[preproc:sym]: Append to sequence rather than
    outputting new l:sym-stack tree.
  Update all annotations and uses accordingly.
master
Mike Gerwitz 2018-07-13 23:34:43 -04:00
parent f2db9f1268
commit d624ee6d7e
1 changed files with 41 additions and 48 deletions

View File

@ -57,13 +57,11 @@
<variable name="l:orig-root" as="document-node( element( lv:package ) )" <variable name="l:orig-root" as="document-node( element( lv:package ) )"
select="/" /> select="/" />
<variable name="l:process-empty" as="element( l:pstack )"> <variable name="l:process-empty" as="element( preproc:sym )*"
<l:pstack /> select="()" />
</variable>
<variable name="l:stack-empty" as="element( l:sym-stack )"> <variable name="l:stack-empty" as="element( preproc:sym )*"
<l:sym-stack /> select="()" />
</variable>
<template match="*" mode="l:link" priority="1"> <template match="*" mode="l:link" priority="1">
@ -115,7 +113,7 @@
<l:dep> <l:dep>
<!-- empty stack --> <!-- empty stack -->
<apply-templates select="preproc:symtable" mode="l:depgen"> <apply-templates select="preproc:symtable" mode="l:depgen">
<with-param name="stack" select="$l:stack-empty" as="element( l:sym-stack )" /> <with-param name="stack" select="$l:stack-empty" />
</apply-templates> </apply-templates>
</l:dep> </l:dep>
</variable> </variable>
@ -175,8 +173,8 @@
<template mode="l:depgen" as="element( preproc:sym )*" <template mode="l:depgen" as="element( preproc:sym )*"
match="preproc:symtable"> match="preproc:symtable">
<param name="stack" as="element( l:sym-stack )" <param name="stack" as="element( preproc:sym )*"
select="$l:stack-empty" /> select="()" />
<!-- we care only of the symbols used by lv:yields, from which all <!-- we care only of the symbols used by lv:yields, from which all
dependencies may be derived (if it's not derivable from the yield dependencies may be derived (if it's not derivable from the yield
@ -209,7 +207,7 @@
<variable name="result" as="element()+"> <variable name="result" as="element()+">
<call-template name="l:depgen-sym"> <call-template name="l:depgen-sym">
<with-param name="pending" select="$yields" /> <with-param name="pending" select="$yields" />
<with-param name="stack" select="$stack" as="element( l:sym-stack )" /> <with-param name="stack" select="$stack" />
</call-template> </call-template>
</variable> </variable>
@ -235,24 +233,24 @@
<template name="l:depgen-sym" as="element( preproc:sym )*"> <template name="l:depgen-sym" as="element( preproc:sym )*">
<param name="pending" as="element( preproc:sym )*" /> <param name="pending" as="element( preproc:sym )*" />
<param name="stack" as="element( l:sym-stack )" /> <param name="stack" as="element( preproc:sym )*" />
<param name="path" as="xs:string" <param name="path" as="xs:string"
select="''" /> select="''" />
<param name="processing" as="element( l:pstack )" <param name="processing" as="element( preproc:sym )*"
select="$l:process-empty" /> select="$l:process-empty" />
<variable name="pend-count" as="xs:integer" <variable name="pend-count" as="xs:integer"
select="count( $pending )" /> select="count( $pending )" />
<variable name="stack-count" as="xs:integer" <variable name="stack-count" as="xs:integer"
select="count( $stack/preproc:sym )" /> select="count( $stack )" />
<variable name="process-count" as="xs:integer" <variable name="process-count" as="xs:integer"
select="count( $processing/* )" /> select="count( $processing )" />
<choose> <choose>
<!-- if there are no pending symbols left, then we are done; return the <!-- if there are no pending symbols left, then we are done; return the
stack --> stack -->
<when test="$pend-count = 0"> <when test="$pend-count = 0">
<sequence select="$stack/*" /> <sequence select="$stack" />
</when> </when>
@ -277,9 +275,9 @@
<text>r - </text> <text>r - </text>
<value-of select="$cur/@name" /> <value-of select="$cur/@name" />
<text> [s:: </text> <text> [s:: </text>
<value-of select="$stack/preproc:sym/@name" /> <value-of select="$stack/@name" />
<text> ::s] [r:: </text> <text> ::s] [r:: </text>
<value-of select="$processing/preproc:sym/@name" /> <value-of select="$processing/@name" />
<text>::r]</text> <text>::r]</text>
</with-param> </with-param>
</call-template> </call-template>
@ -361,9 +359,9 @@
--> -->
<template match="preproc:sym[ @extern='true' ]" mode="l:depgen-process-sym" priority="5"> <template match="preproc:sym[ @extern='true' ]" mode="l:depgen-process-sym" priority="5">
<param name="pending" as="element( preproc:sym )*" /> <param name="pending" as="element( preproc:sym )*" />
<param name="stack" as="element( l:sym-stack )" /> <param name="stack" as="element( preproc:sym )*" />
<param name="path" as="xs:string" /> <param name="path" as="xs:string" />
<param name="processing" as="element( l:pstack )" /> <param name="processing" as="element( preproc:sym )*" />
<variable name="cur" select="." /> <variable name="cur" select="." />
@ -407,7 +405,7 @@
<text>); pulled in by: </text> <text>); pulled in by: </text>
<!-- help the user figure out how this happened --> <!-- help the user figure out how this happened -->
<for-each select="$processing/preproc:sym"> <for-each select="$processing">
<if test="position() gt 1"> <if test="position() gt 1">
<text> - </text> <text> - </text>
</if> </if>
@ -433,7 +431,7 @@
<!-- use the resolved symbol in place of the original extern --> <!-- use the resolved symbol in place of the original extern -->
<apply-templates select="$eresolv-uniq" mode="l:depgen-process-sym"> <apply-templates select="$eresolv-uniq" mode="l:depgen-process-sym">
<with-param name="pending" select="$pending" /> <with-param name="pending" select="$pending" />
<with-param name="stack" select="$stack" as="element( l:sym-stack )" /> <with-param name="stack" select="$stack" />
<with-param name="path" select="$path" /> <with-param name="path" select="$path" />
<with-param name="processing" select="$processing" /> <with-param name="processing" select="$processing" />
</apply-templates> </apply-templates>
@ -443,9 +441,9 @@
<template mode="l:depgen-process-sym" priority="1" <template mode="l:depgen-process-sym" priority="1"
match="preproc:sym"> match="preproc:sym">
<param name="pending" as="element( preproc:sym )*" /> <param name="pending" as="element( preproc:sym )*" />
<param name="stack" as="element( l:sym-stack )" /> <param name="stack" as="element( preproc:sym )*" />
<param name="path" as="xs:string" /> <param name="path" as="xs:string" />
<param name="processing" as="element( l:pstack )" /> <param name="processing" as="element( preproc:sym )*" />
<variable name="cur" as="element( preproc:sym )" <variable name="cur" as="element( preproc:sym )"
select="." /> select="." />
@ -455,7 +453,7 @@
exception is if the circular dependency is a function, since that simply exception is if the circular dependency is a function, since that simply
implies recursion, which we can handle just fine --> implies recursion, which we can handle just fine -->
<variable name="circ" as="element( preproc:sym )*" <variable name="circ" as="element( preproc:sym )*"
select="$processing/preproc:sym[ select="$processing[
@name=$cur/@name @name=$cur/@name
and @src=$cur/@src ]" /> and @src=$cur/@src ]" />
@ -477,7 +475,7 @@
<call-template name="l:depgen-sym"> <call-template name="l:depgen-sym">
<with-param name="pending" select="remove( $pending, 1 )" /> <with-param name="pending" select="remove( $pending, 1 )" />
<with-param name="processing" select="$processing" /> <with-param name="processing" select="$processing" />
<with-param name="stack" select="$stack" as="element( l:sym-stack )" /> <with-param name="stack" select="$stack" />
</call-template> </call-template>
</when> </when>
@ -485,8 +483,7 @@
<!-- process; TODO: good refactoring point; large template --> <!-- process; TODO: good refactoring point; large template -->
<otherwise> <otherwise>
<variable name="existing" as="element( preproc:sym )*" <variable name="existing" as="element( preproc:sym )*"
select="$stack/preproc:sym[ select="$stack[ @name=$cur/@name ]" />
@name=$cur/@name ]" />
<!-- TODO: this uses @name instead of @src because of map import <!-- TODO: this uses @name instead of @src because of map import
paths; decide on one or the other --> paths; decide on one or the other -->
@ -518,7 +515,7 @@
<with-param name="pending" select="remove( $pending, 1 )" /> <with-param name="pending" select="remove( $pending, 1 )" />
<with-param name="processing" select="$processing" /> <with-param name="processing" select="$processing" />
<with-param name="stack" as="element( l:sym-stack )"> <with-param name="stack" as="element( preproc:sym )*">
<!-- if this symbol already exists on the stack, then there is no use <!-- if this symbol already exists on the stack, then there is no use
re-adding it (note that we check both the symbol name and its source re-adding it (note that we check both the symbol name and its source
since symbols could very well share a name due to exporting rules) --> since symbols could very well share a name due to exporting rules) -->
@ -546,27 +543,23 @@
</call-template> </call-template>
</variable> </variable>
<l:sym-stack> <!-- process the dependencies (note that this has the effect of
<!-- process the dependencies (note that this has the effect of outputting the existing stack as well, which is why we have
outputting the existing stack as well, which is why we have not yet done so) -->
not yet done so) --> <call-template name="l:depgen-sym">
<call-template name="l:depgen-sym"> <with-param name="pending" select="$deps-aug" />
<with-param name="pending" select="$deps-aug" /> <with-param name="stack" select="$stack" />
<with-param name="stack" select="$stack" as="element( l:sym-stack )" /> <with-param name="path" select="$mypath" />
<with-param name="path" select="$mypath" /> <with-param name="processing" as="element( preproc:sym )*">
<with-param name="processing" as="element( l:pstack )"> <sequence select="$processing" />
<l:pstack> <sequence select="$cur" />
<sequence select="$processing/*" /> </with-param>
<sequence select="$cur" /> </call-template>
</l:pstack>
</with-param>
</call-template>
<!-- finally, we can output ourself --> <!-- finally, we can output ourself -->
<preproc:sym> <preproc:sym>
<sequence select="$cur/@*" /> <sequence select="$cur/@*" />
</preproc:sym> </preproc:sym>
</l:sym-stack>
</when> </when>
@ -760,7 +753,7 @@
<value-of select="concat( $cur/@src, '/', $cur/@name )" /> <value-of select="concat( $cur/@src, '/', $cur/@name )" />
<text>): </text> <text>): </text>
<for-each select="$stack//preproc:sym"> <for-each select="$stack">
<if test="position() > 1"> <if test="position() > 1">
<text> - </text> <text> - </text>
</if> </if>