[Openmp-commits] [PATCH] D81054: [OpenMP] Introduce target memory manager

Johannes Doerfert via Phabricator via Openmp-commits openmp-commits at lists.llvm.org
Wed Jul 22 19:03:13 PDT 2020


jdoerfert added a comment.

I left a bunch of comments below, from minor nits and style things to design suggestions. I think high-level there are a few things:

- We want to manage device memory for allocations up to as user defined maximum size. That means we need compile time parameters here, maybe also read environment variables at creation time.
- We should consider a "more complex" designs that allow to trade of wasted memory versus number of allocations. For example, we can allocate an array with N elements of size `S` if we run out of `S`-sized nodes. That further minimizes the number of runtime calls through the entire system. Let's leave that for later though.



================
Comment at: openmp/libomptarget/src/device.cpp:204
+      uintptr_t tp =
+          (uintptr_t)MemoryManager.allocate(Size, HstPtrBegin, DeviceID);
       DP("Creating new map entry: HstBase=" DPxMOD ", HstBegin=" DPxMOD ", "
----------------
Nit: make `tp` a `void *` and cast the one use of it as `uintptr_t` instead.


================
Comment at: openmp/libomptarget/src/device.cpp:285
           DPxPTR(HT.TgtPtrBegin), Size);
-      RTL->data_delete(RTLDeviceID, (void *)HT.TgtPtrBegin);
+      MemoryManager.free((void *)HT.TgtPtrBegin, DeviceID);
       DP("Removing%s mapping with HstPtrBegin=" DPxMOD ", TgtPtrBegin=" DPxMOD
----------------
Nit: Remove the cast.


================
Comment at: openmp/libomptarget/src/memory.cpp:61
+  return L;
+}
+
----------------
No inline but static please. Same above. This feels like something we could use from llvm other share with libomp... this code duplication is a nightmare.

Anyway, as @JonChesterfield mentioned, we should aim for a unit test here. We could also add a executable test case that hits a bucket really hard to ensure we can deal with it.



================
Comment at: openmp/libomptarget/src/memory.cpp:68
+  Node(size_t S, void *P) : Size(S), Ptr(P) {}
+};
+
----------------
Function and member comments in doxygen style please. Also in the header.

---

Add a static assert that the node size is 2 * sizeof(void*).


================
Comment at: openmp/libomptarget/src/memory.cpp:70
+
+class MemoryManagerTy {
+  std::list<Node *> FreeList[NumBuckets];
----------------
Comment explaining this thing. I'm also very confused by the duplicated class declaration. Let's not do that.


================
Comment at: openmp/libomptarget/src/memory.cpp:77
+  std::mutex NodeListLock;
+  DeviceTy *Device;
+
----------------
Comments explaining these things. Maybe place the mutexes next to the things they protext.

Why a std::list and an unordered map? 

Naturally, I would have gone with a `vector` or `std::deque`. To "delete" elements I would mark them taken. There should be 32bit padding in a `Node` anyway. Though hard to predict what is good. 

I am unsure about the map, w/o measurements its guesswork and I would go with the regular one but this is fine.


================
Comment at: openmp/libomptarget/src/memory.cpp:85
+    return Device->RTL->data_delete(Device->RTLDeviceID, Ptr);
+  }
+
----------------
Comments on all of these please. Maye `allocateOnDevice` as name instead? 


================
Comment at: openmp/libomptarget/src/memory.cpp:91
+  // free one or two) and try to allocate again until either we can get memory
+  // or every buffer we hold has been freed.
+  void *freeAndAllocate(size_t Size, void *HstPtr) {
----------------
Hm.. running out of memory seems like a "edge case" and if it happens it seems "likely" it happens again. Why not use the opportunity to free everything in the free list while we are here. I mean, it will be "cheaper", complexity wise, reasonably useful given that the next allocation will hit the same problem, and very much simpler.


================
Comment at: openmp/libomptarget/src/memory.cpp:150
+        deleteFromDevice(N.Ptr);
+  }
+
----------------
If this is part of the device, the place we tear down the context, this issue should go away, I think.


================
Comment at: openmp/libomptarget/src/memory.cpp:153
+  void *allocate(size_t Size, void *HstPtr) {
+    assert(Size && "Size is zero");
+
----------------
At least for malloc and friends that is totally fine btw. If we filter this earlier we can leave the assert though.


================
Comment at: openmp/libomptarget/src/memory.cpp:158
+
+    const int B = findBucket(Size);
+    std::list<Node *> &List = FreeList[B];
----------------
Descriptive variable names are worth the trouble typing.


================
Comment at: openmp/libomptarget/src/memory.cpp:172
+      // Allocate one from device
+      DevPtr = allocateFromDevice(Size, HstPtr);
+
----------------
We should round the size up to increase reuse. Also makes all blocks in a bucket the same size.


================
Comment at: openmp/libomptarget/src/memory.cpp:182
+      if (DevPtr == nullptr)
+        return nullptr;
+
----------------
Nothing is wrong, we just run OOM, return a `nullptr` and all is good.


================
Comment at: openmp/libomptarget/src/memory.cpp:197
+        P = &NodeList.back();
+      }
+    } else {
----------------
As the lock is released, this can/should go into a helper function.


================
Comment at: openmp/libomptarget/src/memory.h:21
+class MemoryManagerTy {
+public:
+  // Allocate memory from device DeviceId
----------------
If there is no private state I'd go for struct. Though I would have expected private state TBH.


================
Comment at: openmp/libomptarget/src/memory.h:35
+
+extern MemoryManagerTy MemoryManager;
----------------
I think the MemoryManager, like the StreamManager, is a thing that belongs to a Device. Different devices might choose different implementations etc. That also reduced our global state footprint. Note that you can and should keep the memory.{h,cpp} files, but make the object part of a Device if possible.


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