|
27 | 27 | #include <cstddef> |
28 | 28 | #include <cstdlib> |
29 | 29 | #include <iostream> |
| 30 | +#include <mutex> |
30 | 31 | #include <string> |
31 | 32 | #include <type_traits> |
32 | 33 |
|
33 | 34 | namespace axom |
34 | 35 | { |
| 36 | +#ifdef AXOM_USE_UMPIRE |
| 37 | +namespace detail |
| 38 | +{ |
| 39 | +/*! |
| 40 | + * \brief Cache for Umpire data used in axom::copy. |
| 41 | + */ |
| 42 | +struct UmpireCopyContext |
| 43 | +{ |
| 44 | + umpire::strategy::AllocationStrategy* hostStrategy {nullptr}; |
| 45 | + umpire::op::MemoryOperationRegistry* operationRegistry {nullptr}; |
| 46 | +}; |
| 47 | + |
| 48 | +/*! |
| 49 | + * \brief Gets a reference to an UmpireCopyContext object, initializing it on demand. |
| 50 | + * The static UmpireCopyContext is initialized via std::call_once so multiple |
| 51 | + * threads can call this function and only initialize the object once. |
| 52 | + * |
| 53 | + * \return A reference to the cached UmpireCopyContext. |
| 54 | + */ |
| 55 | +inline const UmpireCopyContext& getUmpireCopyContext() noexcept |
| 56 | +{ |
| 57 | + static std::once_flag once; |
| 58 | + static UmpireCopyContext context {}; |
| 59 | + |
| 60 | + // Resolve Umpire's fallback HOST path once so the first threaded axom::copy() |
| 61 | + // cannot race through lazy resource creation. |
| 62 | + std::call_once(once, []() { |
| 63 | + auto& rm = umpire::ResourceManager::getInstance(); |
| 64 | + context.hostStrategy = rm.getAllocator("HOST").getAllocationStrategy(); |
| 65 | + context.operationRegistry = &umpire::op::MemoryOperationRegistry::getInstance(); |
| 66 | + }); |
| 67 | + |
| 68 | + return context; |
| 69 | +} |
| 70 | +} // namespace detail |
| 71 | +#endif |
| 72 | + |
35 | 73 | // To co-exist with Umpire allocator ids, use negative values here. |
36 | 74 | constexpr int INVALID_ALLOCATOR_ID = -1; //!< Place holder for no/unknown allocator |
37 | 75 | constexpr int MALLOC_ALLOCATOR_ID = -3; //!< Refers to MemorySpace::Malloc |
@@ -462,11 +500,11 @@ inline T* reallocate(T* pointer, std::size_t n, int allocID) noexcept |
462 | 500 | inline void copy(void* dst, const void* src, std::size_t numbytes) noexcept |
463 | 501 | { |
464 | 502 | #ifdef AXOM_USE_UMPIRE |
| 503 | + const auto& copyContext = detail::getUmpireCopyContext(); |
465 | 504 | umpire::ResourceManager& rm = umpire::ResourceManager::getInstance(); |
466 | | - umpire::op::MemoryOperationRegistry& op_registry = |
467 | | - umpire::op::MemoryOperationRegistry::getInstance(); |
| 505 | + umpire::op::MemoryOperationRegistry& op_registry = *copyContext.operationRegistry; |
468 | 506 |
|
469 | | - auto dstStrategy = rm.getAllocator("HOST").getAllocationStrategy(); |
| 507 | + auto dstStrategy = copyContext.hostStrategy; |
470 | 508 | auto srcStrategy = dstStrategy; |
471 | 509 |
|
472 | 510 | using AllocationRecord = umpire::util::AllocationRecord; |
|
0 commit comments