This is an archive of the discontinued LLVM Phabricator instance.

[LoopUnswitch] Add block frequency analysis to recognize hot/cold regions
ClosedPublic

Authored by chenli on Jul 29 2015, 12:02 PM.

Details

Summary

This patch adds block frequency analysis to LoopUnswitch pass to recognize hot/cold regions. For cold regions the pass only performs trivial unswitches since they do not increase code size, and for hot regions everything works as before. This helps to minimize code growth in cold regions and be more aggressive in hot regions. Currently the default cold regions are blocks with frequencies below 20% of function entry frequency, and it can be adjusted via -loop-unswitch-cold-block-frequency flag. The entire feature is controlled via -loop-unswitch-with-block-frequency flag and it is off by default.

Diff Detail

Event Timeline

chenli retitled this revision from to [LoopUnswitch] Add block frequency analysis to recognize hot/cold regions.
chenli updated this object.
chenli added reviewers: reames, broune.
chenli added a subscriber: llvm-commits.
chenli added inline comments.Jul 29 2015, 12:20 PM
lib/Transforms/Scalar/LoopUnswitch.cpp
502

I chose to use loop preheader's frequency for coldness comparison. This will ignore the size of the loop because it does not count backedges or iteration numbers. My reasoning is that if the loop was only entered once in the pass 1000 executions, we should be confident that it will never be entered again. Therefore, no matter how many times the loop iterates, it shouldn't affect our decision. But I could see the other way around. I am open to change it if anyone prefers the other way.

reames requested changes to this revision.Jul 31 2015, 4:25 PM
reames edited edge metadata.
reames added inline comments.
lib/Transforms/Scalar/LoopUnswitch.cpp
78

What are your plans for testing this and getting it enabled by default?

84

Have you explored this parameter at all?

My guess would be that disabling loop unswitching should only be done for *really* cold loops. I have no evidence, but a cool loop in a really hot function seems like something we should unswitch.

436

Minor comment clarification: "function entry baseline frequency". "Loops with headers below this frequency"

502

I feel pretty strongly that making decisions based on the number of times the loop executes rather than the number of times the header executes is likely to produce negative results.

Consider:
while(true) {

if (loop invariant) {
}
if (loop invariant2) {
}
if (loop invariant3) {
}
do work();

}

Your change would completely disable unswitching in this loop which seems non-ideal.

504

Given there's already handling for OptForSize within UnswitchIfProfitable, I'd like to see the handling combined. A cleanup change to move the OptForSize check here - I think that's NFC right? - and then using that in this patch would help.

test/Transforms/LoopUnswitch/cold-loop.ll
22

This is perhaps a bad example. In this particular case, we could split the loop into two subloops without code growth. Maybe tweak your example so it's more obvious why we want to avoid unswitching this?

This revision now requires changes to proceed.Jul 31 2015, 4:25 PM

The main problem with the patch is that the cold loop detection can have many false positives. With profile feedback, cold loops can be reliably detected but not with the method described in this patch. Without profile feedback, the cold loop filtering should probably not be turned on by default unless it is optimized for size. When the filtering is not on, we should not pay the compile time penalty of computing BFI unconditionally either. Cong has recently made it possible to compute BFI without relying on running the wrapper pass.

lib/Transforms/Scalar/LoopUnswitch.cpp
502

The hotness of the loop should be measured by the frequency of the hottest BB in the loop relative to the function entry.

With PGO, you will need to check the execution count of the hottest BB in the loop (relative to some threshold set by the program summary).

test/Transforms/LoopUnswitch/cold-loop.ll
22

Unswitching duplicates the loop, so size overhead is the loop setup code (in this case probably just a branch associated with backedge).

The main problem with the patch is that the cold loop detection can have many false positives. With profile feedback, cold loops can be reliably detected but not with the method described in this patch.

Do you mean by using other profiles together with BFI or using BFI differently?

Without profile feedback, the cold loop filtering should probably not be turned on by default unless it is optimized for size.

Yes, you are correct. Initially I was thinking this could take cold loop's unswitch budget to hot loop and thus make hot loop unswitch more aggressively. But it turned out separate loops will have the same initial unswitch budget and not effect each other. So it will only optimize code size.

When the filtering is not on, we should not pay the compile time penalty of computing BFI unconditionally either. Cong has recently made it possible to compute BFI without relying on running the wrapper pass.

Do you mean this patch http://reviews.llvm.org/D11196 ?

lib/Transforms/Scalar/LoopUnswitch.cpp
84

I was thinking about that too. Maybe adding function hotness to its loops is a good idea, ie. lower this threshold for hot functions and increase it for cold functions.

502

I think the hottest BB should be the header, assuming its inner loops will be processed by their own unswitch passes.

504

I will have a look at this.

test/Transforms/LoopUnswitch/cold-loop.ll
22

Yes, this is not a good case. I will add some side-effect code after the first condition (so the first one is still trivial and not affected by coldness check, but unswitching the second one will grow code size).

The main problem with the patch is that the cold loop detection can have many false positives. With profile feedback, cold loops can be reliably detected but not with the method described in this patch.

By the correct cold loop detection, do you specifically mean to check the execution count of the hottest BB in the loop?

chenli updated this revision to Diff 32087.Aug 13 2015, 1:08 PM
chenli edited edge metadata.

Update patch to fix the following issues:

  1. Use standalone BFI without relying on the wrapper pass.
  2. Use the hottest block (loop header in this case) to determine the loop's hotness.
  3. Update the non-trivial condition test case to have effect of code growth.

I also plan to have a follow-up patch to introduce function_entry_count to hot/cold region detection.

Minor comments below. Once addressed, I plan to give a LGTM unless David has further comments in the meantime.

lib/Transforms/Scalar/LoopUnswitch.cpp
77

This comment is a bit deceptive. I'd just drop it.

84

Right now, we're only limiting code size increase. Please adjust the string.

88

I think the default here should be much lower, but we can tune this in separate changes. My guess here would be something like 1/100 rather than 20/100. I also think we should have an absolute cutoff, but again, we can tune separately.

176

Add a comment which says what these are used for and that they're only used with the PGO option enabled.

test/Transforms/LoopUnswitch/cold-loop.ll
39

Please add a couple of instructions here per previous comment on test case.

davidxl added inline comments.Sep 10 2015, 11:32 AM
lib/Transforms/Scalar/LoopUnswitch.cpp
88

This is not frequency. Maybe call it 'ColdnessThreshold' or something.

89

It is the 'Coldness threshold in percent. The loop header frequency (relative to the entry frequency) is compared with the threshold to determine if non-trivial unswitching should be enabled.'

441

Note that this also triggers the check when PGO is not enabled (e.g, with static prediction).

To check if PGO is on, do:

HasProfileData = F.getEntryCount().hasValue();
if (HasProfileData) {

..

chenli added inline comments.Sep 10 2015, 11:48 AM
lib/Transforms/Scalar/LoopUnswitch.cpp
441

Do you mean that without PGO enabled, this should never be triggered?

Right. I won't trust static profile data to tell you what is cold or hot.

In fact I think the right way to determine coldness is to use the
actual profile count of the loop header to determine loop is cold or
not -- the actual exec count of a loop header can be computed by
multiplying the relative frequency with the the F.getEntryCount(). A
common threshold can be 0 or 1, which means the loop rarely executes.

David

chenli updated this revision to Diff 35060.Sep 17 2015, 9:27 PM
chenli edited edge metadata.

Update patch w.r.t Philip's and David's comments.

Looks fine, but please wait for Phillip or another review to give you LGTM.

reames accepted this revision.Sep 28 2015, 5:41 PM
reames edited edge metadata.
This revision is now accepted and ready to land.Sep 28 2015, 5:41 PM
chenli closed this revision.Sep 28 2015, 10:05 PM