This is an archive of the discontinued LLVM Phabricator instance.

[OpenMPOpt] ICV macro definitions
ClosedPublic

Authored by sstefan1 on Jun 19 2020, 7:55 AM.

Details

Summary

This defines some basic information about ICVs in OMPKinds.def.
We also emit remarks with initial values for each function (which are default for now)
as a way to test this.

Diff Detail

Event Timeline

sstefan1 created this revision.Jun 19 2020, 7:55 AM
sstefan1 marked an inline comment as done.Jun 19 2020, 7:57 AM
sstefan1 added inline comments.
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

I wasn't sure how to add filenames here like in other remarks tests. Not sure we need them, but if someone knows how, please let me know.

jhuber6 added inline comments.Jun 19 2020, 8:17 AM
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

It reads the debug information for the filename and line numbers. Something like this should let you set the filename.

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 ")
!1 = !DIFile(filename: "filename.c", directory: "/tmp")

Adding line numbers manually is a bit more complicated since it requires scoping information. There's usually a line like this

!21 = !DILocation(line: 5, column: 10, scope: !14)

And a corresponding usage assigning it to one of the instructions

%1 = tail call i32 @__kmpc_global_thread_num(%struct.ident_t* nonnull @0), !dbg !21
sstefan1 marked an inline comment as done.Jun 19 2020, 8:33 AM
sstefan1 added inline comments.
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

Thanks for answering. I guess I'm on my own if this is not completely generated by clang?

jdoerfert added inline comments.Jun 19 2020, 9:11 AM
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

run clang with -g. Don't generate these on your own.

sstefan1 marked an inline comment as done.Jun 21 2020, 4:01 AM
sstefan1 added inline comments.
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

One more question. Does it make sense to have a separate file, eg. icv_remarks.ll (or use one of existing remarks tests) with only one simple function to test this? Debug info adds a lot of noise here. For exampe, for these limited number of tests we get 450+ additional lines. Furthermore, this test file will only grow in the future with the addition of other ICVs. This will probably also affect reviewing test changes. WDYT?

jdoerfert added inline comments.Jun 21 2020, 9:32 AM
llvm/test/Transforms/OpenMP/icv_tracking.ll
13 ↗(On Diff #272076)

New file(s) is fine.

sstefan1 updated this revision to Diff 272321.Jun 21 2020, 2:43 PM

new test file for icv remarks

sstefan1 updated this revision to Diff 272322.Jun 21 2020, 2:46 PM

leftover check lines

sstefan1 marked an inline comment as done.Jun 21 2020, 2:48 PM
sstefan1 added inline comments.
llvm/test/Transforms/OpenMP/icv_remarks.ll
1

In the new PM remarks are emitted in reverse order. I wasn't sure how to handle this nicely.

jdoerfert accepted this revision.Jun 22 2020, 6:40 PM

Once the test is adjusted for both PMs, LGTM.

llvm/test/Transforms/OpenMP/icv_remarks.ll
1

Either:

  1. Make all check lines CHECK-DAG:, or
  2. Use two different prefixes.
This revision is now accepted and ready to land.Jun 22 2020, 6:40 PM
This revision was automatically updated to reflect the committed changes.
fhahn added a subscriber: fhahn.Jun 26 2020, 1:37 AM
fhahn added inline comments.
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

Is it possible to use a different name than FALSE here, because it will fail to compile if the system headers contain a FALSE define? Maybe something like ICV_FALSE to avoid conflicts.

sstefan1 marked an inline comment as done.Jun 26 2020, 4:18 AM
sstefan1 added inline comments.
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

Sure! I hope we will move away from macro magic soon anyway.

@jdoerfert sounds good?

daltenty added inline comments.
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

We currently have exactly such a build break from this change on AIX due to the system headers defining FALSE

jdoerfert added inline comments.Jun 26 2020, 7:41 AM
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

ICV_.. for all of them seems sensible. Thanks for catching this!

sstefan1 marked an inline comment as done.Jun 26 2020, 8:47 AM
sstefan1 added inline comments.
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

Sorry about that. Should be fixed with rG951e43f357ec3ee0ffc570aea9cbf19871696c42

fhahn added inline comments.Jun 26 2020, 9:18 AM
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

great thanks!

daltenty added inline comments.Jun 26 2020, 10:59 AM
llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
327

Thanks, this seems to have resolved our build issue.

wenlei added a subscriber: wenlei.Jul 1 2020, 3:05 PM
hoyFB added a subscriber: hoyFB.Jul 1 2020, 4:21 PM
hoyFB added inline comments.
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Hello,

Looks like the Int32 type with the full name llvm::omp::types::Int32 is a global variable. Creating a value using it may cause a race condition in thinLTO mode. Although Int32 is initialized with a module specific context, but it may or never get re-created per module. Please correct me if I misunderstand anything. Thanks.

Below is the my failing call stack in thinLTO mode:

PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0. Running pass 'CallGraph Pass Manager' on module ...'.
#0 0x00000000014a3a8f llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:564:13
#1 0x00000000014a1c30 llvm::sys::RunSignalHandlers() /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Signals.cpp:69:18
#2 0x00000000014a402c SignalHandler(int) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:396:3
#3 0x00007f00baf0b630 __restore_rt (/lib64/libpthread.so.0+0xf630)
#4 0x00000000030afd08 llvm::ConstantInt::get(llvm::LLVMContext&, llvm::APInt const&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/IR/Constants.cpp:776:40
#5 0x00000000030b2a9b llvm::ConstantInt::get(llvm::IntegerType*, unsigned long, bool) /home/hoy/local/server-llvm/llvm-project/llvm/lib/IR/Constants.cpp:797:10
#6 0x00000000024ccc56 (anonymous namespace)::OMPInformationCache::initializeInternalControlVars() /home/hoy/local/server-llvm/llvm-project/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def:326:1
#7 0x00000000024ccc56 (anonymous namespace)::OMPInformationCache::OMPInformationCache(llvm::Module&, llvm::AnalysisGetter&, llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, llvm::SetVector<llvm::Function*, std::vector<llvm::Function*, std::allocator<llvm::Function*> >, llvm::DenseSet<llvm::Function*, llvm::DenseMapInfo<llvm::Function*> > >*, llvm::SmallPtrSetImpl<llvm::Function*>&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:69:0
#8 0x00000000024f10ff llvm::SmallVectorTemplateCommon<llvm::Function*, void>::begin() /home/hoy/local/server-llvm/llvm-project/llvm/include/llvm/ADT/SmallVector.h:152:45
#9 0x00000000024f10ff (anonymous namespace)::OpenMPOpt::OpenMPOpt(llvm::SmallVectorImpl<llvm::Function*>&, llvm::CallGraphUpdater&, llvm::function_ref<llvm::OptimizationRemarkEmitter& (llvm::Function*)>, (anonymous namespace)::OMPInformationCache&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:336:0
#10 0x00000000024f10ff (anonymous namespace)::OpenMPOptLegacyPass::runOnSCC(llvm::CallGraphSCC&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:834:0

sstefan1 marked an inline comment as done.Jul 2 2020, 12:27 AM
sstefan1 added inline comments.
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Not really sure, but turns out types were initialized twice, maybe that was the problem. I guess I could also get module context explicitly , instead of using Int32->getContext().

Anyway, I'll try to build with thinLTO and report back.

jdoerfert added inline comments.Jul 2 2020, 8:31 AM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Not really sure, but turns out types were initialized twice

That is a problem. Can you fix that first. I would not be surprised if the LTO error goes away.

sstefan1 marked an inline comment as done.Jul 2 2020, 11:29 AM
sstefan1 added inline comments.
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

@hoyFB I wasn't able to reproduce this locally, but I committed a potential fix: rG61238d2690a6ebdf3c4f3f68f39101fac30263a7

Can you check again if the problem is still there?

christylee added inline comments.Jul 2 2020, 12:04 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

@sstefan1 Thanks! I'll check and report back.

hoyFB added inline comments.Jul 2 2020, 1:37 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

@sstefan1 Thanks for the quick response. I applied the fix and the problem is still there:

#0 0x0000000001474c2f llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:564:13
 #1 0x0000000001472dd0 llvm::sys::RunSignalHandlers() /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Signals.cpp:69:18
 #2 0x00000000014751cc SignalHandler(int) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:396:3
 #3 0x00007fb6ac7cc630 __restore_rt (/lib64/libpthread.so.0+0xf630)
 #4 0x0000000003107065 llvm::Type::getInt32Ty(llvm::LLVMContext&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/IR/Type.cpp:186:66
 #5 0x0000000002462754 (anonymous namespace)::OMPInformationCache::initializeInternalControlVars() /home/hoy/local/server-llvm/llvm-project/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def:326:1
 #6 0x0000000002462754 (anonymous namespace)::OMPInformationCache::OMPInformationCache(llvm::Module&, llvm::AnalysisGetter&, llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>&, llvm::SetVector<llvm::Function*, std::vector<llvm::Function*, std::allocator<llvm::Function*> >, llvm::DenseSet<llvm::Function*, llvm::DenseMapInfo<llvm::Function*> > >*, llvm::SmallPtrSetImpl<llvm::Function*>&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:69:5
 #7 0x0000000002484e0f llvm::SmallVectorTemplateCommon<llvm::Function*, void>::begin() /home/hoy/local/server-llvm/llvm-project/llvm/include/llvm/ADT/SmallVector.h:152:45
 #8 0x0000000002484e0f (anonymous namespace)::OpenMPOpt::OpenMPOpt(llvm::SmallVectorImpl<llvm::Function*>&, llvm::CallGraphUpdater&, llvm::function_ref<llvm::OptimizationRemarkEmitter& (llvm::Function*)>, (anonymous namespace)::OMPInformationCache&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:334:18
 #9 0x0000000002484e0f (anonymous namespace)::OpenMPOptLegacyPass::runOnSCC(llvm::CallGraphSCC&) /home/hoy/local/server-llvm/llvm-project/llvm/lib/Transforms/IPO/OpenMPOpt.cpp:832:15

It seems we still have a race condition. The Int32 type can be initialized by a module and then consumed by another module simultaneously. Your early proposal to use the explicit module context to create a constant value instead of using Int32.getContext() which can be from whatever module that first initializes the type sounds good to me. Thanks.

sstefan1 marked an inline comment as done.Jul 2 2020, 1:44 PM
sstefan1 added inline comments.
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Can you provide some details on how to reproduce this? I wasn't able to. I would like to be able to test this locally.

jdoerfert added inline comments.Jul 2 2020, 2:39 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

I think I understand now. Two processes spin up OMPIRBuilder or OpenMPOpt passes at the same time, both of those initialize global types, we created a race on these globals and all bets are off. I assume (thin)LTO has a single llvm::Context so we "just" need to prevent two threads from initializing at the same time. LLVM has a RAII mutex in llvm/include/llvm/Support/Mutex.h (SmartScopedLock) that we should place in a (new) initializer function (which calls the initializer functions we call now in the constructor) to prevent the race.

hoyFB added inline comments.Jul 2 2020, 2:44 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

The issue happened to one of our internal large projects with many files having OpenMP usage. The project is built with 40 threads in thinLTO mode. I guess it doesn't reproduce with smaller projects.

You may want to print out the Int32.getContext() object as well as the Module object for each ConstantInt::get(Type::getInt32Ty(Int32->getContext()), 0); call and see if they match. Two modules creating constants in the same context may cause a problem.

hoyFB added inline comments.Jul 2 2020, 2:51 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Yeah, that's the problem.

The global OMP types are initialized without lock protection with a module local context:

https://github.com/llvm/llvm-project/blob/1a70077b5a64189d9c04d1a2d7ea6ff0e49744d6/llvm/lib/Frontend/OpenMP/OMPConstants.cpp#L73

Even if they are lock protected, the module local context passed to them can still be used to create a constant by another module in parallel. Module constants should be created in sequence.

jdoerfert added inline comments.Jul 2 2020, 4:56 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

Even if they are lock protected, the module local context passed to them can still be used to create a constant by another module in parallel. Module constants should be created in sequence.

This is not up to the pass. The race in question here is home made but llvm::Context has to be thread safe itself if you use it in parallel, right? This is not the only pass creating constants and types. If, however, thinLTO uses different contexts per module, we have a different problem here. If the latter is the case we need to keep the Types as part of the OpenMPIRBuilder object which is "local" to one lvm::Context. @sstefan1 is going to look into the race tomorrow. I think it might be the best thing to move the types into the OpenMPIRBuilder. That will require some rewrite but make it race free and working with multiple contexts in parallel.

hoyFB added inline comments.Jul 2 2020, 5:48 PM
llvm/lib/Transforms/IPO/OpenMPOpt.cpp
230

If I understand correctly, functions of one module are always compiled sequentially, even in thinLTO mode. Different modules can be compiled in parallel. A module should have a unique context. Constants and types created during the compilation of one module are appended to the module's context in sequence. With the global Int32 type owning a context of an arbitrary module, creating multiple constants in that context from different threads concurrently result in a race.

I think moving the types into OpenMPIRBuilder objects should fix the issue. If you look at this code: https://github.com/llvm/llvm-project/blob/15440191b57237eafb18600ac653b9a0023db391/llvm/lib/IR/Constants.cpp#L776 , the constants are added to a DenseMap object with no lock protection. As long as they are added sequentially, it should be fine.

The problem should be thinLTO-specific. In full LTO mode, a dummy module is created to cover all functions which are then compiled sequentially. In thinLTO mode, an input file is one module owning its own context, and they are compiled in parallel.