Transfer files from RAD repository

Αυτή η υποβολή περιλαμβάνεται σε:
Brandon Potter
2024-07-01 09:57:08 -05:00
γονέας a30da178c1
υποβολή ea8f264a11
382 αρχεία άλλαξαν με 67034 προσθήκες και 1 διαγραφές
@@ -0,0 +1,32 @@
###############################################################################
# Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
###############################################################################
###############################################################################
# ADD ROCSHMEM TARGET FOR FILES IN CURRENT DIRECTORY
###############################################################################
target_sources(
${PROJECT_NAME}
PRIVATE
single_heap.cpp
slab_heap.cpp
memory_allocator.cpp
)
@@ -0,0 +1,133 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_ADDRESS_RECORD_HPP_
#define LIBRARY_SRC_MEMORY_ADDRESS_RECORD_HPP_
#include <cassert>
#include <utility>
/**
* @file address_record.hpp
*
* @brief Contains an address record class
*
* The address record is intended to be used by allocators which need to
* keep track of raw pointers and the corresponding allocation size.
*/
namespace rocshmem {
class AddressRecord {
/**
* @brief Helper type for address records
*/
using AR_T = AddressRecord;
public:
/**
* @brief Default constructor
*
* @note This constructor generates an empty record. In some contexts,
* an empty record signifies an INVALID record and is treated
* accordingly.
*/
AddressRecord() = default;
/**
* @brief Primary constructor type
*
* @param[in] raw pointer holding an address
* @param[in] size
*/
AddressRecord(char* address, size_t size) : address_(address), size_(size) {}
/**
* @brief Accessor for address_
*
* @return raw pointer
*/
char* get_address() { return address_; }
/**
* @brief Accessor for size_
*
* @return size
*/
size_t get_size() { return size_; }
/**
* @brief Splits record in half
*
* @return pair containing initialized address records
*/
std::pair<AR_T, AR_T> split() {
assert(address_);
assert(size_);
auto half_size{size_ >> 1};
assert(half_size);
AR_T e1{address_, half_size};
AR_T e2{address_ + half_size, half_size};
return {e1, e2};
}
/**
* @brief Combines record with another record
*
* @return an address record containing both input records
*/
AR_T combine(AR_T other) {
assert(address_);
assert(other.get_address());
bool this_smaller{address_ < other.get_address()};
auto smaller_addr{this_smaller ? address_ : other.get_address()};
[[maybe_unused]] auto larger_addr{this_smaller ? other.get_address()
: address_};
assert(size_ == other.get_size());
auto combined_size{size_ + size_};
assert(smaller_addr + size_ == larger_addr);
AR_T record{smaller_addr, combined_size};
return record;
}
private:
/**
* @brief raw memory pointer
*/
char* address_{nullptr};
/**
* @brief size of address record
*/
size_t size_{0};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_ADDRESS_RECORD_HPP_
+85
Προβολή Αρχείου
@@ -0,0 +1,85 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_BIN_HPP_
#define LIBRARY_SRC_MEMORY_BIN_HPP_
#include <cassert>
#include <stack>
/**
* @file bin.hpp
*
* @brief Simple container class
*
* The class wraps a stack and provides simple mutators. A different internal
* container class might be preferable to a stack.
*/
namespace rocshmem {
template <typename T>
class Bin {
public:
/**
* @brief Is stack empty?
*
* @return A boolean denoting stack emptiness
*/
bool empty() { return stack_.empty(); }
/**
* @brief How many elements in stack?
*
* @return The number of elements in the stack
*/
size_t size() { return stack_.size(); }
/**
* @brief Emplace an element in stack
*
* @param[in] An element
*/
void put(T element) { stack_.emplace(element); }
/**
* @brief Retrieve an element from stack
*
* @return An element
*/
T get() {
assert(stack_.size());
auto top = stack_.top();
stack_.pop();
return top;
}
private:
/**
* @brief Implementation container
*/
std::stack<T> stack_{};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_BIN_HPP_
+246
Προβολή Αρχείου
@@ -0,0 +1,246 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_BINNER_HPP_
#define LIBRARY_SRC_MEMORY_BINNER_HPP_
#include <cassert>
#include <climits>
#include <iostream>
#include <vector>
#include "../constants.hpp"
#include "bin.hpp"
/**
* @file binner.hpp
*
* @brief Contains a builder for bins_ object in Pow2Bins.
*/
namespace rocshmem {
/**
* @brief Helper to choose between clz variants
*
* @param[in] An input value
*
* @return __builtin_clz value
*/
template <typename T>
inline int clz_fn([[maybe_unused]] T v) {
assert(false);
return 0;
}
template <>
inline int clz_fn(unsigned v) {
return __builtin_clz(v);
}
template <>
inline int clz_fn(unsigned long v) {
return __builtin_clzl(v);
}
template <>
inline int clz_fn(unsigned long long v) {
return __builtin_clzll(v);
}
/**
* @brief Finds the bit position of the first one
*
* @param[in] An input value
*
* @return A bit position or UINT_MAX
*/
template <typename T>
inline unsigned find_first_set_one(T v) {
if (v == 0) {
return UINT_MAX;
}
auto num_bytes{sizeof(T)};
auto num_bits{num_bytes * CHAR_BIT};
auto num_leading_zeroes{clz_fn(v)};
auto last_zero_bit_position{num_bits - num_leading_zeroes};
auto first_one_bit_position{last_zero_bit_position - 1};
return first_one_bit_position;
}
template <typename AR_T, typename BINS_T>
class Binner {
public:
/**
* @brief Required for default construction of other objects
*
* @note Not intended for direct usage.
*/
Binner() = default;
/**
* @brief Primary constructor type
*
* Constructs bins by inserting a set of bin into it.
*
* @param[in] Raw memory pointer to bins object
* @param[in] Raw memory pointer to symmetric heap memory.
* @param[in] Size of symmetric heap allocation.
*/
Binner(BINS_T* bins, char* heap_ptr, size_t heap_size)
: bins_{bins}, heap_{heap_ptr, heap_size} {
auto bit_position_heap{find_first_set_one(heap_size)};
assert(bit_position_heap != UINT_MAX);
auto bit_position_align{find_first_set_one(ALIGNMENT)};
assert(bit_position_align != UINT_MAX);
assert(bit_position_heap >= bit_position_align);
auto difference_in_position{bit_position_heap - bit_position_align};
auto vector_size{difference_in_position + 1};
std::vector<size_t> v;
v.resize(vector_size);
auto pow2 = [&bit_position_align]() {
return std::pow(2, bit_position_align++);
};
std::generate(v.begin(), v.end(), pow2);
for (auto x : v) {
bins_->insert({x, Bin<AR_T>{}});
}
}
/**
* @brief Assign symmetric heap memory to bins object
*/
void assign_heap_to_bins() {
assert(bins_);
assert(heap_.get_address());
assert(heap_.get_size());
ignore_unaligned_heap_memory();
assign_heap_memory_to_bins();
}
/**
* @brief Accessor for bins_ pointer.
*
* @return Raw pointer to bins_
*
* @note Used by unit-test test fixture
*/
BINS_T* get_bins() { return bins_; }
/**
* @brief Dump the bins_ object to the standard out
*/
void dump_bins() {
auto dump_bin = [](const auto& pair) {
auto [address, bin] = pair;
std::cout << "address " << address << " bin.size " << bin.size()
<< std::endl;
};
std::for_each(bins_->begin(), bins_->end(), dump_bin);
}
private:
/**
* @brief Shift assignment point past unaligned memory.
*/
void ignore_unaligned_heap_memory() {
static_assert(sizeof(char) == 1);
auto heap_ptr{heap_.get_address()};
size_t off_by_bytes{reinterpret_cast<size_t>(heap_ptr) % ALIGNMENT};
if (off_by_bytes) {
size_t required_offset{ALIGNMENT - off_by_bytes};
heap_ptr += required_offset;
auto heap_size{heap_.get_size() - required_offset};
heap_ = AR_T(heap_ptr, heap_size);
}
}
/**
* @brief Delegate method for top-level heap assignment.
*/
void assign_heap_memory_to_bins() {
AR_T chunk = heap_;
while (chunk.get_address()) {
chunk = assign_heap_chunk(chunk);
}
}
/**
* @brief Chunk heap memory up into bin sized allocations
*
* The method starts with the largest chunks possible and proceeds
* to smaller chunks. It continues chunking until there are no more
* chunks which will fit into bins.
*
* @param[in] An address record
*
* @return An address record minus a chunk
*/
AR_T assign_heap_chunk(AR_T address_record) {
char* memory_chunk{address_record.get_address()};
size_t memory_chunk_size{address_record.get_size()};
auto rit{bins_->rbegin()};
auto rend{bins_->rend()};
while (rit != rend) {
auto& [bin_memory_chunk_size, bin] = *rit;
if (memory_chunk_size >= bin_memory_chunk_size) {
break;
}
rit++;
}
if (rit == rend) {
return {nullptr, 0};
}
auto& [bin_memory_chunk_size, bin] = *rit;
bin.put({memory_chunk, bin_memory_chunk_size});
return {memory_chunk + bin_memory_chunk_size,
memory_chunk_size - bin_memory_chunk_size};
}
/**
* @brief Raw pointer to external bins_ object
*/
BINS_T* bins_{nullptr};
/**
* @brief An address record holding heap object's information
*/
AR_T heap_{};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_BINNER_HPP_
@@ -0,0 +1,144 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_DEV_MONO_LINEAR_HPP_
#define LIBRARY_SRC_MEMORY_DEV_MONO_LINEAR_HPP_
#include <cassert>
#include "shmem_allocator_strategy.hpp"
#include "../util.hpp"
/**
* @file dev_mono_linear.hpp
*
* @brief Contains an allocator strategy for the heap.
*
* This strategy returns memory chunks by monotonically increasing a pointer.
*/
namespace rocshmem {
template <typename HM_T>
class DevMonoLinear : public ShmemAllocatorStrategy {
public:
/**
* @brief Required for default construction of other objects
*
* @note Not intended for direct usage.
*/
DevMonoLinear() = default;
/**
* @brief Primary constructor type
*
* @param[in] Raw pointer to heap memory type
*/
explicit DevMonoLinear(HM_T* heap_mem)
: heap_mem_{heap_mem}, current_ptr_{heap_mem_->get_ptr()} {}
/**
* @brief Allocates memory from the heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
void alloc(char** ptr, size_t request_size) override {
assert(ptr);
*ptr = nullptr;
if (!request_size) {
return;
}
char* heap_end{heap_mem_->get_ptr() + heap_mem_->get_size()};
if (current_ptr_ + request_size < heap_end) {
*ptr = current_ptr_;
current_ptr_ += request_size;
}
}
/**
* @brief Allocates memory from the heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
__device__ void alloc(char** ptr, size_t request_size) override {
if (is_thread_zero_in_block()) {
assert(ptr);
*ptr = nullptr;
if (!request_size) {
return;
}
char* heap_end{heap_mem_->get_ptr() + heap_mem_->get_size()};
if (current_ptr_ + request_size < heap_end) {
*ptr = current_ptr_;
current_ptr_ += request_size;
}
}
}
/**
* @brief Frees memory from the heap
*
* Released memory ignored.
*
* @param[in] Raw pointer to heap memory
*/
__host__ void free([[maybe_unused]] char* ptr) override {}
/**
* @brief Frees memory from the heap
*
* Released memory ignored.
*
* @param[in] Raw pointer to heap memory
*/
__device__ void free([[maybe_unused]] char* ptr) override {}
/**
* @brief Return pointer to monotonic linear ptr
*
* @return Raw pointer to heap memory.
*/
__host__ __device__ char* current() { return current_ptr_; }
private:
/**
* The pointer is used to keep reference to heap memory.
*/
HM_T* heap_mem_{nullptr};
/**
* The pointer is used to track the next allocation point.
*/
char* current_ptr_{nullptr};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_DEV_MONO_LINEAR_HPP_
@@ -0,0 +1,133 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_HEAP_MEMORY_HPP_
#define LIBRARY_SRC_MEMORY_HEAP_MEMORY_HPP_
#include <cassert>
#include <memory>
#include <utility>
/**
* @file heap_memory.hpp
*
* @brief Contains heap memory class
*
* @note The heap memory class owns the symmetric heap memory allocation
*/
namespace rocshmem {
template <typename ALLOCATOR>
class HeapMemory {
public:
/**
* @brief Primary constructor type
*
* Uses default heap size specified in class body.
*/
HeapMemory() : HeapMemory(gibibyte_) {}
/**
* @brief Secondary constructor type
*
* @param[in] User-specified size used as heap size
*/
explicit HeapMemory(size_t size) : size_{size} {
char* temp;
allocator_.allocate(reinterpret_cast<void**>(&temp), size_);
assert(temp);
std::unique_ptr<char, Deleter> up{temp};
up_ = std::move(up);
/*
* Set a c-style ptr for access by the device.
*/
ptr_ = up_.get();
}
/**
* @brief Accessor for heap ptr
*
* @return Raw memory pointer
*/
__host__ __device__ char* get_ptr() { return ptr_; }
/**
* @brief Accessor for heap size
*
* @return Heap size
*/
__host__ __device__ size_t get_size() { return size_; }
/**
* @brief Returns is the heap is allocated with managed memory
*
* @return bool
*/
bool is_managed() { return allocator_.is_managed(); }
private:
/**
* @brief Template type member with allocate and deallocate methods.
*/
ALLOCATOR allocator_{};
/**
* @brief Wrap deallocator into a functor for up_ template.
*/
class Deleter {
public:
void operator()(void* x) { a_.deallocate(x); }
private:
ALLOCATOR a_;
};
/**
* @brief Owning pointer to heap memory.
*/
std::unique_ptr<char, Deleter> up_{nullptr};
/**
* @brief Named constant for a gibibyte.
*/
static constexpr size_t gibibyte_{1 << 30};
/**
* @brief Size of heap memory.
*/
size_t size_{gibibyte_};
/**
* @brief A handle to access the internal memory.
*
* In general, device code cannot access standard library routines
* like std::unique_ptr::get(). Circumvent this problem by caching
* the pointer manually in this class.
*/
char* ptr_{nullptr};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_HEAP_MEMORY_HPP_
@@ -0,0 +1,55 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_HEAP_TYPE_HPP_
#define LIBRARY_SRC_MEMORY_HEAP_TYPE_HPP_
#include "config.h" // NOLINT(build/include_subdir)
#include "hip_allocator.hpp"
/**
* @file heap_type.hpp
*
* @brief Contains the type of heap memory used to allocate the symmetric heap
*
* The heap type in this file is used by other classes to select the allocation
* policy for the symmetric heap. The heap type choices depend on whether
* the heap is cacheable in hardware and if the heap is a managed memory type.
*/
namespace rocshmem {
#if defined USE_MANAGED_HEAP
using HEAP_T = HeapMemory<HIPAllocatorManaged>;
#elif defined USE_COHERENT_HEAP || defined USE_CACHED_HEAP
using HEAP_T = HeapMemory<HIPAllocator>;
#elif defined USE_HOST_HEAP
using HEAP_T = HeapMemory<HostAllocator>;
#elif defined USE_HIP_HOST_HEAP
using HEAP_T = HeapMemory<HIPHostAllocator>;
#else
using HEAP_T = HeapMemory<HIPDefaultFinegrainedAllocator>;
#endif
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_HEAP_TYPE_HPP_
@@ -0,0 +1,139 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_HIP_ALLOCATOR_HPP_
#define LIBRARY_SRC_MEMORY_HIP_ALLOCATOR_HPP_
/**
* @file hip_allocator.hpp
*
* @brief Contains HIP wrapper class for memory allocator
*/
#include <hip/hip_runtime_api.h>
#include <cstdlib>
#include <limits>
#include "memory_allocator.hpp"
// `hipDeviceMallocUncached` was introduced at ROCm 5.5
#if HIP_VERSION_MAJOR >= 5 && HIP_VERSION_MINOR >= 5
#define HIP_SUPPORTS_MALLOC_UNCACHED
#endif
namespace rocshmem {
class HIPAllocator : public MemoryAllocator {
public:
HIPAllocator() : MemoryAllocator(hipMalloc, hipFree) {}
};
class HIPAllocatorFinegrained : public MemoryAllocator {
public:
HIPAllocatorFinegrained()
: MemoryAllocator(hipExtMallocWithFlags, hipFree,
hipDeviceMallocFinegrained) {}
};
#ifdef HIP_SUPPORTS_MALLOC_UNCACHED
class HIPAllocatorUncached : public MemoryAllocator {
public:
HIPAllocatorUncached()
: MemoryAllocator(hipExtMallocWithFlags, hipFree,
hipDeviceMallocUncached) {}
};
// The default fine-grained coherence allocator is the uncached allocator
using HIPDefaultFinegrainedAllocator = HIPAllocatorUncached;
#else
// The default fine-grained coherence allocator is the fine-grained allocator
using HIPDefaultFinegrainedAllocator = HIPAllocatorFinegrained;
#endif
class HIPAllocatorManaged : public MemoryAllocator {
public:
HIPAllocatorManaged()
: MemoryAllocator(hipMallocManaged, hipFree, hipMemAttachHost) {
_managed = true;
}
};
class HIPHostAllocator : public MemoryAllocator {
public:
HIPHostAllocator()
: MemoryAllocator(hipHostMalloc, hipFree, hipHostMallocCoherent) {}
};
class HostAllocator : public MemoryAllocator {
public:
HostAllocator() : MemoryAllocator(std::malloc, std::free) {}
};
class PosixAligned64Allocator : public MemoryAllocator {
public:
PosixAligned64Allocator() : MemoryAllocator(posix_memalign, std::free, 64) {}
};
template <class T>
class StdAllocatorHIP {
public:
typedef T value_type;
StdAllocatorHIP() = default;
template <class U>
constexpr StdAllocatorHIP(const StdAllocatorHIP<U>&) noexcept {}
[[nodiscard]] T* allocate(size_t n) {
if (n > std::numeric_limits<size_t>::max() / sizeof(T)) {
throw std::bad_array_new_length();
}
T* p{nullptr};
allocator_.allocate(reinterpret_cast<void**>(&p), n * sizeof(T));
if (p) {
return p;
}
throw std::bad_alloc();
}
void deallocate(T* p, [[maybe_unused]] size_t n) noexcept {
allocator_.deallocate(p);
}
private:
HIPDefaultFinegrainedAllocator allocator_{};
};
template <class T, class U>
bool operator==(const StdAllocatorHIP<T>&, const StdAllocatorHIP<U>&) {
return true;
}
template <class T, class U>
bool operator!=(const StdAllocatorHIP<T>&, const StdAllocatorHIP<U>&) {
return false;
}
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_HIP_ALLOCATOR_HPP_
@@ -0,0 +1,99 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#include "memory_allocator.hpp"
#include <cassert>
#include "../util.hpp"
namespace rocshmem {
MemoryAllocator::MemoryAllocator(hipError_t (*hip_alloc_fn)(void**, size_t,
unsigned),
hipError_t (*hip_free_fn)(void*),
unsigned flags)
: _hip_alloc_with_flags(hip_alloc_fn),
_hip_free(hip_free_fn),
_flags(flags) {}
MemoryAllocator::MemoryAllocator(hipError_t (*hip_alloc_fn)(void**, size_t),
hipError_t (*hip_free_fn)(void*))
: _hip_alloc(hip_alloc_fn), _hip_free(hip_free_fn) {}
MemoryAllocator::MemoryAllocator(std::function<void*(size_t)> alloc_fn,
std::function<void(void*)> free_fn)
: _alloc(alloc_fn), _free(free_fn) {}
MemoryAllocator::MemoryAllocator(
std::function<int(void**, size_t, size_t)> posix_align_fn,
std::function<void(void*)> free_fn, size_t alignment)
: _alloc_posix_memalign(posix_align_fn),
_free(free_fn),
_alignment(alignment) {}
void MemoryAllocator::allocate(void** void_ptr, size_t size) {
assert(void_ptr);
if (_alloc) {
*(reinterpret_cast<char**>(void_ptr)) =
reinterpret_cast<char*>(_alloc(size));
assert(*reinterpret_cast<char**>(void_ptr));
return;
}
if (_alloc_posix_memalign) {
assert(_alignment);
_alloc_posix_memalign(void_ptr, _alignment, size);
assert(*reinterpret_cast<char**>(void_ptr));
return;
}
if (_hip_alloc) {
CHECK_HIP(_hip_alloc(void_ptr, size));
return;
}
if (_hip_alloc_with_flags) {
CHECK_HIP(_hip_alloc_with_flags(void_ptr, size, _flags));
return;
}
assert(false);
}
void MemoryAllocator::deallocate(void* ptr) {
if (!ptr) {
return;
}
if (_free) {
_free(ptr);
return;
}
if (_hip_free) {
CHECK_HIP(_hip_free(ptr));
return;
}
assert(false);
}
bool MemoryAllocator::is_managed() { return _managed; }
} // namespace rocshmem
@@ -0,0 +1,168 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_MEMORY_ALLOCATOR_HPP_
#define LIBRARY_SRC_MEMORY_MEMORY_ALLOCATOR_HPP_
/**
* @file memory_allocator.hpp
*
* @brief Wraps allocators in a uniform interface
*/
#include <hip/hip_runtime_api.h>
#include <cstdlib>
#include <functional>
namespace rocshmem {
class MemoryAllocator {
public:
/**
* @brief Required for default construction of other objects
*
* @note Not intended for direct usage.
*/
MemoryAllocator() = default;
/**
* @brief Primary constructor
*
* @param[in] hip library allocation function
* @param[in] hip library free function
* @param[in] hip flags
*
* @note Finegrained flag is assumed by default
*/
MemoryAllocator(hipError_t (*hip_alloc_fn)(void**, size_t, unsigned),
hipError_t (*hip_free_fn)(void*), unsigned flags);
/**
* @brief Primary constructor
*
* @param[in] hip library allocation function
* @param[in] hip library free function
*/
MemoryAllocator(hipError_t (*hip_alloc_fn)(void**, size_t),
hipError_t (*hip_free_fn)(void*));
/**
* @brief Primary constructor
*
* @param[in] an allocation function
* @param[in] a free function
*/
MemoryAllocator(std::function<void*(size_t)> alloc_fn,
std::function<void(void*)> free_fn);
/**
* @brief Primary constructor
*
* @param[in] an allocation function
* @param[in] a free function
* @param[in] alignment for allocations
*/
MemoryAllocator(std::function<int(void**, size_t, size_t)> posix_align_fn,
std::function<void(void*)> free_fn, size_t alignment);
/**
* @brief Allocates memory
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
void allocate(void** ptr, size_t size);
/**
* @brief Deallocates memory
*
* @param[in] Address of raw pointer (&pointer_to_char)
*/
void deallocate(void* ptr);
/**
* @brief Returns is memory is managed
*
* @return returns whether this memory is managed
*/
bool is_managed();
protected:
/**
* @brief is this memory allocated using managed memory
*/
bool _managed{false};
private:
/**
* @brief a posix allocator function for memory aligned accesses
*/
std::function<int(void**, size_t, size_t)> _alloc_posix_memalign;
/**
* @brief alignment for posix_memalign allocations
*/
size_t _alignment{0};
/**
* @brief a standard allocator function
*/
std::function<void*(size_t)> _alloc{nullptr};
/**
* @brief a standard free function
*/
std::function<void(void*)> _free{nullptr};
/**
* @brief a hip-specific allocator function
*/
std::function<hipError_t(void**, size_t)> _hip_alloc{nullptr};
/**
* @brief a hip-specific allocator function
*/
std::function<hipError_t(void**, size_t, unsigned)> _hip_alloc_with_flags{
nullptr};
/**
* @brief flags specified in hip_runtime_api.h
*
* Used as a runtime input parameter to the _hip_alloc_with_flags function.
*/
unsigned _flags{0x0};
/**
* @brief a hip-specific free function
*/
std::function<hipError_t(void*)> _hip_free{nullptr};
/**
* @brief a hip-specific return code
*/
hipError_t _hip_return_value{hipSuccess};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_MEMORY_ALLOCATOR_HPP_
@@ -0,0 +1,83 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
/**
* @file notifier.hpp
*
* @brief Contains the notification memory space for threads to communicate
* results with one another.
*
* Assume one thread does work on behalf of other threads (as a leader) and
* that work needs to be communicated to the other threads as a result.
* To expose the result, the threads need to share a memory space where the
* result can be written. The leader thread writes the result out to this
* memory space and all threads synchronize on it.
*
* This class allows the leader thread to notify other threads of the update.
*/
#ifndef LIBRARY_SRC_MEMORY_NOTIFIER_HPP_
#define LIBRARY_SRC_MEMORY_NOTIFIER_HPP_
#include "../device_proxy.hpp"
#include "../util.hpp"
namespace rocshmem {
class Notifier {
public:
__device__ uint64_t read() { return value_; }
__device__ void write(uint64_t val) {
if (is_thread_zero_in_block()) {
value_ = val;
}
publish();
}
__device__ void done() { __syncthreads(); }
private:
__device__ void publish() {
if (is_thread_zero_in_block()) {
__threadfence();
}
__syncthreads();
}
uint64_t value_{};
};
template <typename ALLOCATOR>
class NotifierProxy {
using ProxyT = DeviceProxy<ALLOCATOR, Notifier, 1>;
public:
__host__ __device__ Notifier* get() { return proxy_.get(); }
private:
ProxyT proxy_{};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_NOTIFIER_HPP_
@@ -0,0 +1,353 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_POW2_BINS_HPP_
#define LIBRARY_SRC_MEMORY_POW2_BINS_HPP_
#include <cassert>
#include <map>
#include "../constants.hpp"
#include "bin.hpp"
#include "binner.hpp"
#include "shmem_allocator_strategy.hpp"
/**
* @file pow2_bins.hpp
*
* @brief Contains an allocator strategy for the heap.
*
* This strategy returns memory chunks with power-of-two sizes.
*/
namespace rocshmem {
template <typename AR_T, typename HM_T>
class Pow2Bins : public ShmemAllocatorStrategy {
/**
* @brief Helper type for bins of address records
*/
using BIN_T = Bin<AR_T>;
/**
* @brief Helper type for size to bin maps
*/
using BINS_T = std::map<size_t, BIN_T>;
/**
* @brief Helper type for BINS_T iterator
*/
using BINS_IT_T = typename BINS_T::iterator;
/**
* @brief Helper type for raw pointers to address record maps
*/
using PROFFERED_T = std::map<char*, AR_T>;
public:
/**
* @brief Required for default construction of other objects
*
* @note Not intended for direct usage.
*/
Pow2Bins() = default;
/**
* @brief Primary constructor type
*
* @param[in] Raw pointer to heap memory type
*/
explicit Pow2Bins(HM_T* heap_mem)
: binner_{&bins_, heap_mem->get_ptr(), heap_mem->get_size()} {
binner_.assign_heap_to_bins();
}
/**
* @brief Allocates memory from the heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
void alloc(char** ptr, size_t request_size) override {
assert(ptr);
*ptr = nullptr;
if (!request_size) {
return;
}
auto do_request_using = [&](auto it) {
if (it != bins_.end()) {
AR_T record{retrieve_record_from_bin(it)};
/*
* Record retrieval may have generated INVALID record.
* If INVALID, do not mark record as proffered.
* Also notice, input pointer "ptr" may have nullptr value.
*/
if (record.get_address()) {
emplace_in_proffered(record);
}
*ptr = record.get_address();
}
};
/*
* Try to find exact power-of-two matches.
*/
do_request_using(bins_.find(request_size));
if (*ptr) {
return;
}
/*
* Round up to the nearest power-of-two size.
*/
do_request_using(bins_.lower_bound(request_size));
}
/**
* @brief Allocates memory from the heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*
* @note Not implemented
*/
__device__ void alloc([[maybe_unused]] char** ptr,
[[maybe_unused]] size_t request_size) override {}
/**
* @brief Frees memory from the heap
*
* Released memory is tracked by bookkeeping structures within this class.
*
* @param[in] Raw pointer to heap memory
*
* @note We do not attempt to combine records together into larger
* even if it is possible to do so. This may eventually exhaust the
* number of records in the larger bins.
*/
void free(char* ptr) override {
auto record{retrieve_from_proffered(ptr)};
emplace_record_in_bin(record);
}
/**
* @brief Frees memory from the heap
*
* Released memory is tracked by bookkeeping structures within this class.
*
* @param[in] Raw pointer to heap memory
*
* @note Not implemented
*/
__device__ void free([[maybe_unused]] char* ptr) override {}
/**
* @brief Sum of all proffered_ memory sizes
*
* @return memory size
*/
size_t amount_proffered() {
size_t size{0};
auto sum_sizes = [&size](const auto& pair) {
auto [address, record] = pair;
size += record.get_size();
};
std::for_each(proffered_.begin(), proffered_.end(), sum_sizes);
return size;
}
/**
* @brief Accessor for bins_ internal data structure
*
* @return BINS_T raw pointer
*
* @note Used by unit-test test fixture
*/
BINS_T* get_bins() { return &bins_; }
private:
/**
* @brief Store address record in appropriate bin
*
* @param[in] An address record
*/
void emplace_record_in_bin(AR_T record) {
auto record_size{record.get_size()};
auto bins_it = bins_.find(record_size);
assert(bins_it != bins_.end());
auto& [IGNORE_BIN_SIZE, bin]{*bins_it};
bin.put(record);
}
/**
* @brief Retrieve address record from bin within a BINS_IT_T
*
* @param[in] a VALID FORWARD iterator containing a bin
*
* @return An address record
*
* @note May return an empty record indicating a retrieval failure.
* The failure must be resolved somewhere else within the allocation
* framework.
*/
AR_T retrieve_record_from_bin(BINS_IT_T it) {
try_to_ensure_bin_has_records(it);
auto& [IGNORE, bin]{*it};
if (bin.empty()) {
return AR_T{};
}
return bin.get();
}
/**
* @brief Attempt to accommodate a subsequent record request
*
* The bin under iterator may not (or may) contain records when
* this method is invoked. This method tries to make at least one
* record available.
*
* @param[in] a VALID FORWARD iterator containing a bin
*
* @note BINS_T container must be sorted in ascending bin size for
* delegate method "split_larger_bin"
*/
void try_to_ensure_bin_has_records(BINS_IT_T it) {
auto& [IGNORE, bin]{*it};
if (!bin.empty()) {
return;
}
split_larger_bin(it);
}
/**
* @brief Split records in next largest bin
*
* This method tries to create records within this bin by decomposing
* records in other bins (with larger bin sizes).
*
* This method may be called recursively if records are unavailable
* at each step until records are made available to the initial
* bin.
*
* @param[in] a VALID FORWARD iterator containing a bin
*
* @note BINS_T container must be sorted in ascending bin size
*/
void split_larger_bin(BINS_IT_T it) {
assert(it != bins_.end());
auto next{std::next(it)};
if (next == bins_.end()) {
return;
}
auto& [IGNORE_NEXT, next_bin]{*next};
if (next_bin.empty()) {
split_larger_bin(next);
}
if (next_bin.empty()) {
return;
}
auto record{next_bin.get()};
auto [smaller, larger]{record.split()};
auto& [IGNORE, bin]{*it};
bin.put(larger);
bin.put(smaller);
}
/**
* @brief Store record in proffered_ data structure
*
* @param[in] An address record
*/
void emplace_in_proffered(AR_T record) {
assert(record.get_address());
proffered_[record.get_address()] = record;
}
/**
* @brief Retrieve record from proffered_ data structure
*
* @param[in] raw memory pointer
*
* The memory pointer must match a pointer previously
* handed to the user.
*
* @return An address record
*/
AR_T retrieve_from_proffered(char* ptr) {
assert(ptr);
auto prof_it{proffered_.find(ptr)};
assert(prof_it != proffered_.end());
auto [IGNORE_RECORD_ADDR, record]{*prof_it};
proffered_.erase(prof_it);
return record;
}
/**
* @brief Holds a SORTED set of bin objects
*
* The bin objects are sorted by ascending bin sizes. Each bin holds
* address records with matching sizes. The bin sizes increase by
* powers-of-two. There is a minimum bin size set by memory alignment
* constraints.
*/
BINS_T bins_{};
/**
* @brief Initializes the bins_ object
*
* The binner functions as a bins_ builder. The binner access data in
* the heap memory to establish the number of bins and each bin's size.
*
* Additionally, binner_ will assign the heap memory to bins_.
*/
Binner<AR_T, BINS_T> binner_{};
/**
* @brief Tracks all address records handed over to user.
*
* This member is required to track the sizes of memory allocations
* since the user is not required to provide a size_t field back
* through the "free" interface.
*/
PROFFERED_T proffered_{};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_POW2_BINS_HPP_
@@ -0,0 +1,223 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_REMOTE_HEAP_INFO_HPP_
#define LIBRARY_SRC_MEMORY_REMOTE_HEAP_INFO_HPP_
#include <hip/hip_runtime_api.h>
#include <mpi.h>
#include <cassert>
#include <vector>
#include "hip_allocator.hpp"
#include "window_info.hpp"
/**
* @file remote_heap_info.hpp
*
* @brief Contains information about remote processing elements' heaps
*/
namespace rocshmem {
class CommunicatorMPI {
public:
/**
* @brief Default constructor
*/
CommunicatorMPI() = default;
/**
* @brief Primary constructor
*/
CommunicatorMPI(char* heap_base, size_t heap_size) {
int initialized;
MPI_Initialized(&initialized);
if (!initialized) {
int provided;
MPI_Init_thread(nullptr, nullptr, MPI_THREAD_SINGLE, &provided);
}
MPI_Comm_rank(comm_, &my_pe_);
MPI_Comm_size(comm_, &num_pes_);
heap_window_info_ = WindowInfo(comm_, heap_base, heap_size);
}
/**
* @brief Destructor
*/
~CommunicatorMPI() {}
/**
* @brief Returns my processing element ID
*/
int my_pe() { return my_pe_; }
/**
* @brief Returns number of processing elements
*/
int num_pes() { return num_pes_; }
/**
* @brief Performs MPI_Barrier
*/
void barrier() { MPI_Barrier(comm_); }
/**
* @brief Performs MPI_Allgather on recvbuf
*/
void allgather(void* recvbuf) {
MPI_Allgather(MPI_IN_PLACE, sizeof(void*), MPI_CHAR, recvbuf, sizeof(void*),
MPI_CHAR, comm_);
}
/**
* @brief Accessor method for heap_window_info_
*/
WindowInfo* get_window_info() { return &heap_window_info_; }
private:
/**
* @brief Identifier for this processing element
*/
MPI_Comm comm_{MPI_COMM_WORLD};
/**
* @brief Identifier for this processing element
*/
int my_pe_{-1};
/**
* @brief The total number of processing elements
*/
int num_pes_{-1};
/**
* @brief MPI window on the symmetric GPU heap
*/
WindowInfo heap_window_info_{};
};
template <typename COMMUNICATOR_T>
class RemoteHeapInfo {
/**
* @brief Helper type for heap_bases_ member
*/
using HEAP_BASES_T = std::vector<char*, StdAllocatorHIP<char*>>;
public:
/**
* @brief Required for default construction of other objects
*
* @note Not intended for direct usage
*/
RemoteHeapInfo() = default;
/**
* @brief Primary constructor
*
* @param[in] The identifier for this processing element
* @param[in] The total number of processing elements
*/
RemoteHeapInfo(char* heap_ptr, size_t heap_size)
: communicator_{heap_ptr, heap_size} {
heap_bases_.resize(communicator_.num_pes());
for (auto& base : heap_bases_) {
base = nullptr;
}
heap_bases_[communicator_.my_pe()] = heap_ptr;
communicator_.allgather(heap_bases_.data());
device_heap_bases_ = heap_bases_.data();
}
/**
* @brief Invoke barrier on communicator
*/
void barrier() { communicator_.barrier(); }
/**
* @brief Accessor for my processing element identifier
*
* @return My processing element identifier
*/
int my_pe() { return communicator_.my_pe(); }
/**
* @brief Accessor for number of processing elements
*
* @return Number of processing elements
*/
int num_pes() { return communicator_.num_pes(); }
/**
* @brief Accessor method for heap_window_info_
*
* @return Window info for Reverse Offload interface
*/
auto get_window_info() { return communicator_.get_window_info(); }
/**
* @brief Accessor for heap bases
*
* @return Vector containing the addresses of the symmetric heap bases
*/
__host__ const HEAP_BASES_T& get_heap_bases() { return heap_bases_; }
/**
* @brief Accessor for heap bases
*
* @return Vector containing the addresses of the symmetric heap bases
*/
__device__ auto get_heap_bases() { return device_heap_bases_; }
private:
/**
* @brief Communicator implementation
*/
COMMUNICATOR_T communicator_{};
/**
* @brief C-array of symmetric heap base pointers
*
* A vector of char* pointers corresponding to the heap_bases virtual
* address for all processing element that we can communicate with.
*
* @note Used by __host__ code
*/
HEAP_BASES_T heap_bases_{};
/**
* @brief C-array of symmetric heap base pointers
*
* A vector of char* pointers corresponding to the heap_bases virtual
* address for all processing element that we can communicate with.
*
* @note Used by __device__ code
*/
char** device_heap_bases_{nullptr};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_REMOTE_HEAP_INFO_HPP_
@@ -0,0 +1,90 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_SHMEM_ALLOCATOR_STRATEGY_HPP_
#define LIBRARY_SRC_MEMORY_SHMEM_ALLOCATOR_STRATEGY_HPP_
/**
* @file shmem_allocator_strategy.hpp
*
* @brief Strategy design pattern for SHMEM symmetric heap allocator.
*/
namespace rocshmem {
class ShmemAllocatorStrategy {
public:
/**
* @brief Default constructor
*/
ShmemAllocatorStrategy() = default;
/**
* @brief Default destructor
*/
virtual ~ShmemAllocatorStrategy() = default;
/**
* @brief Default copy construction
*/
ShmemAllocatorStrategy(const ShmemAllocatorStrategy& other) = default;
/**
* @brief Disable copy assignment
*/
ShmemAllocatorStrategy& operator=(const ShmemAllocatorStrategy& other) =
default;
/**
* @brief Allocates memory from the symmetric heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
virtual void alloc(char** ptr, size_t request_size) = 0;
/**
* @brief Allocates memory from the symmetric heap
*
* @param[in, out] Address of raw pointer (&pointer_to_char)
* @param[in] Size in bytes of memory allocation
*/
__device__ virtual void alloc(char** ptr, size_t request_size) = 0;
/**
* @brief Frees memory from the symmetric heap
*
* @param[in] Raw pointer to symmetric heap memory
*/
virtual void free(char* ptr) = 0;
/**
* @brief Frees memory from the symmetric heap
*
* @param[in] Raw pointer to symmetric heap memory
*/
__device__ virtual void free(char* ptr) = 0;
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_SHMEM_ALLOCATOR_STRATEGY_HPP_
@@ -0,0 +1,66 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#include "single_heap.hpp"
#include <sstream>
namespace rocshmem {
SingleHeap::SingleHeap() {
if (auto heap_size_cstr = getenv("ROC_SHMEM_HEAP_SIZE")) {
std::stringstream sstream(heap_size_cstr);
size_t heap_size;
sstream >> heap_size;
heap_mem_ = HEAP_T{heap_size};
strat_ = STRAT_T{&heap_mem_};
}
}
void SingleHeap::malloc(void** ptr, size_t size) {
strat_.alloc(reinterpret_cast<char**>(ptr), size);
}
__device__ void SingleHeap::malloc(void** ptr, size_t size) {}
void SingleHeap::free(void* ptr) {
if (!ptr) {
return;
}
strat_.free(reinterpret_cast<char*>(ptr));
}
__device__ void SingleHeap::free(void* ptr) {}
void* SingleHeap::realloc(void* ptr, size_t size) { return nullptr; }
void* SingleHeap::malign(size_t alignment, size_t size) { return nullptr; }
char* SingleHeap::get_base_ptr() { return heap_mem_.get_ptr(); }
size_t SingleHeap::get_size() { return heap_mem_.get_size(); }
size_t SingleHeap::get_used() { return strat_.amount_proffered(); }
size_t SingleHeap::get_avail() { return get_size() - get_used(); }
} // namespace rocshmem
@@ -0,0 +1,162 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_SINGLE_HEAP_HPP_
#define LIBRARY_SRC_MEMORY_SINGLE_HEAP_HPP_
#include "address_record.hpp"
#include "heap_memory.hpp"
#include "heap_type.hpp"
#include "pow2_bins.hpp"
/**
* @file single_heap.hpp
*
* @brief Contains a single heap
*
* The single heap implements local processing element allocations. The
* symmetric heap delegates allocations to this class.
*/
namespace rocshmem {
class SingleHeap {
/**
* @brief Helper type for address records
*/
using AR_T = AddressRecord;
/**
* @brief Helper type for allocation strategy
*/
using STRAT_T = Pow2Bins<AR_T, HEAP_T>;
public:
/**
* @brief Primary constructor
*/
SingleHeap();
/**
* @brief Allocates memory from the heap
*
* @param[in,out] A pointer to memory handle
* @param[in] Size in bytes of memory allocation
*/
void malloc(void** ptr, size_t size);
/**
* @brief Allocates memory from the heap
*
* @param[in,out] A pointer to memory handle
* @param[in] Size in bytes of memory allocation
*
* @note Not implemented
*/
__device__ void malloc(void** ptr, size_t size);
/**
* @brief Frees memory from the heap
*
* @param[in] Raw pointer to heap memory
*/
void free(void* ptr);
/**
* @brief Frees memory from the heap
*
* @param[in] Raw pointer to heap memory
*
* @note Not implemented
*/
__device__ void free(void* ptr);
/**
* @brief
*
* @param[in]
* @param[in]
*
* @return
*/
void* realloc(void* ptr, size_t size);
/**
* @brief
*
* @param[in]
* @param[in]
*
* @return
*/
void* malign(size_t alignment, size_t size);
/**
* @brief Accessor for heap base ptr
*
* @return Pointer to base of my heap
*/
char* get_base_ptr();
/**
* @brief Accessor for heap size
*
* @return Amount of bytes in heap
*/
size_t get_size();
/**
* @brief Accessor for heap usage
*
* @return Amount of used bytes in heap
*/
size_t get_used();
/**
* @brief Accessor for heap available
*
* @return Amount of available bytes in heap
*/
size_t get_avail();
/**
* @brief Returns is the heap is allocated with managed memory
*
* @return bool
*/
bool is_managed() { return heap_mem_.is_managed(); }
private:
/**
* @brief Heap memory object
*/
HEAP_T heap_mem_{};
/**
* @brief Allocation strategy object
*/
STRAT_T strat_{&heap_mem_};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_SINGLE_HEAP_HPP_
@@ -0,0 +1,113 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#include "slab_heap.hpp"
#include <sstream>
#include "../util.hpp"
namespace rocshmem {
SlabHeap::SlabHeap() {
if (auto slab_size_cstr = getenv("ROC_SHMEM_SLAB_SIZE")) {
std::stringstream sstream(slab_size_cstr);
size_t slab_size;
sstream >> slab_size;
heap_mem_ = HEAP_T{slab_size};
strat_ = STRAT_T{&heap_mem_};
}
}
void SlabHeap::malloc(void** ptr, size_t size) {
strat_.alloc(reinterpret_cast<char**>(ptr), size);
}
__device__ void SlabHeap::malloc(void** ptr, size_t size) {
/*
* Grab the mutex from the proxy object which owns it.
*/
auto mutex{mutex_.get()};
/*
* Take the ticketed lock.
*
* The lock is held jointly by all threads in the block.
*/
auto ticket{mutex->lock()};
/*
* Perform allocation and verify it worked.
*
* Allocation should only be run by only one thread in the
* strategy code.
*/
char** ptr_c{reinterpret_cast<char**>(ptr)};
strat_.alloc(ptr_c, size);
__threadfence();
/*
* The notifier works with uint64_t for the address broadcasts
* between threads (as type erasure for the pointer arithmetic).
*/
uint64_t ptr_deref_u64{reinterpret_cast<uint64_t>(*ptr)};
/*
* Notify other threads in block about the allocation result.
*/
auto notifier{notifier_.get()};
notifier->write(ptr_deref_u64);
uint64_t notification_u64{notifier->read()};
notifier->done();
/*
* Write to the ptr parameter (to return it back up the call stack).
*/
char* read_value_c{reinterpret_cast<char*>(notification_u64)};
*ptr_c = read_value_c;
/*
* Release the lock with our ticket number.
*/
mutex->unlock(ticket);
}
__host__ __device__ void SlabHeap::free(void* ptr) {
if (!ptr) {
return;
}
strat_.free(reinterpret_cast<char*>(ptr));
}
void* SlabHeap::realloc(void* ptr, size_t size) { return nullptr; }
void* SlabHeap::malign(size_t alignment, size_t size) { return nullptr; }
char* SlabHeap::get_base_ptr() { return heap_mem_.get_ptr(); }
size_t SlabHeap::get_size() { return heap_mem_.get_size(); }
size_t SlabHeap::get_used() { return strat_.current() - get_base_ptr(); }
size_t SlabHeap::get_avail() { return get_size() - get_used(); }
} // namespace rocshmem
@@ -0,0 +1,185 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_SLAB_HEAP_HPP_
#define LIBRARY_SRC_MEMORY_SLAB_HEAP_HPP_
#include "dev_mono_linear.hpp"
#include "heap_memory.hpp"
#include "heap_type.hpp"
#include "notifier.hpp"
#include "../sync/abql_block_mutex.hpp"
/**
* @file slab_heap.hpp
*
* @brief Contains a heap used to allocate library objects
*
* The slab heap is used internally by the library
*/
namespace rocshmem {
class SlabHeap {
/**
* @brief Helper type for allocation strategy
*/
using STRAT_T = DevMonoLinear<HEAP_T>;
/**
* @brief Helper type for notifier
*/
using NOTIFIER_PROXY_T = NotifierProxy<HIPAllocator>;
/**
* @brief Helper type for notifier
*/
using MUTEX_PROXY_T = ABQLBlockMutexProxy<HIPAllocator>;
public:
/**
* @brief Primary constructor
*/
SlabHeap();
/**
* @brief Allocates memory from the heap
*
* @param[in,out] A pointer to memory handle
* @param[in] Size in bytes of memory allocation
*/
void malloc(void** ptr, size_t size);
/**
* @brief Allocates memory from the heap
*
* @param[in,out] A pointer to memory handle
* @param[in] Size in bytes of memory allocation
*/
__device__ void malloc(void** ptr, size_t size);
/**
* @brief Frees memory from the heap
*
* @param[in] Raw pointer to heap memory
*/
__host__ __device__ void free(void* ptr);
/**
* @brief
*
* @param[in]
* @param[in]
*
* @return
*/
void* realloc(void* ptr, size_t size);
/**
* @brief
*
* @param[in]
* @param[in]
*
* @return
*/
void* malign(size_t alignment, size_t size);
/**
* @brief Accessor for heap base ptr
*
* @return Pointer to base of my heap
*/
char* get_base_ptr();
/**
* @brief Accessor for heap size
*
* @return Amount of bytes in heap
*/
size_t get_size();
/**
* @brief Accessor for heap usage
*
* @return Amount of used bytes in heap
*/
size_t get_used();
/**
* @brief Accessor for heap available
*
* @return Amount of available bytes in heap
*/
size_t get_avail();
private:
/**
* @brief Heap memory object
*/
HEAP_T heap_mem_{};
/**
* @brief Allocation strategy object
*/
STRAT_T strat_{&heap_mem_};
/**
* @brief Notifier proxy to share information between threads.
*
* Need this object to share allocation information between the
* leader thread (that does allocation) and the follower threads
* (who need the allocation address).
*/
NOTIFIER_PROXY_T notifier_{};
/**
* @brief Mutex to access the heap mutator methods.
*/
MUTEX_PROXY_T mutex_;
};
template <typename ALLOCATOR>
class SlabHeapProxy {
using ProxyT = DeviceProxy<ALLOCATOR, SlabHeap, 1>;
public:
/*
* Placement new the memory which is allocated by proxy_
*/
SlabHeapProxy() { new (proxy_.get()) SlabHeap(); }
/*
* Since placement new is called in the constructor, then
* delete must be called manually.
*/
~SlabHeapProxy() { proxy_.get()->~SlabHeap(); }
__host__ __device__ SlabHeap* get() { return proxy_.get(); }
private:
ProxyT proxy_{};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_SLAB_HEAP_HPP_
@@ -0,0 +1,129 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_SYMMETRIC_HEAP_HPP_
#define LIBRARY_SRC_MEMORY_SYMMETRIC_HEAP_HPP_
/**
* @file symmetric_heap.hpp
*
* @brief Contains a symmetric heap
*
* Every processing element allocates a symmetric heap. (For details on
* the symmetric heap, refer to the OpenSHMEM specification.)
*
* The symmetric heap is allocated using fine-grained memory to allow
* both host access and device access to the memory space.
*
* The symmetric heaps are visible to network by registering them as
* InfiniBand memory regions. Every memory region has a remote key
* which needs to be shared across the network (to access the memory
* region).
*/
#include <hip/hip_runtime_api.h>
#include "remote_heap_info.hpp"
#include "single_heap.hpp"
namespace rocshmem {
class SymmetricHeap {
/**
* @brief Helper type for RemoteHeapInfo with MPI
*/
using RemoteHeapInfoType = RemoteHeapInfo<CommunicatorMPI>;
public:
/**
* @brief Allocates heap memory and returns ptr to caller
*
* @param[in,out] A pointer to memory handle
* @param[in] Number of bytes of requested
*/
void malloc(void** ptr, size_t size) { single_heap_.malloc(ptr, size); }
/**
* @brief Frees previously allocated network visible memory
*
* @param[in] Handle of previously allocated memory
*/
void free(void* ptr) { single_heap_.free(ptr); }
/**
* @brief Accessor for local heap base
*
* @return Base address of the local symmetric heap
*/
__host__ char* get_local_heap_base() { return single_heap_.get_base_ptr(); }
/**
* @brief Accessor method for heap size
*/
auto get_size() { return single_heap_.get_size(); }
/**
* @brief Accessor method for heap_window_info_
*/
auto get_window_info() { return remote_heap_info_.get_window_info(); }
/**
* @brief Accessor for heap bases
*
* @return Vector containing the addresses of the symmetric heap bases
*/
__host__ const auto& get_heap_bases() {
return remote_heap_info_.get_heap_bases();
}
/**
* @brief Accessor for heap bases
*
* @return Vector containing the addresses of the symmetric heap bases
*/
__device__ auto get_heap_bases() {
return remote_heap_info_.get_heap_bases();
}
/**
* @brief Returns is the heap is allocated with managed memory
*
* @return bool
*/
bool is_managed() { return single_heap_.is_managed(); }
private:
/**
* @brief Processing element's implementation of heap
*/
SingleHeap single_heap_{};
/**
* @brief Implementation of remote heaps
*/
RemoteHeapInfoType remote_heap_info_{single_heap_.get_base_ptr(),
single_heap_.get_size()};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_SYMMETRIC_HEAP_HPP_
@@ -0,0 +1,194 @@
/******************************************************************************
* Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*****************************************************************************/
#ifndef LIBRARY_SRC_MEMORY_WINDOW_INFO_HPP_
#define LIBRARY_SRC_MEMORY_WINDOW_INFO_HPP_
#include <mpi.h>
#include <cassert>
#include <memory>
/**
* @file window_info.hpp
*
* @brief Contains information about symmetric heaps' windows
*/
namespace rocshmem {
class WindowInfo {
public:
/**
* @brief Default constructor
*/
WindowInfo() = default;
/**
* @brief Primary constructor
*/
WindowInfo(MPI_Comm comm, void* start, size_t size)
: comm_{comm},
win_start_{start},
win_end_{reinterpret_cast<char*>(start) + size} {
up_win_ = std::unique_ptr<MPI_Win>(new MPI_Win);
MPI_Win_create(win_start_, size, 1, MPI_INFO_NULL, comm_, up_win_.get());
MPI_Win_lock_all(MPI_MODE_NOCHECK, *up_win_.get());
}
/**
* @brief Destructor
*/
~WindowInfo() {
if (up_win_) {
MPI_Win_unlock_all(*up_win_.get());
MPI_Win_free(up_win_.get());
}
}
/**
* @brief Copy constructor
*
* @note Disabled due to up_win_
*/
WindowInfo(WindowInfo& other) = delete; // NOLINT
/**
* @brief Const copy constructor
*
* @note Disabled due to up_win_
*/
WindowInfo(const WindowInfo& other) = delete;
/**
* @brief Copy assignment
*
* @note Disabled due to up_win_
*/
WindowInfo& operator=(WindowInfo other) = delete;
/**
* @brief Move constructor
*/
WindowInfo(WindowInfo&& other) = default;
/**
* @brief Move assignment
*/
WindowInfo& operator=(WindowInfo&& other) = default;
/**
* @brief Accessor for object in up_win_
*
* @return MPI_Win object
*/
MPI_Win get_win() const { return *up_win_.get(); }
/**
* @brief Accessor for win_start_
*
* @return Raw start pointer
*/
void* get_start() const { return win_start_; }
/**
* @brief Accessor for win_end_
*
* @return Raw end pointer
*/
void* get_end() const { return win_end_; }
/**
* @brief Setter for object in up_win_
*
* @param[in] An MPI Window object
*/
void set_win(MPI_Win win) { *up_win_.get() = win; }
/**
* @brief Setter for win_start_
*
* @param[in] Start raw pointer
*/
void set_start(void* start) { win_start_ = start; }
/**
* @brief Setter for win_end_
*
* @param[in] End raw pointer
*/
void set_end(void* end) { win_end_ = end; }
/**
* @brief Get offset between address and start of window
*
* @param[in] Address in raw pointer format
*
* @return Difference between dest and window start
*/
MPI_Aint get_offset(const void* dest) {
assert(reinterpret_cast<char*>(const_cast<void*>(dest)) >=
reinterpret_cast<char*>(win_start_));
assert(reinterpret_cast<char*>(const_cast<void*>(dest)) >=
reinterpret_cast<char*>(win_start_));
assert(reinterpret_cast<char*>(const_cast<void*>(dest)) <
reinterpret_cast<char*>(win_end_));
MPI_Aint dest_disp;
MPI_Get_address(dest, &dest_disp);
MPI_Aint start_disp;
MPI_Get_address(win_start_, &start_disp);
return MPI_Aint_diff(dest_disp, start_disp);
}
private:
/**
* @brief MPI Communicator
*/
MPI_Comm comm_{MPI_COMM_WORLD};
/**
* @brief Owning pointer to MPI_Win
*
* The pointer is used to track which object is responsible for
* releasing window resources during class destruction.
*
* This becomes an issue if objects of this class are move constructed
* or move assigned.
*/
std::unique_ptr<MPI_Win> up_win_{nullptr};
/**
* @brief Raw pointer marking the start of window
*/
void* win_start_{nullptr};
/**
* @brief Raw pointer marking the end of window
*/
void* win_end_{nullptr};
};
} // namespace rocshmem
#endif // LIBRARY_SRC_MEMORY_WINDOW_INFO_HPP_