Program Listing for File ResourceManager.hpp

Return to documentation for file (umpire/ResourceManager.hpp)

//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-20, Lawrence Livermore National Security, LLC and Umpire
// project contributors. See the COPYRIGHT file for details.
//
// SPDX-License-Identifier: (MIT)
//////////////////////////////////////////////////////////////////////////////
#ifndef UMPIRE_ResourceManager_HPP
#define UMPIRE_ResourceManager_HPP

#include <vector>
#include <string>
#include <memory>
#include <mutex>
#include <list>
#include <unordered_map>

#include "umpire/Allocator.hpp"
#include "umpire/strategy/AllocationStrategy.hpp"
#include "umpire/util/AllocationMap.hpp"

#include "umpire/resource/MemoryResourceTypes.hpp"

namespace umpire {

namespace op {
  class MemoryOperation;
}

namespace strategy {
  class ZeroByteHandler;
}

/*!
 * \brief
 */
class ResourceManager {
  public:
    /*!
     * \brief
     */
    static ResourceManager& getInstance();

    /*!
     * \brief Initialize the ResourceManager.
     *
     * This will create all registered MemoryResource objects
     */
    void initialize();

    /*!
     * \brief Get the names of all available Allocator objects.
     */
    std::vector<std::string> getAllocatorNames() const noexcept;

    /*!
     * \brief Get the ids of all available Allocator objects.
     */
    std::vector<int> getAllocatorIds() const noexcept;

    /*!
     * \brief Get the Allocator with the given name.
     */
    Allocator getAllocator(const std::string& name);

    Allocator getAllocator(const char* name);

    /*!
     * \brief Get the default Allocator for the given resource_type.
     */
    Allocator getAllocator(resource::MemoryResourceType resource_type);

    /*!
     * \brief Get the Allocator with the given ID.
     */
    Allocator getAllocator(int id);

    /*!
     * \brief Get the default Allocator.
     *
     * The default Allocator is used whenever an Allocator is required and one
     * is not provided, or cannot be inferred.
     *
     * \return The default Allocator.
     */
    Allocator getDefaultAllocator();

    /*!
     * \brief Set the default Allocator.
     *
     * The default Allocator is used whenever an Allocator is required and one
     * is not provided, or cannot be inferred.
     *
     * \param allocator The Allocator to use as the default.
     */
    void setDefaultAllocator(Allocator allocator) noexcept;

    /*!
     * \brief Construct a new Allocator.
     */
    template <typename Strategy,
             bool introspection=true,
             typename... Args>
    Allocator makeAllocator(const std::string& name, Args&&... args);

    /*!
     * \brief Register an Allocator with the ResourceManager.
     *
     * After registration, the Allocator can be retrieved by calling
     * getAllocator(name).
     *
     * The same Allocator can be registered under multiple names.
     *
     * \param name Name to register Allocator with.
     * \param allocator Allocator to register.
     */
    void registerAllocator(const std::string& name, Allocator allocator);

    /*!
     * \brief Get the Allocator used to allocate ptr.
     *
     * \param ptr Pointer to find the Allocator for.
     * \return Allocator for the given ptr.
     */
    Allocator getAllocator(void* ptr);

    bool isAllocator(const std::string& name) noexcept;

    /*!
     * \brief Does the given pointer have an associated Allocator.
     *
     * \return True if the pointer has an associated Allocator.
     */
    bool hasAllocator(void* ptr);

    /*!
     * \brief register an allocation with the manager.
     */
    void registerAllocation(void* ptr, util::AllocationRecord record);

    /*!
     * \brief de-register the address ptr with the manager.
     *
     * \return the allocation record removed from the manager.
     */
    util::AllocationRecord deregisterAllocation(void* ptr);

    /*!
     * \brief Find the allocation record associated with an address ptr.
     *
     * \return the record if found, or throws an exception if not found.
     */
    const util::AllocationRecord* findAllocationRecord(void* ptr) const;

    /*!
     * \brief Check whether the named Allocator exists.
     *
     */
    bool isAllocatorRegistered(const std::string& name);

    /*!
     * \brief Copy size bytes of data from src_ptr to dst_ptr.
     *
     * Both the src_ptr and dst_ptr addresses must be allocated by Umpire. They
     * can be offset from any Umpire-managed base address.
     *
     * The dst_ptr must be large enough to accommodate size bytes of data.
     *
     * \param dst_ptr Destination pointer.
     * \param src_ptr Source pointer.
     * \param size Size in bytes.
     */
    void copy(void* dst_ptr, void* src_ptr, std::size_t size=0);

    /*!
     * \brief Set the first length bytes of ptr to the value val.
     *
     * \param ptr Pointer to data.
     * \param val Value to set.
     * \param length Number of bytes to set to val.
     */
    void memset(void* ptr, int val, std::size_t length=0);

    /*!
     * \brief Reallocate current_ptr to new_size.
     *
     * \param current_ptr Source pointer to reallocate.
     * \param new_size New size of pointer.
     *
     * If current_ptr is nullptr, then the default allocator will be used to
     * allocate data. The default allocator may be set with a call to
     * setDefaultAllocator(Allocator allocator).
     *
     * NOTE 1: This is not thread safe
     * NOTE 2: If the allocator for which current_ptr is intended is different
     *         from the default allocator, then all subsequent reallocate calls
     *         will result in allocations from the default allocator which may
     *         not be the intended behavior.
     *
     * If new_size is 0, then the current_ptr will be deallocated if it is not
     * a nullptr, and a zero-byte allocation will be returned.
     *
     * \return Reallocated pointer.
     *
     */
    void* reallocate(void* current_ptr, std::size_t new_size);

    /*!
     * \brief Reallocate current_ptr to new_size.
     *
     * \param current_ptr Source pointer to reallocate.
     * \param new_size New size of pointer.
     * \param allocator Allocator to use if current_ptr is null.
     *
     * If current_ptr is null, then allocator will be used to allocate the
     * data.
     *
     * If new_size is 0, then the current_ptr will be deallocated if it is not
     * a nullptr, and a zero-byte allocation will be returned.
     *
     * \return Reallocated pointer.
     *
     */
    void* reallocate(void* current_ptr, std::size_t new_size, Allocator allocator);

    /*!
     * \brief Move src_ptr to memory from allocator
     *
     * \param src_ptr Pointer to move.
     * \param allocator Allocator to use to allocate new memory for moved data.
     *
     * \return Pointer to new location of data.
     */
    void* move(void* src_ptr, Allocator allocator);

    /*!
     * \brief Deallocate any pointer allocated by an Umpire-managed resource.
     *
     * \param ptr Pointer to deallocate.
     */
    void deallocate(void* ptr);

    /*!
     * \brief Get the size in bytes of the allocation for the given pointer.
     *
     * \param ptr Pointer to find size of.
     *
     * \return Size of allocation in bytes.
     */
    std::size_t getSize(void* ptr) const;

    std::shared_ptr<op::MemoryOperation> getOperation(
        const std::string& operation_name,
        Allocator src_allocator,
        Allocator dst_allocator);

    ~ResourceManager();
    ResourceManager (const ResourceManager&) = delete;
    ResourceManager& operator= (const ResourceManager&) = delete;
  private:
    ResourceManager();

    strategy::AllocationStrategy* findAllocatorForPointer(void* ptr);
    strategy::AllocationStrategy* findAllocatorForId(int id);
    strategy::AllocationStrategy* getAllocationStrategy(const std::string& name);

    int getNextId() noexcept;

    std::string getAllocatorInformation() const noexcept;

    strategy::AllocationStrategy* getZeroByteAllocator();

    void* reallocate_impl(void* current_ptr, std::size_t new_size, Allocator allocator);

    util::AllocationMap m_allocations;

    std::list<std::unique_ptr<strategy::AllocationStrategy> > m_allocators;

    std::unordered_map<int, strategy::AllocationStrategy*> m_allocators_by_id;
    std::unordered_map<std::string, strategy::AllocationStrategy* > m_allocators_by_name;
    std::unordered_map<resource::MemoryResourceType, strategy::AllocationStrategy*, resource::MemoryResourceTypeHash > m_memory_resources;

    strategy::AllocationStrategy* m_default_allocator;

    int m_id;

    std::mutex m_mutex;

    // Methods that need access to m_allocations to print/filter records
    friend void print_allocator_records(Allocator, std::ostream&);
    friend std::vector<util::AllocationRecord> get_allocator_records(Allocator);
    friend strategy::ZeroByteHandler;
};

} // end namespace umpire

#include "umpire/ResourceManager.inl"

#endif // UMPIRE_ResourceManager_HPP