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

Improve Element#attribute implementation as 6500x faster #146

Merged
merged 3 commits into from
Jun 13, 2024

Conversation

makenowjust
Copy link
Contributor

@makenowjust makenowjust commented Jun 13, 2024

Element#namespaces is heavy method because this method needs to traverse all ancestors of the element. Element#attribute calls namespaces redundantly, so it is much slower.

This PR reduces namespaces calls in Element#attribute. Also, this PR removes a redundant respond_to? because namespaces must return Hash in the current implementation.

Below is the result of a benchmark for this on my laptop.

RUBYLIB= BUNDLER_ORIG_RUBYLIB= /Users/makenowjust/Projects/github.com/makenowjust/simple-dotfiles/.asdf/installs/ruby/3.3.2/bin/ruby -v -S benchmark-driver /Users/makenowjust/Projects/github.com/ruby/rexml/benchmark/attribute.yaml
ruby 3.3.2 (2024-05-30 revision e5a195edf6) [arm64-darwin23]
Calculating -------------------------------------
                     rexml 3.2.6      master  3.2.6(YJIT)  master(YJIT)
   attribute_with_ns     425.420     849.271       5.336k       10.629k i/s -      1.000k times in 2.350620s 1.177481s 0.187416s 0.094084s
attribute_without_ns     834.750      5.587M      10.656k        2.950M i/s -      1.000k times in 1.197963s 0.000179s 0.093846s 0.000339s

Comparison:
                attribute_with_ns
        master(YJIT):     10628.8 i/s
         3.2.6(YJIT):      5335.7 i/s - 1.99x  slower
              master:       849.3 i/s - 12.52x  slower
         rexml 3.2.6:       425.4 i/s - 24.98x  slower

             attribute_without_ns
              master:   5586593.2 i/s
        master(YJIT):   2949854.4 i/s - 1.89x  slower
         3.2.6(YJIT):     10655.8 i/s - 524.28x  slower
         rexml 3.2.6:       834.8 i/s - 6692.53x  slower

This result shows that Element#attribute is now 6500x faster than the old implementation if namespace is not supplied.

It seems strange that it is slower when YJIT is enabled, but we believe this is a separate issue.

Thank you.

`Element#namespaces` is heavy method because this method needs to
traverse all ancestors of the element. `Element#attribute` calls
`namespaces` redundantly, so it is much slower.

This commit reduces `namespaces` calls in `Element#attribute`.
Also, this commit removes a redundant `respond_to?` because
`namespaces` must return `Hash` in the current implementation.
benchmark/attribute.yaml Outdated Show resolved Hide resolved
Comment on lines 40 to 42
attribute_with_ns: |
deepest_node.attribute("with_ns", "xyz")
attribute_without_ns: |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attribute_ is redundant because this file is attribute.yaml.
Can we use with_ns/without_ns or something?

else
prefix = namespaces.index(namespace) if namespace
end
prefix = namespaces.key(namespace) if namespace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
prefix = namespaces.key(namespace) if namespace
prefix = namespaces[namespace] if namespace

may be faster than namespaces.key(namespace).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namespaces.key(namespace) means namespaces.invert[namespace]. Your suggestion changes the code's meaning.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry.

@kou kou merged commit 3b026f8 into ruby:master Jun 13, 2024
61 checks passed
@makenowjust makenowjust deleted the improve-attribute branch June 13, 2024 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants