Program Listing for File QuickPool.hpp

Return to documentation for file (umpire/strategy/QuickPool.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_PoolMap_HPP
#define UMPIRE_PoolMap_HPP

#include "umpire/strategy/AllocationStrategy.hpp"
#include "umpire/util/MemoryMap.hpp"

#include <functional>
#include <map>
#include <tuple>
#include <unordered_map>

namespace umpire {

class Allocator;

namespace util {

class FixedMallocPool;

}

namespace strategy {

class QuickPool :
  public AllocationStrategy
{
  public:
    using Pointer = void*;
    using CoalesceHeuristic = std::function<bool (const strategy::QuickPool& )>;

    static CoalesceHeuristic percent_releasable(int percentage);

    QuickPool(
        const std::string& name,
        int id,
        Allocator allocator,
        const std::size_t initial_alloc_size = (512 * 1024 * 1024),
        const std::size_t min_alloc_size = (1 * 1024 * 1024),
        CoalesceHeuristic coalesce_heuristic = percent_releasable(100)) noexcept;

    ~QuickPool();

    QuickPool(const QuickPool&) = delete;

    void* allocate(std::size_t bytes) override;
    void deallocate(void* ptr) override;
    void release() override;

    std::size_t getCurrentSize() const noexcept override;
    std::size_t getActualSize() const noexcept override;
    std::size_t getHighWatermark() const noexcept override;
    std::size_t getReleasableSize() const noexcept;

    Platform getPlatform() noexcept override;

    void coalesce() noexcept;

  private:
    struct Chunk;

    template <typename Value>
    class pool_allocator {
      public:
        using value_type = Value;
        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;

        pool_allocator() :
          pool{new util::FixedMallocPool{sizeof(Value)}} {}

        /// BUG: Only required for MSVC
        template<typename U>
        pool_allocator(const pool_allocator<U>& other):
          pool{other.pool}
        {}

        Value* allocate(std::size_t n) {
          return static_cast<Value*>(pool->allocate(n));
        }

        void deallocate(Value* data, std::size_t)
        {
          pool->deallocate(data);
        }

      util::FixedMallocPool* pool;
    };

    using PointerMap = std::unordered_map<void*, Chunk*>;
    using SizeMap = std::multimap<std::size_t, Chunk*, std::less<std::size_t>, pool_allocator<std::pair<const std::size_t, Chunk*>>>;

    struct Chunk {
      Chunk(void* ptr, std::size_t s, std::size_t cs) :
        data{ptr}, size{s}, chunk_size{cs} {}

      void* data{nullptr};
      std::size_t size{0};
      std::size_t chunk_size{0};
      bool free{true};
      Chunk* prev{nullptr};
      Chunk* next{nullptr};
      SizeMap::iterator size_map_it;
    };

    PointerMap m_pointer_map;
    SizeMap m_size_map;

    util::FixedMallocPool m_chunk_pool;

    strategy::AllocationStrategy* m_allocator;

    CoalesceHeuristic m_should_coalesce;

    const std::size_t m_initial_alloc_bytes;
    const std::size_t m_min_alloc_bytes;

    std::size_t m_curr_bytes{0};
    std::size_t m_actual_bytes{0};
    std::size_t m_highwatermark{0};
    std::size_t m_releasable_bytes{0};
};

} // end of namespace strategy
} // end namespace umpire

#endif // UMPIRE_Pool_HPP