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

std: Avoid ptr::copy if unnecessary in vec::Drain #50575

Merged
merged 1 commit into from
May 11, 2018

Commits on May 9, 2018

  1. std: Avoid ptr::copy if unnecessary in vec::Drain

    This commit is spawned out of a performance regression investigation in rust-lang#50496.
    In tracking down this regression it turned out that the `expand_statements`
    function in the compiler was taking quite a long time. Further investigation
    showed two key properties:
    
    * The function was "fast" on glibc 2.24 and slow on glibc 2.23
    * The hottest function was memmove from glibc
    
    Combined together it looked like glibc gained an optimization to the memmove
    function in 2.24. Ideally we don't want to rely on this optimization, so I
    wanted to dig further to see what was happening.
    
    The hottest part of `expand_statements` was `Drop for Drain` in the call to
    `splice` where we insert new statements into the original vector. This *should*
    be a cheap operation because we're draining and replacing iterators of the exact
    same length, but under the hood memmove was being called a lot, causing a
    slowdown on glibc 2.23.
    
    It turns out that at least one of the optimizations in glibc 2.24 was that
    `memmove` where the src/dst are equal becomes much faster. [This program][prog]
    executes in ~2.5s against glibc 2.23 and ~0.3s against glibc 2.24, exhibiting
    how glibc 2.24 is optimizing `memmove` if the src/dst are equal.
    
    And all that brings us to what this commit itself is doing. The change here is
    purely to `Drop for Drain` to avoid the call to `ptr::copy` if the region being
    copied doesn't actually need to be copied. For normal usage of just `Drain`
    itself this check isn't really necessary, but because `Splice` internally
    contains `Drain` this provides a nice speed boost on glibc 2.23. Overall this
    should fix the regression seen in rust-lang#50496 on glibc 2.23 and also fix the
    regression on Windows where `memmove` looks to not have this optimization.
    
    Note that the way `splice` was called in `expand_statements` would cause a
    quadratic number of elements to be copied via `memmove` which is likely why the
    tuple-stress benchmark showed such a severe regression.
    
    Closes rust-lang#50496
    
    [prog]: https://gist.github.com/alexcrichton/c05bc51c6771bba5ae5b57561a6c1cd3
    alexcrichton committed May 9, 2018
    Configuration menu
    Copy the full SHA
    254b601 View commit details
    Browse the repository at this point in the history