Re: [PATCH 01/29] iov_iter: Switch to using a table of operations
From: Linus Torvalds
Date: Sun Nov 22 2020 - 14:22:53 EST
On Sun, Nov 22, 2020 at 5:33 AM David Howells <dhowells@xxxxxxxxxx> wrote:
>
> I don't know enough about how spectre v2 works to say if this would be a
> problem for the ops-table approach, but wouldn't it also affect the chain of
> conditional branches that we currently use, since it's branch-prediction
> based?
No, regular conditional branches aren't a problem. Yes, they may
mispredict, but outside of a few very rare cases that we handle
specially, that's not an issue.
Why? Because they always mispredict to one or the other side, so the
code flow may be mis-predicted, but it is fairly controlled.
In contrast, an indirect jump can mispredict the target, and branch
_anywhere_, and the attack vectors can poison the BTB (branch target
buffer), so our mitigation for that is that every single indirect
branch isn't predicted at all (using "retpoline").
So a conditional branch takes zero cycles when predicted (and most
will predict quite well). And as David Laight pointed out a compiler
can also turn a series of conditional branches into a tree, means that
N conditional branches basically only needs log2(N) conditionals
executed.
In contrast, with retpoline in place, an indirect branch will
basically always take something like 25-30 cycles, because it always
mispredicts.
End result:
- well-predicted conditional branches are basically free (apart from
code layout issues)
- even with average prediction, a series of conditional branches has
to be fairly long for it to be worse than an indirect branch
- only completely unpredictable conditional branches end up basically
losing, and even then you probably need more than one. And while
completely unpredictable conditional branches do exist, they are
pretty rare.
The other side of the coin, of course, is
- often this is not measurable anyway.
- code cleanliness is important
- not everything needs retpolines and the expensive indirect branches.
So this is not in any way "indirect branches are bad". It's more of a
"indirect branches really aren't necessarily better than a couple of
conditionals, and _may_ be much worse".
For example, look at this gcc bugzilla:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86952
which basically is about the compiler generating a jump table (is a
single indirect branch) vs a series of conditional branches. With
retpoline, the cross-over point is basically when you need to have
over 10 conditional branches - and because of the log2(N) behavior,
that's around a thousand cases!
(But this depends hugely on microarchitectural details).
Linus