The Gaudi Framework  master (594c33fa)
Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator > Class Template Reference

A fast memory arena that does not track deallocations. More...

#include </builds/gaudi/Gaudi/GaudiKernel/include/Gaudi/Arena/Monotonic.h>

Collaboration diagram for Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >:

Public Member Functions

 Monotonic (std::size_t next_block_size) noexcept
 Construct an arena whose first block have approximately the given size. More...
 
 ~Monotonic () noexcept
 
 Monotonic (Monotonic &&)=delete
 
 Monotonic (Monotonic const &)=delete
 
Monotonicoperator= (Monotonic &&)=delete
 
Monotonicoperator= (Monotonic const &)=delete
 
template<std::size_t ReqAlign>
std::byte * allocate (std::size_t n)
 Return an aligned point to n bytes of memory. More...
 
constexpr void deallocate (std::byte *, std::size_t) noexcept
 Deallocations are not tracked, so this is a no-op! More...
 
void reset () noexcept
 Signal that this arena may start re-using the memory resources. More...
 
std::size_t capacity () const noexcept
 Query how much memory is owned by this arena, in bytes. More...
 
std::size_t size () const noexcept
 Query how much memory was used from this arena, in bytes. More...
 
std::size_t num_blocks () const noexcept
 Query how many blocks of memory this arena owns. More...
 
std::size_t num_allocations () const noexcept
 Query how many allocations this arena has served. More...
 

Static Public Attributes

static constexpr std::size_t alignment = Alignment
 

Private Attributes

std::size_t m_next_block_size {}
 Size (in bytes) of the next block to be allocated. More...
 
std::size_t m_allocations { 0 }
 Number of allocation requests served by this arena. More...
 
std::byte * m_current { nullptr }
 Current position in the current block, or nullptr if there is no current block. More...
 
std::byte * m_current_end { nullptr }
 One byte past the end of the current block, or nullptr if it doesn't exist. More...
 
boost::container::small_vector< gsl::span< std::byte >, 1 > m_all_blocks
 All memory blocks owned by this arena. More...
 

Static Private Attributes

static constexpr std::size_t growth_factor = 2
 Approximate factor by which each block is larger than its predecessor. More...
 

Detailed Description

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
class Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >

A fast memory arena that does not track deallocations.

This is a memory arena suitable for use with Gaudi::Allocators::Arena. It allocates memory from an upstream resource in blocks of geometrically increasing size and serves allocation requests from those blocks. Deallocations are not tracked, so the memory footprint of a Monotonic arena increases monotonically until either it is destroyed or its reset() method is called. All requests are served with alignment specified in the template parameter.

Todo:

Efficiently support stateful upstream allocators, probably by putting an instance of the upstream allocator in a boost::compressed_pair.

Use the given UpstreamAllocator to serve dynamic allocations required by boost::container::small_vector.

Definition at line 46 of file Monotonic.h.

Constructor & Destructor Documentation

◆ Monotonic() [1/3]

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::Monotonic ( std::size_t  next_block_size)
inlinenoexcept

Construct an arena whose first block have approximately the given size.

This constructor does not trigger any allocation.

Definition at line 74 of file Monotonic.h.

75  : m_next_block_size{ details::align_up<Alignment>( next_block_size ) } {}

◆ ~Monotonic()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::~Monotonic ( )
inlinenoexcept

Definition at line 77 of file Monotonic.h.

77  {
78  for ( auto block : m_all_blocks ) { UpstreamAllocator{}.deallocate( block.data(), block.size() ); }
79  }

◆ Monotonic() [2/3]

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::Monotonic ( Monotonic< Alignment, UpstreamAllocator > &&  )
delete

◆ Monotonic() [3/3]

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::Monotonic ( Monotonic< Alignment, UpstreamAllocator > const &  )
delete

Member Function Documentation

◆ allocate()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
template<std::size_t ReqAlign>
std::byte* Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::allocate ( std::size_t  n)
inline

Return an aligned point to n bytes of memory.

This may trigger allocation from the upstream resource.

Definition at line 92 of file Monotonic.h.

92  {
93  // If the requested alignment was larger we would need to round up
94  // m_current -- instead of implementing that, just assert it's not
95  // the case.
96  static_assert( ReqAlign <= alignment, "Requested alignment too large for this Gaudi::Arena::Monotonic!" );
97  // Figure out how many bytes we need to allocate
98  std::size_t const aligned_n = details::align_up<Alignment>( n );
99  // Check that we have a current block and this request fits inside it
100  if ( !m_current || m_current + aligned_n > m_current_end ) {
101  // Calculate our next block size
102  auto next_block_size = std::max( m_next_block_size, aligned_n );
103  // And update the estimate of what comes after that, following a geometric series
104  m_next_block_size = details::align_up<Alignment>( growth_factor * next_block_size );
105  // Allocate the new block and mark it as the current one
106  m_current = UpstreamAllocator{}.allocate( next_block_size );
107  m_current_end = m_current + next_block_size;
108  // Add it to the list of blocks that we'll eventually deallocate
109  m_all_blocks.emplace_back( m_current, next_block_size );
110  }
111  m_allocations++;
112  return std::exchange( m_current, m_current + aligned_n );
113  }

◆ capacity()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::capacity ( ) const
inlinenoexcept

Query how much memory is owned by this arena, in bytes.

Definition at line 145 of file Monotonic.h.

