Program Listing for File HugePageAllocator.h

↰ Return to documentation for file (ADS/memory/HugePageAllocator.h)

/*--------------------------------------------------------------------------*/
/*------------------------ File HugePageAllocator.h ------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*----------------------------- DEFINITIONS --------------------------------*/
/*--------------------------------------------------------------------------*/

#ifndef __ADS_HugePageAllocator
 #define __ADS_HugePageAllocator
                      /* self-identification: #endif constant */

/*--------------------------------------------------------------------------*/
/*------------------------------ INCLUDES ----------------------------------*/
/*--------------------------------------------------------------------------*/

#include <cstddef>
#include <limits>
#include <memory>
#include <new>

#if defined( __linux__ ) && __has_include( <sys/mman.h> )
 #include <sys/mman.h>
#endif

/*--------------------------------------------------------------------------*/
/*--------------------------- NAMESPACE ------------------------------------*/
/*--------------------------------------------------------------------------*/

namespace ADS {

namespace detail {

struct HugeCache {
 static constexpr int N = 16;
 static constexpr std::size_t BYTES = std::size_t( 64 ) << 20;
 static constexpr std::size_t LEAST = std::size_t( 8 ) << 20;

 void * p[ N ];
 std::size_t r[ N ];
 int n = 0;
 std::size_t bytes = 0;

 void * take( std::size_t s ) {
  for( int i = n ; i-- > 0 ; )
   if( r[ i ] == s ) {
    void * q = p[ i ];
    bytes -= s;
    p[ i ] = p[ --n ];
    r[ i ] = r[ n ];
    return( q );
    }
  return( nullptr );
  }

 bool keep( void * q , std::size_t s ) {
  if( ( s < LEAST ) || ( n == N ) || ( bytes + s > BYTES ) )
   return( false );
  p[ n ] = q;
  r[ n++ ] = s;
  bytes += s;
  return( true );
  }

 ~HugeCache();
 };

inline bool & hugeCacheGone( void )
{
 thread_local bool gone = false;           // no destructor: always there
 return( gone );
 }

inline HugeCache::~HugeCache()
{
 hugeCacheGone() = true;
 while( n > 0 ) {
  --n;
  ::operator delete( p[ n ] , std::align_val_t( std::size_t( 1 ) << 21 ) );
  }
 }

inline HugeCache & hugeCache( void )
{
 thread_local HugeCache c;
 return( c );
 }

}  // end( namespace detail )

/*--------------------------------------------------------------------------*/
/*----------------------- CLASS HugePageAllocator --------------------------*/
/*--------------------------------------------------------------------------*/

template< class T >
class HugePageAllocator {

/*--------------------------------------------------------------------------*/
 public:

 using value_type = T;

 static constexpr std::size_t PAGE = std::size_t( 1 ) << 21;

 HugePageAllocator( void ) = default;

 template< class U >
 HugePageAllocator( const HugePageAllocator< U > & ) noexcept {}

 [[nodiscard]] T * allocate( std::size_t n ) {
  if( n > ( std::numeric_limits< std::size_t >::max() - PAGE ) /
          sizeof( T ) )
   throw std::bad_array_new_length();
  const std::size_t b = n * sizeof( T );
  if( b < PAGE )
   return( std::allocator< T >().allocate( n ) );
  const std::size_t r = ( b + PAGE - 1 ) & ~( PAGE - 1 );
  if( ! detail::hugeCacheGone() )           // a block kept
   if( void * q = detail::hugeCache().take( r ) )
    return( static_cast< T * >( q ) );
  void * p = ::operator new( r , std::align_val_t( PAGE ) );
#if defined( MADV_HUGEPAGE )
  madvise( p , r , MADV_HUGEPAGE );
#endif
  return( static_cast< T * >( p ) );
  }

 void deallocate( T * p , std::size_t n ) noexcept {
  const std::size_t b = n * sizeof( T );
  if( b < PAGE )
   std::allocator< T >().deallocate( p , n );
  else if( detail::hugeCacheGone() ||
           ! detail::hugeCache().keep( p ,
                                       ( b + PAGE - 1 ) & ~( PAGE - 1 ) ) )
   ::operator delete( p , std::align_val_t( PAGE ) );
  }

 template< class U >
 bool operator==( const HugePageAllocator< U > & ) const noexcept {
  return( true );
  }

 };  // end( class HugePageAllocator )

/*--------------------------------------------------------------------------*/

}  // end( namespace ADS )

/*--------------------------------------------------------------------------*/

#endif  /* HugePageAllocator.h included */

/*--------------------------------------------------------------------------*/
/*---------------------- End File HugePageAllocator.h ----------------------*/
/*--------------------------------------------------------------------------*/