-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
memcpy-style copies of small fixed length arrays become memcpy, unless done via a loop with ops::Index #92993
Comments
This smells like a duplicate of #44099 |
@rustbot label +A-codegen +I-slow |
I just got bitten by this suboptimal codegen on a production project, and made a detailed write-up with performance analysis for my case here. From my experience, calling This is a fairly old problem that has been partially addressed with small-copy optimizations on the |
comparing a fixed-size copy and unknown-but-small-size copy, including llvm opt remarks: https://godbolt.org/z/MacG1Yrx3 even in the case of a fixed-size copy there's a
so in the typical case we're pretty dependent on LLVM deciding to turn calls to the intrinsic memcpy back into loads and stores! that, in turn, seems to happen in one of three places, two of which require constant-size
fsrm in particular is an interesting detail, because for processors supporting fast that seems like an indication that the "best" thing to do here is improve LLVM to handle the memcpy better, rather than avoiding the memcpy in LLVM entirely. (i recognize most of the above is more suitable for an LLVM issue, but prevalence of the memcpy intrinsic in code that optimizes well was a surprise!) bonus: related poor codegen from clang and workaround-ish in rusta contributing factor to this being more noticeable in Rust is once you know that it's very easy to replicate this with clang (clang godbolt), or "fix" this by using rust types that might alias (rustc godbolt). |
this empty commit reproduces a github comment that describes the work on commits from this point back to, roughly, 1.2.2. since many commits between these two points are interesting in the context of performance optimization (especially uarch-relevant tweaks), many WIP commits are preserved. as a result there is no clear squash merge, and this commit will be the next best thing. on Rust 1.68.0 and a Xeon E3-1230 V2, relative changes are measured roughly as: starting at ed4f238: - non-fmt ns/decode: 15ns - non-fmt instructions/decode: 94.6 - non-fmt IPC: 1.71 - fmt ns/decode+display: 91ns - fmt instructions/decode+display: 683.8 - fmt IPC: 2.035 ending at 6a5ea10 - non-fmt ns/decode: 15ns - non-fmt instructions/decode: 94.6 - non-fmt IPC: 1.71 - fmt ns/decode+display: 47ns - fmt instructions/decode+display: 329.6 - fmt IPC: 1.898 for an overall ~50% reduction in runtimes to display instructions. writing into InstructionTextBuffer reduces overhead another ~10%. -- original message follows -- this is where much of iximeow/yaxpeax-arch#7 originated. `std::fmt` as a primary writing mechanism has.. some limitations: * rust-lang/rust#92993 (comment) * llvm/llvm-project#87440 * rust-lang/rust#122770 and some more interesting more fundamental limitations - writing to a `T: fmt::Write` means implementations don't know if it's possible to write bytes in reverse order (useful for printing digits) or if it's OK to write too many bytes and then only advance `len` by the correct amount (useful for copying variable-length-but-short strings like register names). these are both perfectly fine to a `String` or `Vec`, less fine to do to a file descriptor like stdout. at the same time, `Colorize` and traits depending on it are very broken, for reasons described in yaxpeax-arch. so, this adapts `yaxpeax-x86` to use the new `DisplaySink` type for writing, with optimizations where appropriate and output spans for certain kinds of tokens - registers, integers, opcodes, etc. it's not a perfect replacement for Colorize-to-ANSI-supporting-outputs but it's more flexible and i think can be made right. along the way this completes the move of `safer_unchecked` out to yaxpeax-arch (ty @5225225 it's still so useful), cleans up some docs, and comes with a few new test cases. because of the major version bump of yaxpeax-arch, and because this removes most functionality of the Colorize impl - it prints the correct words, just without coloring - this is itself a major version bump to 2.0.0. yay! this in turn is a good point to change the `Opcode` enums from being tuple-like to struct-like, and i've done so in 1b8019d. full notes in CHANGELOG ofc. this is notes for myself when i'm trying to remember any of this in two years :)
godbolt demo
I have a
[u8; 4]
and I want to copy an unknown number of bytes from it into a&mut [u8]
. Based on benchmarking, on x86_64 at least it is much slower to callmemcpy
than it is to do a byte-by-byte copy. The fastest implementation of this pattern in Rust is this:That just doesn't seem right to me.
The text was updated successfully, but these errors were encountered: