[Openmp-commits] [PATCH] D81054: [OpenMP] Introduce target memory manager
Shilei Tian via Phabricator via Openmp-commits
openmp-commits at lists.llvm.org
Thu Aug 13 13:32:12 PDT 2020
tianshilei1992 marked 4 inline comments as done.
tianshilei1992 added inline comments.
================
Comment at: openmp/libomptarget/src/MemoryManager.cpp:149
+ FreeListTy &List = FreeLists[I];
+ if (List.empty())
+ continue;
----------------
JonChesterfield wrote:
> tianshilei1992 wrote:
> > ye-luo wrote:
> > > There can be race when you test List.empty().
> > It is on purpose, and the "race" is not a problem. Think about it. Even we wrap it into a lock and now it is empty, there is still chance that when we move to the next list, one or more nodes are returned to this list. No difference.
> That seems to assume list.empty() is an atomic operation. It isn't - calling list.empty() from one thread while another can be inserting into the list is a data race.
>
> We could do something involving a relaxed read followed by a lock followed by another read, in the double checked locking fashion. Uncontended locks are cheap though so it's probably not worthwhile.
Double check does not work either. If the `empty` function might crash because of the data race, that is a problem. Otherwise, it is not a problem. Like I said, another thread could still insert node into the list after we check empty using a lock.
================
Comment at: openmp/libomptarget/src/MemoryManager.cpp:193
+ // object, therefore the memory free will not succeed.
+ // Deallocate all memory in map
+ for (std::pair<void *, NodePtrTy> P : PtrToNodeTable) {
----------------
JonChesterfield wrote:
> This seems bad. Perhaps we should call a function to do this work shortly before destroying the target plugin?
That is a potential problem, and actually it might not be a problem. Only when we're going to exit the process can this function be invoked. Even the deallocation will not succeed, GPU memory will be free once the process exits anyway.
================
Comment at: openmp/libomptarget/src/MemoryManager.cpp:273
+ // Insert the node into the map table if it is not there
+ if (PtrToNodeTable.find(NodePtr->Ptr) == PtrToNodeTable.end()) {
+ std::lock_guard<std::mutex> Guard(MapTableLock);
----------------
JonChesterfield wrote:
> tianshilei1992 wrote:
> > ye-luo wrote:
> > > There can be race in PtrToNodeTable when you find()
> > There is no race because same `NodePtr` will never go to two threads.
> It looks like PtrToNodeTable can be modified by other threads while this is running. Doesn't matter that NodePtr itself is unique - can't call .find() on the structure while another thread is mutating it.
The iterators will not be invalidated on `multiset` in insert operation, but anyway, I'm not sure whether it will crash in some middle status, so I'll wrap them into the guard lock.
================
Comment at: openmp/libomptarget/src/device.cpp:31
+ DataMapMtx(), PendingGlobalsMtx(), ShadowMtx(),
+ LoopTripCnt(D.LoopTripCnt), MemoryManager(nullptr) {}
+
----------------
JonChesterfield wrote:
> tianshilei1992 wrote:
> > ye-luo wrote:
> > > Why do you think it is OK here leaving the copy constructor always setting MemoryManager nullptr? This cause surprises. The same question applies to assign operator as well.
> > `MemoryManager` will be initialized separately later. The only reason we need this is `std::vector<DeviceTy>` requires it. We don't copy or construct those objects afterwards.
> std::vector<DeviceTy> should be content with a move constructor. Then the copy constructor can be = delete.
`std::mutex` cannot be moved. That is the only reason we have the copy constructor.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D81054/new/
https://reviews.llvm.org/D81054
More information about the Openmp-commits
mailing list