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 ----------------------*/
/*--------------------------------------------------------------------------*/