6
$\begingroup$

It's common knowledge that branching in a GPU program is costly because it may have to run both the if and else logic for every pixel being evaluated in the same wave, but only applying each result to the appropriate pixels.

I was curious if branching was still a performance issue if there is only an if statement and no else statement?

In this case, it seems like it has the ability to be faster compared to branchless logic, for the case when no pixels need to do the work inside the if statement, and can instead skip past it as a group.

Is this true? Are there any other downsides? like perhaps older video cards still doing the if logic anyways, even though no pixels evaluate to true?

$\endgroup$
4
$\begingroup$

If there is no divergence (i.e. all threads in a wave take the same branch) newer GPU's can skip all the work within the if-branch. If there's divergence, then code in both branches is executed, but thread execution mask basically defines which threads execute code in which branch (code in non-executed branches for threads are effectively NOPed out). This is basically the same as predicated branching but happens dynamically based on divergence.

On GCN architecture at least the branching itself is basically free or at least very cheap (handled by a separate unit running parallel to ALU for example), but something to keep in mind is that branching also tends to increase GPR pressure, which in turn lowers the occupancy. Low occupancy means there can be less threads in flight at once which influences GPU's ability to hide memory latencies. This may or may not be an issue in your shaders depending on how they access memory, i.e. you should see performance increase along with increased occupancy in shaders with heavy memory access.

So it's still good to optimize out branching where reasonable, but I think it's one of the things good left to the optimization stage where you need to squeeze max performance out of your shaders.

$\endgroup$
5
$\begingroup$

Old Hardware

Some older cards didn't used to jump instructions in warps, so this was indeed an issue. If you have a conditional with these cards, the inside logic of the conditional would still be evaluated even if the block wasn't entered by any of the pixels, vertices, etc. There's little you can do in this case because every instruction will be executed. The worst case is also the best case here.

Modern Hardware

However, if you are working with relatively modern hardware though, this isn't an issue and "if/else" blocks will be skipped when necessary. There really shouldn't be a downside to using "if/else" blocks compared to not using them. You are still branching with an "else"-less statement. In fact, some post-processing effects/deferred rendering specifically benefit from this.

The worst case scenario is that some threads go through the "if" block and the rest go through the "else" block. The best case scenario is that all go through the "if" block or the "else" block. There isn't a downside to using "if/else" conditionals as they are needed (either on old hardware or newer hardware), but there's a possible upside with newer hardware.

$\endgroup$
  • $\begingroup$ Isn't there still a downside if not all the waves want to take the same path? Won't it do both paths for the wave? I was also wondering what you meant in the last paragraph about newer cards doing double the logic? Thanks for the answer and info (: $\endgroup$ – Alan Wolfe Oct 11 '16 at 14:34
  • $\begingroup$ Ignore the last paragraph, I'll edit my answer. I thought you were attempting to do something else and I made a bad assumption. If the whole warp doesn't go through the same path, then you're right, then you have to go through the "if" and the "else" block even for newer cards. $\endgroup$ – aces Oct 12 '16 at 4:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.