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

TokenStream::extend #53304

Merged
merged 2 commits into from
Aug 16, 2018
Merged

TokenStream::extend #53304

merged 2 commits into from
Aug 16, 2018

Conversation

dtolnay
Copy link
Member

@dtolnay dtolnay commented Aug 13, 2018

Two new insta-stable impls in libproc_macro:

impl Extend<TokenTree> for TokenStream
impl Extend<TokenStream> for TokenStream

proc_macro::TokenStream already implements FromIterator<TokenTree> and FromIterator<TokenStream> so I elected to support the same input types for Extend.

This commit reduces compile time of Serde derives by 60% (takes less than half as long to compile) as measured by building our test suite:

$ git clone https://github.com/serde-rs/serde
$ cd serde/test_suite
$ cargo check --tests --features proc-macro2/nightly
$ rm -f ../target/debug/deps/libtest_*.rmeta
$ time cargo check --tests --features proc-macro2/nightly
Before: 20.8 seconds
After: 8.6 seconds

r? @alexcrichton

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 13, 2018
@dtolnay
Copy link
Member Author

dtolnay commented Aug 13, 2018

Requires dtolnay/proc-macro2#114 in order to see the performance improvement.

offset: 0,
len: vec.len() as u32,
data: Lrc::new(vec),
}
Copy link
Member

Choose a reason for hiding this comment

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

Could this delegate to new_preserving_capacity after the shrink_to_fit?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

vec.truncate(self.offset as usize + self.len as usize);
// Drop any elements before our view of the data.
if self.offset != 0 {
vec.drain(..self.offset as usize);
Copy link
Member

Choose a reason for hiding this comment

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

Switching these two may be a bit more readable perhaps?

vec.drain(..self.offset as usize);
vec.truncate(self.len as usize);

Additionally, how come the drain is conditional?

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the conditional but I kept the order of truncate first then drain. I added a comment to explain -- draining first would involve unnecessarily shifting all the vector elements that are past the end of the current rc's view of the data.

Copy link
Member

Choose a reason for hiding this comment

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

Aha makes sense 👍

@alexcrichton
Copy link
Member

@bors: delegate=dtolnay

Looks great to me, very nice find! r=me with a few nits, and otherwise cc @rust-lang/libs, @nrc, and @petrochenkov on the API addition here.

@bors
Copy link
Contributor

bors commented Aug 13, 2018

✌️ @dtolnay can now approve this pull request

@dtolnay
Copy link
Member Author

dtolnay commented Aug 14, 2018

@bors r+

@bors
Copy link
Contributor

bors commented Aug 14, 2018

📌 Commit 69b9c23 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 14, 2018
@BurntPizza
Copy link
Contributor

@dtolnay I'd like to hear how you found this; just profiling while building a serde project?

@dtolnay
Copy link
Member Author

dtolnay commented Aug 14, 2018

@BurntPizza no profiling involved this time, although that would have revealed the problem. I think I've built enough of Serde / syn / quote / proc-macro2 to know where the skeletons are hidden and I finally got a chance to pursue this one.

The original code in alexcrichton/proc-macro2#114 performs a quadratic amount of memory allocation and copying when called the way quote! ends up calling it. I had brought up the need for Extend in #38356 (comment) during the design phase of Syn 0.14 and the quadratic approach was done as a stopgap until the impl could be written.

@BurntPizza
Copy link
Contributor

Ah, the "Because I'm a guru" methodology.
I wish I could apply it more often myself. ;)

@bors
Copy link
Contributor

bors commented Aug 16, 2018

⌛ Testing commit 69b9c23 with merge b559042...

bors added a commit that referenced this pull request Aug 16, 2018
TokenStream::extend

Two new insta-stable impls in libproc_macro:

```rust
impl Extend<TokenTree> for TokenStream
impl Extend<TokenStream> for TokenStream
```

`proc_macro::TokenStream` already implements `FromIterator<TokenTree>` and `FromIterator<TokenStream>` so I elected to support the same input types for `Extend`.

**This commit reduces compile time of Serde derives by 60% (takes less than half as long to compile)** as measured by building our test suite:

```console
$ git clone https://github.com/serde-rs/serde
$ cd serde/test_suite
$ cargo check --tests --features proc-macro2/nightly
$ rm -f ../target/debug/deps/libtest_*.rmeta
$ time cargo check --tests --features proc-macro2/nightly
Before: 20.8 seconds
After: 8.6 seconds
```

r? @alexcrichton
@bors
Copy link
Contributor

bors commented Aug 16, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: dtolnay
Pushing b559042 to master...

@bors bors merged commit 69b9c23 into rust-lang:master Aug 16, 2018
@dtolnay dtolnay deleted the extend branch August 16, 2018 18:03
Copy link
Member Author

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Perf looks clean, I see no regression from changing RcSlice to RcVec. perf comparison

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants