Skip to content

Change an instance of .collect::<Vec<_>>().join("") to .collect::<String>() #95216

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

Closed
wants to merge 2 commits into from
Closed

Conversation

yoav-lavi
Copy link
Contributor

Hey,
I've noticed that compiler/rustc_resolve/src/late/diagnostics.rs uses .collect::<Vec<_>>().join(""); over .collect::<String>();, the latter being shorter, clearer and more performant:

    criterion.bench_function("bench 1", |bencher| {
        bencher.iter(|| {
            std::iter::repeat("'a, ")
                .take(10)
                .collect::<Vec<_>>()
                .join("");
        })
    });

    criterion.bench_function("bench 2", |bencher| {
        bencher.iter(|| {
            std::iter::repeat("'a, ").take(10).collect::<String>();
        })
    });
bench 1                 time:   [88.355 ns 88.526 ns 88.704 ns]                         
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
slope  [88.355 ns 88.704 ns] R^2            [0.9910173 0.9909753]
mean   [88.312 ns 88.623 ns] std. dev.      [640.43 ps 940.42 ps]
median [88.168 ns 88.576 ns] med. abs. dev. [587.33 ps 932.58 ps]

bench 2                 time:   [110.31 ns 110.50 ns 110.77 ns]                         
Found 5 outliers among 100 measurements (5.00%)
  5 (5.00%) high mild
slope  [110.31 ns 110.77 ns] R^2            [0.9907452 0.9903230]
mean   [110.85 ns 111.38 ns] std. dev.      [1.1039 ns 1.5752 ns]
median [110.25 ns 110.91 ns] med. abs. dev. [395.71 ps 1.1579 ns]

I'm currently working on a clippy PR to lint this issue but thought to create a manual PR for Deno

Thanks for your consideration!

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 22, 2022
@rust-highfive
Copy link
Contributor

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @wesleywiser (or someone else) soon.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 22, 2022
@the8472
Copy link
Member

the8472 commented Mar 22, 2022

Merge branch 'master' of https://github.com/yoav-lavi/rust

This runs afoul of the no-merge policy, you'll have to rebase.

@yoav-lavi
Copy link
Contributor Author

@the8472 Should be fine now

@yoav-lavi yoav-lavi changed the title .collect::<Vec<_>>().join(""); => .collect::<String>(); Change an instance of .collect::<Vec<_>>().join("") to .collect::<String>() Mar 22, 2022
@jackh726
Copy link
Member

bench 1                 time:   [88.355 ns 88.526 ns 88.704 ns]                         
bench 2                 time:   [110.31 ns 110.50 ns 110.77 ns]

Unless I'm reading this wrong, doesn't this suggest the opposite? That collecting into a vec and joining is faster?

@yoav-lavi
Copy link
Contributor Author

@jackh726 you're right, I misread the results in this case.

All other instances of .collect::<Vec<_>>().join("") that I checked were slower.
I wonder why it's behaving differently in this case, will look into it. Closing for now.

Thanks!

@yoav-lavi yoav-lavi closed this Mar 22, 2022
@yoav-lavi
Copy link
Contributor Author

yoav-lavi commented Mar 22, 2022

For instance if you take a similar case that Deno had:

    criterion.bench_function("1", |bencher| {
        bencher.iter(|| {
            let url = "https://google.com".to_owned();
            let split_specifier = url.as_str().split(':');
            split_specifier.skip(1).collect::<String>();
        })
    });

    criterion.bench_function("2", |bencher| {
        bencher.iter(|| {
            let url = "https://google.com".to_owned();
            let split_specifier = url.as_str().split(':');
            split_specifier.skip(1).collect::<Vec<_>>().join("");
        })
    });
1                       time:   [61.874 ns 61.959 ns 62.071 ns]                   
Found 14 outliers among 100 measurements (14.00%)
4 (4.00%) high mild
10 (10.00%) high severe
slope  [61.874 ns 62.071 ns] R^2            [0.9864790 0.9862826]
mean   [61.979 ns 62.326 ns] std. dev.      [424.74 ps 1.3139 ns]
median [61.842 ns 61.906 ns] med. abs. dev. [131.58 ps 218.49 ps]

2                       time:   [93.029 ns 93.209 ns 93.443 ns]                   
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
slope  [93.029 ns 93.443 ns] R^2            [0.9892041 0.9888479]
mean   [93.153 ns 93.528 ns] std. dev.      [626.57 ps 1.2486 ns]
median [92.996 ns 93.290 ns] med. abs. dev. [362.85 ps 716.21 ps]

@yoav-lavi
Copy link
Contributor Author

And my own benchmark:

fn criterion_benchmark(criterion: &mut Criterion) {
    criterion.bench_function("1", |bencher| {
        bencher.iter(|| {
            vec!["hello", "world"]
                .iter()
                .map(|item| item.to_uppercase())
                .collect::<Vec<String>>()
                .join("")
        })
    });
    criterion.bench_function("2", |bencher| {
        bencher.iter(|| {
            vec!["hello", "world"]
                .iter()
                .map(|item| item.to_uppercase())
                .collect::<String>()
        })
    });
}
1                       time:   [155.79 ns 155.97 ns 156.16 ns]                   
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) high mild
  2 (2.00%) high severe
slope  [155.79 ns 156.16 ns] R^2            [0.9971885 0.9971738]
mean   [155.87 ns 156.58 ns] std. dev.      [672.36 ps 2.9345 ns]
median [156.12 ns 156.26 ns] med. abs. dev. [209.02 ps 650.40 ps]

2                       time:   [118.11 ns 118.20 ns 118.28 ns]                   
Found 8 outliers among 100 measurements (8.00%)
  8 (8.00%) high severe
slope  [118.11 ns 118.28 ns] R^2            [0.9987699 0.9987697]
mean   [118.31 ns 118.87 ns] std. dev.      [794.06 ps 2.0461 ns]
median [117.96 ns 118.43 ns] med. abs. dev. [154.11 ps 692.31 ps]

@paolobarbolini
Copy link
Contributor

Compiler Explorer shows that although the generated assembly is simpler it doesn't unroll the loop as it does with .collect<Vec<_>>() https://rust.godbolt.org/z/WTxh83Y4z. This might be fixed by specialization!? (just guessing, I don't know too much about this stuff)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants