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

String::from and str::to_owned are not inlined #53681

Closed
nagisa opened this issue Aug 24, 2018 · 11 comments
Closed

String::from and str::to_owned are not inlined #53681

nagisa opened this issue Aug 24, 2018 · 11 comments
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-slow Issue: Problems and improvements with respect to performance of generated code. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@nagisa
Copy link
Member

nagisa commented Aug 24, 2018

#![crate_type="rlib"]

pub fn banana() -> String {
    String::from("")
}

pub fn peach() -> String {
    "".to_owned()
}

pub fn expected() -> String {
    unsafe {
    String::from_utf8_unchecked("".as_bytes().to_owned())
    }
}

Playground (Use show assembly or llvm-ir, make sure to turn on optimisations)

All these functions should be equivalent.

@nagisa nagisa added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. E-help-wanted Call for participation: Help is requested to fix this issue. labels Aug 24, 2018
@nagisa
Copy link
Member Author

nagisa commented Aug 24, 2018

A fix would involve adding an #[inline] attribute in following locations:

fn from(s: &'a str) -> String {

fn to_owned(&self) -> String {

@nagisa
Copy link
Member Author

nagisa commented Aug 24, 2018

It might be prudent to also investigate whether similar one-liner functions are inlined (if they haven’t an #[inline] attribute already).

@nagisa nagisa added I-slow Issue: Problems and improvements with respect to performance of generated code. and removed E-help-wanted Call for participation: Help is requested to fix this issue. labels Aug 24, 2018
@matthiaskrgr
Copy link
Member

I can have a look tomorrow.
I played around with -C inline-threshold earlier on godbolt but it didn't seem to have an effect at all which I don't quite understand https://rust.godbolt.org/z/b3Se3j

@matthiaskrgr
Copy link
Member

Note on the side: for "", expected() has the fewest instructions, but if I pass a none zero &str into the functions expected() has the most instns (might still be worth it, may need benchmarks) https://rust.godbolt.org/z/ep1ivP

@nagisa
Copy link
Member Author

nagisa commented Aug 24, 2018

-Cinline-threshold does not work in this scenario because this function already has an instantiation in liballoc (i.e another codegen unit) and therefore is not available for inlining at all. #[inline] would make it available for inlining again, I believe.

if I pass a none zero &str into the functions expected() has the most instns (might still be worth it, may need benchmarks

Right, because it starts allocating stuff. It will result in larger binary (if actually inlined), but that already happens for [T]::to_owned, so it should be fine for str::to_owned as well.

@ollie27
Copy link
Member

ollie27 commented Aug 24, 2018

The #[inline] attribute was actually removed by #32182.

@matthiaskrgr
Copy link
Member

Interesting, so if I understand correctly the motivation for the "outlining" was to make the functions generate the same code by llvm.
I guess it's ok if we mark all of them #[inline]?

@ollie27
Copy link
Member

ollie27 commented Aug 26, 2018

Adding #[inline] might bloat binary sizes which I believe is why it was removed. You'll have to test if it's actually worth it.

@matthiaskrgr
Copy link
Member

I did a quick and dirty test and rust/build/x86_64-unknown-linux-gnu/stage2/lib size went from 212_929_188 bytes to 213_310_526 bytes, so an increase of 381_338 bytes.

@matthiaskrgr
Copy link
Member

matthiaskrgr commented Sep 25, 2018

Here are the size change numbers of some tools (sizes in bytes):

binary master inline diff %diff
cargo 12852720 12900008 +47288 +0.36%
clippy-driver 5561512 5579672 +18160 +0.34%
rls 22212128 22347944 +135816 +0.61%
rustfmt 7744464 7768376 +23912 +0.30%

bors added a commit that referenced this issue Sep 27, 2018
liballoc: mark str.to_owned() and String::from(&str) as #[inline].

Fixes #53681
@jens1o
Copy link
Contributor

jens1o commented Sep 30, 2018

How much faster is it?

bors added a commit that referenced this issue Oct 9, 2018
liballoc: mark str.to_owned() and String::from(&str) as #[inline].

Fixes #53681
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-slow Issue: Problems and improvements with respect to performance of generated code. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants