This is an archive of the discontinued LLVM Phabricator instance.

[Pseudo Probe] Do not instrument EH blocks.
ClosedPublic

Authored by hoy on Jan 27 2023, 9:25 AM.

Details

Summary

This change avoids inserting probes to EH blocks. Pseudo probe can prevent block merging when probes in the blocks look different. This has a chained effect to passes incurring exponential IR growth (such as jump threading) and as a consequence the compilation may time out. Not inserting probes to EH blocks could mitigate the issue. Another benefit is that both IR size and binary size are smaller. Since EH blocks are usually cold, the change should have minimal impact to profile quality.

Testing:

Out of two internal large benchmarks, no perf impact seen. 1% size savings to both the text and the pseudo_probe section.

Diff Detail

Event Timeline

hoy created this revision.Jan 27 2023, 9:25 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 27 2023, 9:25 AM
hoy requested review of this revision.Jan 27 2023, 9:25 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 27 2023, 9:25 AM
hoy edited the summary of this revision. (Show Details)Jan 27 2023, 9:38 AM
hoy added reviewers: wenlei, wlei.
wenlei added inline comments.Jan 27 2023, 10:10 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
257

nit: inclined to say something like KnownColdBlocks, and treating EH as one kind of code blocks.

262

For this BFS to work, you want to start only from EH region entries. I think isLandingPad marks entries, but isEHPad could be in the middle of EH regions? IIUC, isEHPad is a superset of isLandingPad.

Starting from middle will make it look like having non-EH predecessor, which is not true. It probably doesn't lead to wrong result in current implementation for two reasons: 1) most likely lexical order guarantee EH entry is visited first, 2) if middle blocks are visited first and determined having non-EH predecessor, later visit from EH entry will still cover these blocks and mark them EH. But it feel unnecessary to start from the middle.

277–278

Is this necessary? If Predecessor is non-EH, we will break out the loop later; if it's EH, line 274 should have skipped this Predecessor/Successor already.

hoy added inline comments.Jan 27 2023, 10:33 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
257

Sounds good.

262

Yeah, EHPad is a superset of LandingPad, just checking against EHPad should be enough.

Starting from middle will make it look like having non-EH predecessor, which is not true.

Can a middle block of an EH region be reachable from non-EH path? I'm using it as seeds here. isEHPad is define below. I'm not sure how CatchSwitch is but all other types seem can be only run on EH paths?

/// Return true if the instruction is a variety of EH-block.
bool isEHPad() const {
  switch (getOpcode()) {
  case Instruction::CatchSwitch:
  case Instruction::CatchPad:
  case Instruction::CleanupPad:
  case Instruction::LandingPad:
    return true;
  default:
    return false;
  }
}
277–278

It's necessary if the successor forms a self-loop. In such case, the self back edge should be ignored.

hoy added inline comments.Jan 27 2023, 10:35 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262

OK, by definition, CatchSwitch should refer to EH blocks only: https://llvm.org/docs/LangRef.html#catchswitch-instruction

hoy updated this revision to Diff 492845.Jan 27 2023, 10:42 AM

Updating D142747: [Pseudo Probe] Do not instrument EH blocks.

wlei added a comment.Jan 27 2023, 10:49 AM

Will this affect PROFI? if we don't insert probe for EH block, does PROFI assign a cold(0) value to the BB or leave it with an unknown value like the dangling probe?

hoy added a comment.Jan 27 2023, 10:56 AM

Will this affect PROFI? if we don't insert probe for EH block, does PROFI assign a cold(0) value to the BB or leave it with an unknown value like the dangling probe?

Yes, it will affect Profi. The effect is just like removing those EH blocks from the IR. No corresponding counters (even 0) will show up in the profile. Profi can somehow deal with it smartly: https://github.com/llvm/llvm-project/blob/61eb12e1f423063b0ead944827dc53b02baed0d4/llvm/include/llvm/Transforms/Utils/SampleProfileInference.h#L294.

wlei added inline comments.Jan 27 2023, 10:57 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

Since this skipped some BBs and might assign different id to the same BB, it seems to me this will cause some profile matching issue? say, it's good for on-demand profiling, but for the profile in the production, it still used the old number of BB.

hoy added inline comments.Jan 27 2023, 11:04 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

This is very good point! Yeah, the downwards compatibility is being screwed up there. I guess we can give blocks the same original id, but then it's always going to be like that. Fortunately this change is so far only needed for llvm-15 and there should be no legacy profiles.

wlei added inline comments.Jan 27 2023, 11:30 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

Good to know it's only needed for llvm-15, just I think in this case people need to remind that when upgrading to llvm-15 it should use a new fresh profile, using the profile collected from the old version could cause some regression due to this. Incremental PGO might detect/mitigate this issue if happens :)

hoy added inline comments.Jan 27 2023, 11:34 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

Yeah, platform upgrade should always come with a new round of profile refresh.

modimo added inline comments.Jan 27 2023, 11:45 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262

Can a middle block of an EH region be reachable from non-EH path?

No, https://eel.is/c++draft/except.pre:

A handler will be invoked only by throwing an exception in code executed in the handler's try block or in functions called from the handler's try block.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

wenlei added inline comments.Jan 27 2023, 11:55 AM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
277–278

What I'm saying is the self back edge will be ignored without this check (see reasoning above), or am I wrong?

wenlei added inline comments.Jan 27 2023, 12:00 PM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

Do we require probe Id to be consecutive? If not, skipping blocks we exclude actually isn't a bad idea? It makes probe Id more stable and it gives us flexibility to make changes in this area without breaking compatibility (i.e. we could revert this change in llvm-15, or even exclude other cold blocks later if needed with minimum impact).

hoy added a comment.Jan 27 2023, 12:08 PM

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

Oh I just remembered that code. They're basically the same algorithm. But given that IR and MIR routines are usually implemented separately otherwise templated code would be needed, I'd like to keep as is. WDYT?

llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
262–264

(i.e. we could revert this change in llvm-15, or even exclude other cold blocks later if needed with minimum impact).

The concern is valid. Probe ids do not need to be consecutive. I'll make it downwards compatible.

277–278

Without this check the self back edge is going to be ignored in a different way such that the block will never be considered EH-only.

hoy updated this revision to Diff 492879.Jan 27 2023, 12:13 PM

Updating D142747: [Pseudo Probe] Do not instrument EH blocks.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

Oh I just remembered that code. They're basically the same algorithm. But given that IR and MIR routines are usually implemented separately otherwise templated code would be needed, I'd like to keep as is. WDYT?

I'm okay either way. That being said, all of BFI is templated on BB and MBB:

template <class BT> class BlockFrequencyInfoImpl : BlockFrequencyInfoImplBase {

Given there's precedence and how identical the code I think it makes sense to combine them so they can't get out of sync.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
277–278

Ok, but if the purpose is to prevent predecessor from cycle to be considered non-EH. How about landingpad->A->B->A, where there's no self edge to A, but B would prevent A from being marked EH? The need for self cycle special handling looks fishy.. We either handle all cycles, or don't..

modimo added inline comments.Jan 27 2023, 12:24 PM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
277–278

https://reviews.llvm.org/D131824 handles landingpad->A->B->A by using a lattice and iterating until no change occurs which handles cycles. Even has a test case to make sure it's done right :)

hoy added inline comments.Jan 27 2023, 12:24 PM
llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
277–278

Yeah, I just remembered the issue was also raised up in https://reviews.llvm.org/D131824 so we ended up with a more complicated implementation. Sounds like I should reuse that code here. Then making a shared version makes sense.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

hoy added a comment.Jan 27 2023, 12:38 PM

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

MIR only has landing pads right? The windows EH instructions seems on IR only.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

For where to put it, right now I'd say there's not a good place for it and we may want to create a new file. Clang has llvm-project/clang/lib/CodeGen/CGException.cpp for all of it's EH support structure but EH on LLVM is very haphazard (I suspect because outside of correctness there was not much optimization thought put into it).

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

hoy added a comment.Jan 27 2023, 12:43 PM

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

For where to put it, right now I'd say there's not a good place for it and we may want to create a new file. Clang has llvm-project/clang/lib/CodeGen/CGException.cpp for all of it's EH support structure but EH on LLVM is very haphazard (I suspect because outside of correctness there was not much optimization thought put into it).

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

I'm thinking about llvm/include/llvm/Analysis/CFG.h as a place to put the templated code. WDTY?

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

For where to put it, right now I'd say there's not a good place for it and we may want to create a new file. Clang has llvm-project/clang/lib/CodeGen/CGException.cpp for all of it's EH support structure but EH on LLVM is very haphazard (I suspect because outside of correctness there was not much optimization thought put into it).

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

I'm thinking about llvm/include/llvm/Analysis/CFG.h as a place to put the templated code. WDTY?

No, clearly CFG.h operates on a different abstraction level that is unaware of high level concepts like EH. I think we should keep it that way..

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

I'm not sure this is useful enough to be part of core IR constructs like function/basicblock. Adding its own file seems like a better place than any of the existing ones, though just for one not commonly used function.. That's why I say I don't know :)

I'm thinking about llvm/include/llvm/Analysis/CFG.h as a place to put the templated code. WDTY?

Unfortunately (or really fortunately cause it's doing the right thing) llvm/include/llvm/Analysis/CFG.h is a very clean file and I think this code would look a bit out of place. I would fully support a new file being created since it's really not a big deal (check out how small llvm/lib/Analysis/EHPersonalities.cpp is) and it'll likely be useful to have in the future as well.

We've got the same EH-ness propagation code in MFS already: https://reviews.llvm.org/D131824. Consider merging the code?

That diff also used EHPad as seeds for BFS, I thought we only need LandingPads as seeds? Though I think for simple algorithm, having MIR and IR implementation separated is probably fine. I also don't know where to put a merged version..

if (MBB.isEHPad())
  LandingPads.push_back(&MBB);

LandingPads are the only thing that exists for x86_64 Linux while catchswitch, catchpad, and cleanuppad are all for Windows EH (https://llvm.org/docs/ExceptionHandling.html#new-exception-handling-instructions). Without proper testing on Windows I'd advocate for keeping it to LandingPads only.

For where to put it, right now I'd say there's not a good place for it and we may want to create a new file. Clang has llvm-project/clang/lib/CodeGen/CGException.cpp for all of it's EH support structure but EH on LLVM is very haphazard (I suspect because outside of correctness there was not much optimization thought put into it).

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

I'm thinking about llvm/include/llvm/Analysis/CFG.h as a place to put the templated code. WDTY?

No, clearly CFG.h operates on a different abstraction level that is unaware of high level concepts like EH. I think we should keep it that way..

I would support adding a llvm/lib/Analysis/Exceptions.cpp (or whatever name makes sense) like llvm/lib/Analysis/EHPersonalities.cpp exists. Otherwise, if we don't want to add another file I would place it in Function.h/cpp since technically we can consider this calculating a property of the function.

I'm not sure this is useful enough to be part of core IR constructs like function/basicblock. Adding its own file seems like a better place than any of the existing ones, though just for one not commonly used function.. That's why I say I don't know :)

I'm not confident on what exactly is the right thing to do here either. Looking through the code base we've got other code that could fit better in a llvm/lib/Analysis/Exceptions.cpp like https://github.com/llvm/llvm-project/blame/main/llvm/lib/CodeGen/Analysis.cpp#L729. Looks like Analysis.cpp is a dumping ground for functions that don't fit elsewhere which is another ref-count to me that a dedicated file for EH makes sense.

hoy updated this revision to Diff 492913.Jan 27 2023, 3:03 PM

Addressing feedbacks.

hoy updated this revision to Diff 492917.Jan 27 2023, 3:09 PM

Updating D142747: [Pseudo Probe] Do not instrument EH blocks.

wenlei added inline comments.Jan 27 2023, 6:27 PM
llvm/include/llvm/Analysis/EHUtils.h
18
  1. Is the need for AccessorTraits because of the different API between MBB (member predecessors()) vs BB (standalone predecessors())?
  1. If we have to use AccessorTraits, can we avoid exposing it as template type at the top level API (computeEHOnlyBlocks)? I think we should be able to select the right traits based on BlockT.
  1. Since we only need successor/predecessor, I'd suggest we decouple this from afdo_detail::IRTraits. That is, we define two small traits here for both MBB and BB.
llvm/lib/CodeGen/MachineFunctionSplitter.cpp
89

As mentioned above, this better be moved into EHUtils.h.

hoy added inline comments.Jan 27 2023, 6:37 PM
llvm/include/llvm/Analysis/EHUtils.h
18

Is the need for AccessorTraits because of the different API between MBB (member predecessors()) vs BB (standalone predecessors())?

Yes. I don't see code shared between BB and MBB often. I guess that's one reason preventing it from being shared easily.

If we have to use AccessorTraits, can we avoid exposing it as template type at the top level API (computeEHOnlyBlocks)? I think we should be able to select the right traits based on BlockT

Can you elaborate a little more? Iike based on typeid check?

Since we only need successor/predecessor, I'd suggest we decouple this from afdo_detail::IRTraits. That is, we define two small traits here for both MBB and BB.

Makes sense.

llvm/lib/CodeGen/MachineFunctionSplitter.cpp
89

I thought about that, but I ended up defining them here because otherwise it'll introduce a cyclic dependency between Analysis and Codegen.

wenlei added inline comments.Jan 30 2023, 10:35 AM
llvm/include/llvm/Analysis/EHUtils.h
18

Can you elaborate a little more? Iike based on typeid check?

I haven't looked at how. But I suppose with some investigation we should be able to find a way to hide the traits from API. We have precedence - there's not any need for specifying the traits when instantiating a sample loader.

llvm/lib/CodeGen/MachineFunctionSplitter.cpp
89

Ok, I see. I guess that's why IRTraits<MachineBasicBlock> for sample loader is also in codegen.

This is not ideal - the traits is supposed to be part of the infra/framework, but now you're defining it at the client side. This is also worse than the MIRSampleProfile case because one can argue it's still part of framework there.

hoy added inline comments.Jan 30 2023, 11:03 AM
llvm/include/llvm/Analysis/EHUtils.h
18

Actually just figured out that there are predecessors/successors API defined for MBB in MachineSSAContext.h. We can use that and AccessorTraits will not be needed at all.

hoy updated this revision to Diff 493359.Jan 30 2023, 11:04 AM

Updating D142747: [Pseudo Probe] Do not instrument EH blocks.

wenlei accepted this revision.Jan 30 2023, 11:12 AM

lgtm, thanks.

llvm/include/llvm/Analysis/EHUtils.h
18

Great - that's why I asked the first question. :)

This revision is now accepted and ready to land.Jan 30 2023, 11:12 AM
hoy added inline comments.Jan 30 2023, 11:14 AM
llvm/include/llvm/Analysis/EHUtils.h
18

BTW, I'm thinking about moving the predecessors/successors definition from MachineSSAContext.h to MachineBasicBlocks.h since they could be useful in general for code sharing between IR and MIR. WDYT?

wenlei added inline comments.Jan 30 2023, 11:18 AM
llvm/include/llvm/Analysis/EHUtils.h
18

That makes sense. (though I just realized the counterpart for IR is in CFG.h, instead of BasicBlock.h)

hoy updated this revision to Diff 493365.Jan 30 2023, 11:21 AM

moving the predecessors/successors definition from MachineSSAContext.h to MachineBasicBlocks.h

llvm/include/llvm/Analysis/EHUtils.h
18

Yeah, I didn't find the counterpart of CFG.h in Codegen.

hoy updated this revision to Diff 493366.Jan 30 2023, 11:23 AM

Removing unnecessary header inclusions.

This revision was landed with ongoing or failed builds.Jan 30 2023, 1:27 PM
This revision was automatically updated to reflect the committed changes.