145  {
146  return std::accumulate( m_all_blocks.begin(), m_all_blocks.end(), 0ul,
147  []( std::size_t sum, auto block ) { return sum + block.size(); } );
148  }

◆ deallocate()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
constexpr void Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::deallocate ( std::byte *  ,
std::size_t   
)
inlineconstexprnoexcept

Deallocations are not tracked, so this is a no-op!

Definition at line 117 of file Monotonic.h.

117 {}

◆ num_allocations()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::num_allocations ( ) const
inlinenoexcept

Query how many allocations this arena has served.

Definition at line 160 of file Monotonic.h.

160 { return m_allocations; }

◆ num_blocks()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::num_blocks ( ) const
inlinenoexcept

Query how many blocks of memory this arena owns.

Definition at line 156 of file Monotonic.h.

156 { return m_all_blocks.size(); }

◆ operator=() [1/2]

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Monotonic& Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::operator= ( Monotonic< Alignment, UpstreamAllocator > &&  )
delete

◆ operator=() [2/2]

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
Monotonic& Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::operator= ( Monotonic< Alignment, UpstreamAllocator > const &  )
delete

◆ reset()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
void Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::reset ( )
inlinenoexcept

Signal that this arena may start re-using the memory resources.

  • If the arena owns zero blocks, there is no change.
  • If the arena owns one block, it will reset to serving future requests from the start of that block.
  • If the arena owns more than one block, it will deallocate all but the first one and serve future requests from the start of the remaining block.

Definition at line 126 of file Monotonic.h.

126  {
127  m_allocations = 0;
128  if ( !m_all_blocks.empty() ) {
129  // Only re-use the first block, deallocate any others
130  if ( m_all_blocks.size() > 1 ) {
131  for ( std::size_t i = 1; i < m_all_blocks.size(); ++i ) {
132  UpstreamAllocator{}.deallocate( m_all_blocks[i].data(), m_all_blocks[i].size() );
133  }
134  m_all_blocks.resize( 1 );
135  }
136  auto reused_block = m_all_blocks.front();
137  m_current = reused_block.data();
138  m_current_end = m_current + reused_block.size();
139  m_next_block_size = details::align_up<Alignment>( growth_factor * reused_block.size() );
140  }
141  }

◆ size()

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::size ( ) const
inlinenoexcept

Query how much memory was used from this arena, in bytes.

Definition at line 152 of file Monotonic.h.

152 { return capacity() - ( m_current_end - m_current ); }

Member Data Documentation

◆ alignment

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
constexpr std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::alignment = Alignment
staticconstexpr

Definition at line 69 of file Monotonic.h.

◆ growth_factor

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
constexpr std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::growth_factor = 2
staticconstexprprivate

Approximate factor by which each block is larger than its predecessor.

Definition at line 66 of file Monotonic.h.

◆ m_all_blocks

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
boost::container::small_vector<gsl::span<std::byte>, 1> Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::m_all_blocks
private

All memory blocks owned by this arena.

Definition at line 63 of file Monotonic.h.

◆ m_allocations

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::m_allocations { 0 }
private

Number of allocation requests served by this arena.

Definition at line 54 of file Monotonic.h.

◆ m_current

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::byte* Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::m_current { nullptr }
private

Current position in the current block, or nullptr if there is no current block.

Definition at line 57 of file Monotonic.h.

◆ m_current_end

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::byte* Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::m_current_end { nullptr }
private

One byte past the end of the current block, or nullptr if it doesn't exist.

Definition at line 60 of file Monotonic.h.

◆ m_next_block_size

template<std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
std::size_t Gaudi::Arena::Monotonic< Alignment, UpstreamAllocator >::m_next_block_size {}
private

Size (in bytes) of the next block to be allocated.

Definition at line 51 of file Monotonic.h.


The documentation for this class was generated from the following file:
Gaudi::Arena::Monotonic::capacity
std::size_t capacity() const noexcept
Query how much memory is owned by this arena, in bytes.
Definition: Monotonic.h:145
Gaudi::Arena::Monotonic::m_current_end
std::byte * m_current_end
One byte past the end of the current block, or nullptr if it doesn't exist.
Definition: Monotonic.h:60
Gaudi::Arena::Monotonic::m_next_block_size
std::size_t m_next_block_size
Size (in bytes) of the next block to be allocated.
Definition: Monotonic.h:51
Gaudi::Arena::Monotonic::growth_factor
static constexpr std::size_t growth_factor
Approximate factor by which each block is larger than its predecessor.
Definition: Monotonic.h:66
std::accumulate
T accumulate(T... args)
Gaudi::Arena::Monotonic::m_all_blocks
boost::container::small_vector< gsl::span< std::byte >, 1 > m_all_blocks
All memory blocks owned by this arena.
Definition: Monotonic.h:63
GaudiPluginService.cpluginsvc.n
n
Definition: cpluginsvc.py:234
Gaudi::Arena::Monotonic::size
std::size_t size() const noexcept
Query how much memory was used from this arena, in bytes.
Definition: Monotonic.h:152
std::size_t
Gaudi::Arena::Monotonic::alignment
static constexpr std::size_t alignment
Definition: Monotonic.h:69
Gaudi::Arena::Monotonic::m_allocations
std::size_t m_allocations
Number of allocation requests served by this arena.
Definition: Monotonic.h:54
std::max
T max(T... args)
Gaudi::Arena::Monotonic::m_current
std::byte * m_current
Current position in the current block, or nullptr if there is no current block.
Definition: Monotonic.h:57