Remove meta information from host allocator policy
[alexxy/gromacs.git] / src / gromacs / gpu_utils / hostallocator.cpp
index b983ab0fd496e881f20c77eb7b7ae26757e39fa4..1553aa930a24b0b2f41ce1162b493c7aa0a49d15 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 
 #include <memory>
 
+#include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/gpu_utils/pinning.h"
 #include "gromacs/utility/alignedallocator.h"
 #include "gromacs/utility/gmxassert.h"
 namespace gmx
 {
 
-//! Private implementation class.
-class HostAllocationPolicy::Impl
-{
-    public:
-        /*! \brief Pointer to the last unfreed allocation, or nullptr
-         * if no allocation exists.
-         *
-         * Note that during e.g. std::vector.resize() a call to its
-         * allocator's allocate() function precedes the call to its
-         * allocator's deallocate() function for freeing the old
-         * buffer after the data has been copied from it. So in
-         * general, pointer_ will not match the argument received by
-         * free(). */
-        void         *pointer_ = nullptr;
-        //! Number of bytes in the last unfreed allocation.
-        std::size_t   numBytes_ = 0;
-        //! The pointer to any storage that has been pinned, or nullptr if none has been pinned.
-        void         *pinnedPointer_ = nullptr;
-        //! Whether this object is in mode where new allocations will be pinned by default.
-        PinningPolicy pinningPolicy_ = PinningPolicy::CannotBePinned;
-};
-
-HostAllocationPolicy::HostAllocationPolicy() : impl_(std::make_shared<Impl>())
+HostAllocationPolicy::HostAllocationPolicy(PinningPolicy pinningPolicy)
+    : pinningPolicy_(pinningPolicy)
 {
+    if (GMX_GPU != GMX_GPU_CUDA)
+    {
+        GMX_RELEASE_ASSERT(pinningPolicy == PinningPolicy::CannotBePinned,
+                           "A suitable build of GROMACS (e.g. with CUDA) is required for a "
+                           "HostAllocationPolicy to be set to a mode that produces pinning.");
+    }
 }
 
 std::size_t HostAllocationPolicy::alignment()
 {
-    return (impl_->pinningPolicy_ == PinningPolicy::CanBePinned ?
+    return (pinningPolicy_ == PinningPolicy::CanBePinned ?
             PageAlignedAllocationPolicy::alignment() :
             AlignedAllocationPolicy::alignment());
 }
+
 void *HostAllocationPolicy::malloc(std::size_t bytes) const noexcept
 {
-    // A container could have a pinned allocation that is being
-    // extended, in which case we must un-pin while we still know the
-    // old pinned vector, and which also ensures we don't pin two
-    // buffers at the same time. If there's no allocation, or it isn't
-    // pinned, then attempting to unpin it is OK, too.
-    unpin();
-    impl_->pointer_ = (impl_->pinningPolicy_ == PinningPolicy::CanBePinned ?
-                       PageAlignedAllocationPolicy::malloc(bytes) :
-                       AlignedAllocationPolicy::malloc(bytes));
-
-    if (impl_->pointer_ != nullptr)
+    if (pinningPolicy_ == PinningPolicy::CanBePinned)
+    {
+        void *p = PageAlignedAllocationPolicy::malloc(bytes);
+        pin(p, bytes);
+        return p;
+    }
+    else
     {
-        impl_->numBytes_ = bytes;
+        return AlignedAllocationPolicy::malloc(bytes);
     }
-    pin();
-    return impl_->pointer_;
 }
 
 void HostAllocationPolicy::free(void *buffer) const noexcept
 {
-    unpin();
     if (buffer == nullptr)
     {
         // Nothing to do
         return;
     }
-    if (impl_->pinningPolicy_ == PinningPolicy::CanBePinned)
+    unpin(buffer);
+    if (pinningPolicy_ == PinningPolicy::CanBePinned)
     {
         PageAlignedAllocationPolicy::free(buffer);
     }
@@ -124,65 +105,29 @@ void HostAllocationPolicy::free(void *buffer) const noexcept
     {
         AlignedAllocationPolicy::free(buffer);
     }
-    impl_->pointer_  = nullptr;
-    impl_->numBytes_ = 0;
 }
 
-PinningPolicy HostAllocationPolicy::pinningPolicy() const
+void HostAllocationPolicy::pin(void gmx_unused *p, size_t gmx_unused n) const noexcept
 {
-    return impl_->pinningPolicy_;
-}
-
-void HostAllocationPolicy::setPinningPolicy(PinningPolicy pinningPolicy)
-{
-    if (GMX_GPU != GMX_GPU_CUDA)
-    {
-        GMX_RELEASE_ASSERT(pinningPolicy == PinningPolicy::CannotBePinned,
-                           "A suitable build of GROMACS (e.g. with CUDA) is required for a "
-                           "HostAllocationPolicy to be set to a mode that produces pinning.");
-    }
-    impl_->pinningPolicy_ = pinningPolicy;
-}
-
-void HostAllocationPolicy::pin() const noexcept
-{
-    if (impl_->pinningPolicy_ == PinningPolicy::CannotBePinned ||
-        impl_->pointer_ == nullptr ||
-        impl_->pinnedPointer_ != nullptr)
+#if GMX_GPU == GMX_GPU_CUDA
+    // I believe this if statement isn't required for calls from malloc. But it
+    // is required for the unit tests. Which might not make much sense to test
+    // cases which can't actually happen for an allocator.
+    if (p == nullptr || n == 0 || isHostMemoryPinned(p))
     {
-        // Do nothing if we're not in pinning mode, or the allocation
-        // is empty, or it is already pinned.
         return;
     }
-#if GMX_GPU == GMX_GPU_CUDA
-    pinBuffer(impl_->pointer_, impl_->numBytes_);
-    impl_->pinnedPointer_ = impl_->pointer_;
-#else
-    const char *errorMessage = "Could not register the host memory for pinning.";
-
-    GMX_RELEASE_ASSERT(impl_->pinningPolicy_ == PinningPolicy::CannotBePinned,
-                       formatString("%s This build configuration must only have pinning policy "
-                                    "that leads to no pinning.", errorMessage).c_str());
+    pinBuffer(p, n);
 #endif
 }
 
-void HostAllocationPolicy::unpin() const noexcept
+void HostAllocationPolicy::unpin(void gmx_unused *p) const noexcept
 {
-    if (impl_->pinnedPointer_ == nullptr)
+#if GMX_GPU == GMX_GPU_CUDA
+    if (isHostMemoryPinned(p))
     {
-        return;
+        unpinBuffer(p);
     }
-
-#if GMX_GPU == GMX_GPU_CUDA
-    // Note that if the caller deactivated pinning mode, we still want
-    // to be able to unpin if the allocation is still pinned.
-
-    unpinBuffer(impl_->pointer_);
-    impl_->pinnedPointer_ = nullptr;
-#else
-    GMX_RELEASE_ASSERT(impl_->pinnedPointer_ == nullptr,
-                       "Since the build configuration does not support pinning, then "
-                       "the pinned pointer must be nullptr.");
 #endif
 }