Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd an expect intrinsic #1131
Conversation
seanmonstar
reviewed
May 20, 2015
| `if expect(foo == bar, false) { .. }`. | ||
|
|
||
| The expected value is required to be a constant value. | ||
|
|
This comment has been minimized.
This comment has been minimized.
seanmonstar
May 20, 2015
Contributor
I assume you mean to use something like llvm.expect.i8 and converting the booleans to i8s, but this could be included in the Detailed Design.
Likewise, when I tried this myself by creating extern fn expect_i8 etc functions, linking against llvm, I couldn't find the optimizations in the asm. It'd be nice to see the improvements that such a function could possibly bring in this RFC.
This comment has been minimized.
This comment has been minimized.
Aatch
May 20, 2015
Author
Contributor
@seanmonstar actually, you can use llvm.expect.i1. As for improvements, that's hard to show since benchmark code tends to warm up the prediction table pretty quickly. It also isn't always visible in the asm if the code was already structured such that the blocks were ordered appropriately.
This comment has been minimized.
This comment has been minimized.
seanmonstar
May 20, 2015
Contributor
Right, but we don't have an i1, the smallest in rust is i8.
True about the benchmarks. I meant the compiled asm having the jump altered, before and after using expect.
This comment has been minimized.
This comment has been minimized.
Aatch
May 20, 2015
Author
Contributor
@seanmonstar actually, bools are now treated as i1s when generating LLVM IR.
This comment has been minimized.
This comment has been minimized.
seanmonstar
May 20, 2015
Contributor
Ah, very cool. That confusion may be even more reason to include the implementation details.
This comment has been minimized.
This comment has been minimized.
Aatch
May 20, 2015
Author
Contributor
Oh, and I left it out of the detailed design because I don't think the precise implementation details for a specific backend are important. Just the semantics of the intrinsic.
This comment has been minimized.
This comment has been minimized.
|
However, |
nrc
added
the
T-lang
label
May 20, 2015
This comment has been minimized.
This comment has been minimized.
|
This is something I'd like to see in Rust. However, the suggested 'syntax' seems weird (though some what traditional and I'm guessing close to llvm) from both from a use and implementation point of view: why is the intrinsic on the condition when the hint is about which branch is taken? If we start doing our own optimisations, I assume we'd have to be careful about any kind of code motion here in order to not break hinting to llvm. Could we instead have an attribute on the |
This comment has been minimized.
This comment has been minimized.
IIRC, this is because I'm fully in favor of this RFC... this is very important for getting optimal codegen in many cases and I've personally been wishing for it. Right now I've been resorting to #[cold] to get the desired behavior in a few cases, but it's too blunt of an instrument to use everywhere. |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
To me, the fact that a constant expression is necessary seems to argue for @nagisa The enum variant case could be done with dependent types, sort of: fn expect<const C: T, T=bool>(expr: T) {
/* ... */
expr
}
if expect::<true>( /* some expr */ ) { /* ... */ }
match expect::<Variant1, MyEnum>( /* some expr */ ) {
Variant1 => { /* ... */ }
_ => { /* ... */ }
}But that's a bit clunky and doesn't deal with patterns (e.g. if you want to state that a branch for Edit: My original example didn't make any sense at all. Hopefully it's better now. |
This comment has been minimized.
This comment has been minimized.
|
@quantheory yeah, I'd be happy with @nrc Ok, where would the attribute go? On the @nagisa most of the time use of branch hinting doesn't help at all. The fact that you can't hint about match expressions isn't really a concern I have. This is quite simply to help tune code where the penalty of a misprediction can end up quite large. Most of the time, the only difference this will make to codegen is block reordering (for example, we hint the overflow checks as being unlikely, which pushes the panics down to the bottom of the function). |
This comment has been minimized.
This comment has been minimized.
|
@quantheory |
This comment has been minimized.
This comment has been minimized.
|
@Aatch Seems reasonable to have the annotation on the condition. What about the idea of always assuming the |
This comment has been minimized.
This comment has been minimized.
|
I'd rather it not be an attribute, as that would make it harder when an if statement includes different conditions with different likelihoods. Take this example: https://github.com/h2o/picohttpparser/blob/master/picohttpparser.c#L173 |
This comment has been minimized.
This comment has been minimized.
That would lead to bad codegen when checking error conditions: if some_unexpected_error_condition {
return Err(...);
}Aside: It would also be nice to get likely/unlikely attributes for enum variants: enum Result<V, E> {
#[likely]
Ok(V),
#[unlikely]
Err(E)
}These wouldn't override an explicit likely/unlikely call on a branch but would provide sane defaults. Unfortunately, this would likely take quite a bit more work to implement. |
This comment has been minimized.
This comment has been minimized.
|
@nrc having the attribute on the condition is ultimately identical to having a function call wrapping the condition, no? I'd argue that an attribute on the condition itself would be really unclear, especially since you'd probably need to wrap the condition in parens anyway to be sure that it's applying to the correct expression. What this means is that instead of |
This comment has been minimized.
This comment has been minimized.
|
I really like the attribute on variants idea by @Stebalien |
This comment has been minimized.
This comment has been minimized.
|
@Aatch sorry, I was asking about the idea of always assuming the |
This comment has been minimized.
This comment has been minimized.
|
@nrc, I don't think we should have any guarantees for this feature beyond "doesn't change the observable behaviour of the function", meaning we could just ignore it if we wanted without technically doing anything wrong. In fact, there's no guarantee that it will do anything anyway. LLVM might have ordered the blocks the same way with or without the hint. I guess what I mean is that there isn't any behaviour to preserve for branch hinting. The point is that stuff like ordering blocks is pretty much arbitrary (especially in LLVM IR where you have to have a terminator, no fallthrough) so compilers make a best guess at how to do it. This just gives them another piece of information they can use to do so. If using |
This comment has been minimized.
This comment has been minimized.
bluss
commented
May 22, 2015
@Stebalien These hints shouldn't be used in a blanket way like this. The default should always be to let the branch prediction do its job. likely and unlikely seems like the most readable API. I would like if the eventual docs recommend profiling and not using these indiscriminately. I'm skeptical of this. Are we giving programmers the illusion of control? Isn't profile guided optimization the correct approach? It also appears that branch prediction hints are being obsoleted with newer microarchitectures. |
This comment has been minimized.
This comment has been minimized.
bluss
commented
May 22, 2015
|
I tested the basic benchmark in picohttpparser with and without the likely/unlikely hints. Just to show that it makes a
clang-3.5 with likely/unlikely
clang-3.5 without likely/unlikely
the difference is small but it's there. |
This comment has been minimized.
This comment has been minimized.
|
First, this seems like an important area to have support for in general. When I was at the NY meetup, I was approached by a few people working in the "HFT" area who had all sorts of questions about low-level codegen details like this. In most cases, the answer was basically "well, doing that optimization would be LLVM's job, but we'd probably have to expose some primitive". Anyway, I am currently in favor of likely/unlikely (in preference to the current text) as well, but @Aatch I think it would be great to see some discussion of the approaches taken by other compilers, or projects. We've seen already what picohttpparser uses, but I know that many codebases (the linux kernel, the firefox code base, etc) incorporate some sort of hints, and it'd be nice to know what they use.
|
This comment has been minimized.
This comment has been minimized.
|
Oh, the other question I was wondering: how fragile are LLVM's optimizations with regard to the expected value? (i.e., with regard to @nrc's point about us having to be careful when we reorder code etc). I would sort of expect that the expectation is associated with an SSA value produced by the |
nikomatsakis
self-assigned this
May 22, 2015
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis well C/C++ exposes As for how LLVM actually does it, it alters the weights of branches where the condition is the result of the intrinsic. It processes all the branches in the function first before replacing |
This comment has been minimized.
This comment has been minimized.
|
@Aatch I think you mean gcc exposes |
This comment has been minimized.
This comment has been minimized.
|
It seems to me that |
This comment has been minimized.
This comment has been minimized.
bluss
commented
May 27, 2015
|
|
This comment has been minimized.
This comment has been minimized.
|
Yeah, I understand the desugaring, I'm more interested in the semantics. (If you're talking about semantics, what's the difference between expectation on the conditional vs. expectation on the values?) |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
May 27, 2015
|
On the one hand, LLVM does have the i8 expect intrinsic. In that sense, @huonw may be correct. On the other hand, that will in many cases get expanded right back out again for the underlying machine, to some variety of jump-if-equal. (or a branch prediction hint of some sort taking similar arguments) |
This comment has been minimized.
This comment has been minimized.
bluss
commented
May 27, 2015
|
@huonw consider |
This comment has been minimized.
This comment has been minimized.
|
@bluss while true, I'm actually focusing on the I'm only second guessing myself because the C compilers expose it as |
This comment has been minimized.
This comment has been minimized.
|
@Aatch my bad, I assumed based on most of the initial comments and the title of the RFC that this was actually about expect, without realizing the contents of the RFC changed to be likely/unlikely. |
This comment has been minimized.
This comment has been minimized.
|
Actually, completely nevermind, that isn't the post I thought it was either. |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
Jun 4, 2015
|
Michael Kerrisk's post regarding the performance impact of He maintains the Linux manpages project, and one particularly useful point in his post is where the breakeven point is on the benchmark he provides: 1/10^5 (EDIT: typo, actually 1/10^4) incorrect predictions is about where |
This comment has been minimized.
This comment has been minimized.
|
@eternaleye that is interesting. The fact that 1/10^5 is the "break-even" point is surprising. At any rate, there's a reason my motivating example is a branch not taken in about 1/(2*10^19) cases. I'll keep stuff like this in mind when documenting the intrinsics though. |
This comment has been minimized.
This comment has been minimized.
|
Since the end of the final comment period is approaching and it's likely that this will be accepted when it does, I started on implementation. Turns out that the way we translated function calls meant that the intrinsics didn't actually work, but I improved that, so it all works now. The branch is here: https://github.com/Aatch/rust/tree/branch-hinting |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
I'm ok with the unstable intrinsics but still share @nrc's concern about how these are exposed. In Rust they will just look like functions, which I think is pretty damn misleading. At least in gcc they look like magic functions. |
This comment has been minimized.
This comment has been minimized.
|
@brson sure, the lower-level In gcc, nobody uses I only think them being functions is misleading if you don't actually know what they do. In which case I ask: why the hell are you using them then?! The actual use of them is pretty clear: |
This comment has been minimized.
This comment has been minimized.
Valloric
commented
Jun 9, 2015
|
Agreed with @Aatch. Let's not forget why gcc uses a Let's not try to infer some sort of grand design for the weird-looking names of intrinsic functions in C; there's no such thing, the names are weird because of technical restrictions that Rust thankfully doesn't have. |
This comment has been minimized.
This comment has been minimized.
|
It's official... the language subteam has decided to accept this RFC. Thanks @Aatch! |
nikomatsakis
referenced this pull request
Jun 10, 2015
Open
Implement likely/unlikely intrinsic (tracking issue for RFC 1131) #26179
This comment has been minimized.
This comment has been minimized.
|
Tracking issue: rust-lang/rust#26179 |
nikomatsakis
merged commit 31d230b
into
rust-lang:master
Jun 10, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
What is the state of this? |
This comment has been minimized.
This comment has been minimized.
|
@ticki, implementation turned out to be rather hard, if you actually wanted the intrinsics to do anything at least. It's turned out to simply be easier to wait for work on MIR to progress and build them on top of that. |
This comment has been minimized.
This comment has been minimized.
|
@Aatch, |
This comment has been minimized.
This comment has been minimized.
|
@ticki the macro you added? These intrinsics aren't implemented in the compiler at all yet, so I'm not sure what your macro is doing. The likely/unlikely intrinsics work differently to assume, and LLVM is very finicky about the relationship between the generated |
This comment has been minimized.
This comment has been minimized.
|
Oh! My bad. I was speaking about the assume intrinsics. I wonder why the intrinsics cannot just use LLVM's branch weight metadata? |
Stebalien
referenced this pull request
Aug 19, 2016
Closed
Implement branch prediction intrinsics #918
This comment has been minimized.
This comment has been minimized.
|
The feature name of the RFC still says |
chriskrycho
referenced this pull request
Feb 8, 2017
Closed
Document all features in the reference #38643
This comment has been minimized.
This comment has been minimized.
ofek
commented
May 5, 2017
@Aatch Does this do anything now that we have MIR? |
This comment has been minimized.
This comment has been minimized.
|
Are there thoughts on how to get this to work with |
This comment has been minimized.
This comment has been minimized.
|
that would probably fall under whatever mechanism ends up being used for
hinting which pattern matching clauses are more likely
…On Wed, Sep 6, 2017, at 16:05, Joshua Liebow-Feeser wrote:
Are there thoughts on how to get this to work with `if let`? I haven't
seen any mention of `if let` in the doc or this discussion.>
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#1131 (comment)
--
cmr
http://octayn.net/
+16038524272
|
Aatch commentedMay 20, 2015
Rendered View