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

Check for an extant attribute before interning in setAttribute #8645

Conversation

@fitzgen
Copy link
Member

fitzgen commented Nov 22, 2015

Interning a DOMString as an atom can be expensive, and that work is unnecessary
if the attribute being added already exists and already has an interned
name. Instead of eagerly interning, first do a linear search over the existing
attributes to see if we can skip interning. This is an optimization that Gecko
already employs, as described in #6906.

I tested Dromaeo's dom subsuite and a super naive micro benchmark of my own
writing.

I haven't looked at Dromaeo's code, but given the units it reports, I'm assuming
that higher is better.

For my super naive micro benchmark, smaller is better.

Here are the results:

+---------+-------------------------+----------------------+----------------+
|         | Servo w/out this commit | Servo w/ this commit | Gecko          |
+---------+-------------------------+----------------------+----------------+
| Dromaeo | 2684.37 runs/s          | 2721.35 runs/s       | 2068.78 runs/s |
+---------+-------------------------+----------------------+----------------+
| Micro   | 4985 ms                 | 4540 ms              | 1616 ms        |
+---------+-------------------------+----------------------+----------------+

So this seems to yield a slight performance increase, but nothing to write home
about. This could potentially hurt performance when there are many attributes or
if the attribute names are very long; intuitively, neither seem super common to me.

Here is the source of my super naive micro benchmark:

<!DOCTYPE html>
<body>
    <button onclick="run()">Test</button>
    <h1 id="result"></h1>
    <script>
        function run() {
            var h1 = document.getElementById("result");
            var start = Date.now();
            var i = 10000000;
            while (i--) {
                h1.setAttribute("foobar", "baz");
            }
            h1.textContent = Date.now() - start;
        }
    </script>
</body>

Review on Reviewable

@Ms2ger
Copy link
Contributor

Ms2ger commented Nov 22, 2015

I'm afraid this is wrong.

<!DOCTYPE html>
<div>...</div>
<script>
var e = document.body;
e.setAttributeNS(null, "FOO", "bar");
console.log(e.getAttributeNS(null, "FOO"));
console.log(e.getAttributeNS(null, "foo"));
e.setAttribute("FOO", "quux");
console.log(e.getAttributeNS(null, "FOO"));
console.log(e.getAttributeNS(null, "foo"));
window.close()
</script>

currently correctly logs

bar
null
bar
quux

and with your change logs

bar
null
quux
null
@Ms2ger Ms2ger self-assigned this Nov 22, 2015
@Ms2ger
Copy link
Contributor

Ms2ger commented Nov 22, 2015

I'm also not convinced I want to slow down all the parse_plain_attribute matches.

@eefriedman
Copy link
Contributor

eefriedman commented Nov 22, 2015

The parse_plain_attribute change could probably be avoided by grabbing the appropriate atom off of the Attr.

@fitzgen
Copy link
Member Author

fitzgen commented Nov 22, 2015

The parse_plain_attribute change could probably be avoided by grabbing the appropriate atom off of the Attr.

Yeah, I was just about to comment when I realized it was already there. Adding the namespace check and reverting the parse_plain_attribute changes. New patch in a bit.

I didn't see any wpt test failures, are there other tests that would have caught this?

@eefriedman
Copy link
Contributor

eefriedman commented Nov 22, 2015

The relevant tests are in tests/wpt/web-platform-tests/dom/nodes/attributes.html ; there might not be a test for the particular bug you introduced.

@fitzgen fitzgen force-pushed the fitzgen:check-if-attribute-exists-before-interning branch from 2bcfb19 to 606d9bf Nov 22, 2015
@fitzgen
Copy link
Member Author

fitzgen commented Nov 22, 2015

Fixed it up, added the test case from #8645 (comment) to tests/wpt/web-platform-tests/dom/nodes/attributes.html, reverted the parse_plain_attribute changes.

Benchmark numbers are about the same. See the commit message.

r? @Ms2ger

@bors-servo
Copy link
Contributor

bors-servo commented Nov 25, 2015

The latest upstream changes (presumably #8671) made this pull request unmergeable. Please resolve the merge conflicts.

Interning a DOMString as an atom can be expensive, and that work is unnecessary
if the attribute being added already exists and already has an interned
name. Instead of eagerly interning, first do a linear search over the existing
attributes to see if we can skip interning. This is an optimization that Gecko
already employs, as described in #6906.

I tested Dromaeo's dom subsuite and a super naive micro benchmark of my own
writing.

I haven't looked at Dromaeo's code, but given the units it reports, I'm assuming
that higher is better.

For my super naive micro benchmark, smaller is better.

Here are the results:

+---------+-------------------------+----------------------+----------------+
|         | Servo w/out this commit | Servo w/ this commit | Gecko          |
+---------+-------------------------+----------------------+----------------+
| Dromaeo | 2684.37 runs/s          | 2771.50 runs/s       | 2068.78 runs/s |
+---------+-------------------------+----------------------+----------------+
| Micro   | 4985 ms                 | 4606 ms              | 1616 ms        |
+---------+-------------------------+----------------------+----------------+

So this seems to yield a slight performance increase, but nothing to write home
about. This could potentially hurt performance when there are many attributes or
if the attribute names are very long; intuitively, neither seem super common to
me.

Here is the source of my super naive micro benchmark:

```html
<!DOCTYPE html>
<body>
    <button onclick="run()">Test</button>
    <h1 id="result"></h1>
    <script>
        function run() {
            var h1 = document.getElementById("result");
            var start = Date.now();
            var i = 10000000;
            while (i--) {
                h1.setAttribute("foobar", "baz");
            }
            h1.textContent = Date.now() - start;
        }
    </script>
</body>
```
@fitzgen fitzgen force-pushed the fitzgen:check-if-attribute-exists-before-interning branch from 606d9bf to 4a42093 Nov 28, 2015
@fitzgen
Copy link
Member Author

fitzgen commented Nov 28, 2015

The latest upstream changes (presumably #8671) made this pull request unmergeable. Please resolve the merge conflicts.

Rebased and fixed.

@jdm jdm removed the S-needs-rebase label Nov 28, 2015
@fitzgen
Copy link
Member Author

fitzgen commented Dec 2, 2015

@Ms2ger review ping

@frewsxcv
Copy link
Member

frewsxcv commented Dec 18, 2015

@Ms2ger review ping

Also going to ping @asajeffrey since this is related to strings

@Ms2ger
Copy link
Contributor

Ms2ger commented Dec 18, 2015

I need to try to prove this correct; feel free to help with that :)

@asajeffrey
Copy link
Member

asajeffrey commented Dec 18, 2015

Also, I'm about to commit a patch which makes Atom -> DOMString -> Atom essentially free. This may impact the performance results.

@bors-servo
Copy link
Contributor

bors-servo commented Dec 21, 2015

The latest upstream changes (presumably #9038) made this pull request unmergeable. Please resolve the merge conflicts.

@nox
Copy link
Member

nox commented Feb 27, 2016

Closed for the same reason as #8668.

@nox nox closed this Feb 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

9 participants
You can’t perform that action at this time.