Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#3490): Attempt To Speed Up The add-refs.xsl #3491

Merged
merged 9 commits into from
Nov 15, 2024
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
Loading