Skip to content

Commit

Permalink
Merge pull request #3491 from volodya-lombrozo/3490_add_refs
Browse files Browse the repository at this point in the history
feat(#3490): Attempt To Speed Up The `add-refs.xsl`
  • Loading branch information
yegor256 authored Nov 15, 2024
2 parents e4427a8 + 3230154 commit a0a4afe
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 49 deletions.
40 changes: 28 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,30 @@ All of them have something **we don't tolerate**:

* types ([why?](https://www.yegor256.com/2020/11/10/typing-without-types.html))
* static/class methods or attributes
([why?](http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html))
([why?](http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html))
* classes ([why?](http://www.yegor256.com/2016/09/20/oop-without-classes.html))
* implementation inheritance
([why?](http://www.yegor256.com/2016/09/13/inheritance-is-procedural.html))
([why?](http://www.yegor256.com/2016/09/13/inheritance-is-procedural.html))
* mutability
([why?](http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html)
and
[why not?](https://www.yegor256.com/2016/09/07/gradients-of-immutability.html))
([why?](http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html)
and
[why not?](https://www.yegor256.com/2016/09/07/gradients-of-immutability.html))
* NULL ([why?](http://www.yegor256.com/2014/05/13/why-null-is-bad.html))
* global scope
([why?](https://www.yegor256.com/2018/07/03/global-variables.html))
([why?](https://www.yegor256.com/2018/07/03/global-variables.html))
* type casting
([why?](http://www.yegor256.com/2015/04/02/class-casting-is-anti-pattern.html))
([why?](http://www.yegor256.com/2015/04/02/class-casting-is-anti-pattern.html))
* reflection
([why?](https://www.yegor256.com/2022/06/05/reflection-means-hidden-coupling.html))
([why?](https://www.yegor256.com/2022/06/05/reflection-means-hidden-coupling.html))
* scalar types and data primitives
* annotations
([why?](http://www.yegor256.com/2016/04/12/java-annotations-are-evil.html))
([why?](http://www.yegor256.com/2016/04/12/java-annotations-are-evil.html))
* operators
* traits and mixins
([why?](https://www.yegor256.com/2017/03/07/traits-and-mixins.html))
([why?](https://www.yegor256.com/2017/03/07/traits-and-mixins.html))
* flow control statements (`for`, `while`, `if`, etc)
* [syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar)
([why?](https://github.com/objectionary/eo/issues/51))
([why?](https://github.com/objectionary/eo/issues/51))

## Quick Start

Expand Down Expand Up @@ -242,7 +242,7 @@ Read about integration with Maven,

## Benchmark

This is how many milliseconds were spend on different
This is how many milliseconds were spent on different
XSL stylesheets during the execution of `mvn install` of
the `eo-runtime` module:

Expand Down Expand Up @@ -275,6 +275,21 @@ We show only the first 16 most expensive XSL stylesheets.

<!-- benchmark_end -->

You can run this benchmark locally with the following commands.
First, to generate the `measures.csv` file:

```shell
mvn clean install --errors --batch-mode -Deo.xslMeasuresFile=measures.csv
```

Then, to generate the report:

```shell
awk -F ',' '{ a[$1]+=$2; s+=$2; } END { for (k in a) \
printf("%s.xsl\t%d\t%0.2f%%\n", k, a[k], 100 * a[k]/s)}' \
eo-runtime/measures.csv | sort -g -k 2 | tail -r | column -t | head "-16"
```

## How to Contribute

Fork repository, make changes, then send us
Expand All @@ -297,4 +312,5 @@ to enhance the performance of EO components:
[![YourKit](https://www.yourkit.com/images/yklogo.png)](https://www.yourkit.com)

[cargo]: https://doc.rust-lang.org/cargo/getting-started/installation.html

[benchmark-gha]: https://github.com/objectionary/eo/actions/runs/11770647245
93 changes: 57 additions & 36 deletions eo-parser/src/main/resources/org/eolang/parser/add-refs.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="add-refs" version="2.0">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:eo="https://www.eolang.org" xmlns:xs="http://www.w3.org/2001/XMLSchema" id="add-refs" version="2.0">
<!--
Here we go through all objects and find what their @base
are referring to. If we find the object they refer to,
Expand All @@ -38,6 +38,7 @@ SOFTWARE.
defined in this particular file.
-->
<xsl:output encoding="UTF-8" method="xml"/>
<xsl:key name="o-by-name" match="o[@name]" use="@name"/>
<xsl:template match="o[not(@base='bytes' and /program/metas/meta[head='package' and tail='org.eolang'] and /program/objects/o[@name='bytes'])]">
<xsl:apply-templates select="." mode="not-bytes"/>
</xsl:template>
Expand All @@ -49,44 +50,41 @@ SOFTWARE.
</xsl:template>
<xsl:template match="o[@base!='$' and @base!='^']" mode="no-dots">
<xsl:variable name="current" select="."/>
<xsl:variable name="source" select="eo:closest($current, key('o-by-name', @base))"/>
<xsl:copy>
<xsl:variable name="parent" select="ancestor::*[o[@name=$current/@base]][1]"/>
<xsl:if test="$parent">
<xsl:variable name="source" select="$parent/o[@name=$current/@base]"/>
<xsl:if test="$parent">
<xsl:if test="count($source)!=1">
<xsl:message terminate="yes">
<xsl:text>Duplicate names inside "</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>", the base is "</xsl:text>
<xsl:value-of select="@base"/>
<xsl:text>" at the line #</xsl:text>
<xsl:if test="$source">
<xsl:if test="count($source)!=1">
<xsl:message terminate="yes">
<xsl:text>Duplicate names inside "</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>", the base is "</xsl:text>
<xsl:value-of select="@base"/>
<xsl:text>" at the line #</xsl:text>
<xsl:value-of select="@line"/>
<xsl:text> pointing to </xsl:text>
<xsl:for-each select="$source">
<xsl:if test="position()&gt;1">
<xsl:text>, </xsl:text>
</xsl:if>
<xsl:text>&lt;</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:text>/&gt;</xsl:text>
<xsl:text> at line #</xsl:text>
<xsl:value-of select="@line"/>
<xsl:text> pointing to </xsl:text>
<xsl:for-each select="$source">
<xsl:if test="position()&gt;1">
<xsl:text>, </xsl:text>
</xsl:if>
<xsl:text>&lt;</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:text>/&gt;</xsl:text>
<xsl:text> at line #</xsl:text>
<xsl:value-of select="@line"/>
</xsl:for-each>
<xsl:text>; it's internal bug</xsl:text>
</xsl:message>
</xsl:if>
<xsl:if test="not($source/@line)">
<xsl:message terminate="yes">
<xsl:text>Attribute @line is absent at "</xsl:text>
<xsl:value-of select="$source/@name"/>
<xsl:text>"</xsl:text>
</xsl:message>
</xsl:if>
<xsl:attribute name="ref">
<xsl:value-of select="$source/@line"/>
</xsl:attribute>
</xsl:for-each>
<xsl:text>; it's internal bug</xsl:text>
</xsl:message>
</xsl:if>
<xsl:if test="not($source/@line)">
<xsl:message terminate="yes">
<xsl:text>Attribute @line is absent at "</xsl:text>
<xsl:value-of select="$source/@name"/>
<xsl:text>"</xsl:text>
</xsl:message>
</xsl:if>
<xsl:attribute name="ref">
<xsl:value-of select="$source/@line"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
Expand All @@ -96,4 +94,27 @@ SOFTWARE.
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:function name="eo:closest" as="node()?">
<xsl:param name="current-node" as="node()"/>
<xsl:param name="nodes" as="node()*"/>
<xsl:variable name="intersecting-nodes" select="$nodes[eo:has-intersecting-route($current-node, .)]"/>
<xsl:for-each select="$intersecting-nodes">
<xsl:sort select="string-length(eo:get-route(.))" order="descending" data-type="number"/>
<xsl:if test="position() = 1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:function>
<xsl:function name="eo:has-intersecting-route" as="xs:boolean">
<xsl:param name="node1" as="node()"/>
<xsl:param name="node2" as="node()"/>
<xsl:variable name="route1" select="eo:get-route($node1)"/>
<xsl:variable name="route2" select="eo:get-route($node2)"/>
<xsl:sequence select="starts-with($route1, $route2)"/>
</xsl:function>
<xsl:function name="eo:get-route" as="xs:string">
<xsl:param name="node" as="node()"/>
<xsl:variable name="ancestors" select="$node/ancestor::*"/>
<xsl:sequence select="string-join(for $ancestor in $ancestors return generate-id($ancestor), '/')"/>
</xsl:function>
</xsl:stylesheet>
2 changes: 1 addition & 1 deletion src/test/groovy/check-xsl-id.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ project = new File('.')
project.traverse(
type : FileType.FILES,
preDir : { if (it.name == 'target') return FileVisitResult.SKIP_SUBTREE },
nameFilter : ~/.*\.xsl/
nameFilter : ~/.*\.xsl|xs3p.xsl/
) {
it ->
String id = new XmlSlurper().parse(it).@id
Expand Down

0 comments on commit a0a4afe

Please sign in to comment.