/**************************************************
*
* MemMan 3.0.0.0 beta
*
* Copyright (C) 2007 - 2008 by Len3d
* All rights reserved.
*
*************************************************/
#ifndef __MEMMAN__
#define __MEMMAN__
#include <malloc.h>
#include <vector>
#include <algorithm>
#include <iostream>
#pragma pack(push,1)
namespace mem {
#define mem_inline __forceinline
#define mem_pool_pad 16
#define mem_page_pad 48
#define mem_page_size ( 2 << 18 )
#define mem_align_size 16
#define mem_align __declspec( align( mem_align_size ) )
typedef unsigned int prior_type;
typedef unsigned long time_type;
typedef unsigned long size_type;
typedef unsigned char byte;
#define mem_max( a, b ) ( ( (a) > (b) ) ? (a) : (b) )
#define mem_min( a, b ) ( ( (a) < (b) ) ? (a) : (b) )
#define mem_mbyte( a ) ( float(a) * (1.0f / float( 1024 * 1024 )) )
enum {
ENTRY_PRIORITY = 0,
};
extern time_type num_stream_out;
class heap {
public:
mem_inline heap( size_type max_size )
{
allocated_size = 0;
available_size = max_size;
}
mem_inline ~heap()
{
}
mem_inline void *alloc( size_type size )
{
if( size == 0 )
return NULL;
allocated_size += size;
available_size -= size;
return sys_alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
if( ptr && size != 0 )
{
sys_dealloc( ptr );
allocated_size -= size;
available_size += size;
}
}
mem_inline void *aligned_alloc( size_type size )
{
if( size == 0 )
return NULL;
allocated_size += size;
available_size -= size;
return sys_aligned_alloc( size );
}
mem_inline void aligned_dealloc( void *ptr, size_type size )
{
if( ptr && size != 0 )
{
sys_aligned_dealloc( ptr );
allocated_size -= size;
available_size += size;
}
}
mem_inline size_type available() const
{
return available_size;
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== heap Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "allocated size: " << mem_mbyte( allocated_size ) << " MB" << std::endl;
std::cout << "available size: " << mem_mbyte( available_size ) << " MB" << std::endl;
std::cout << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << std::endl;
}
private:
mem_inline void *sys_alloc( size_type size )
{
return malloc( size );
}
mem_inline void sys_dealloc( void *ptr )
{
free( ptr );
}
mem_inline void *sys_aligned_alloc( size_type size )
{
return _aligned_malloc( size, mem_align_size );
}
mem_inline void sys_aligned_dealloc( void *ptr )
{
_aligned_free( ptr );
}
private:
size_type allocated_size,
available_size;
};
template < typename ALLOC >
class pool {
private:
class page {
public:
mem_inline page( size_type _size, page *old )
{
base = get_base();
_next = old;
size = _size;
}
mem_inline byte *get_base()
{
return ( (byte *) this + sizeof(page) );
}
mem_inline size_type get_size()
{
return static_cast<size_type>( base - get_base() + size );
}
mem_inline size_type available() const
{
return size;
}
mem_inline void *alloc( size_type _size )
{
byte *ptr = base;
base += _size;
size -= _size;
return ptr;
}
mem_inline page *next()
{
return _next;
}
private:
mem_align union {
struct {
byte *base;
page *_next;
size_type size;
};
byte pad[mem_pool_pad];
};
};
class chunk {
public:
mem_inline chunk( size_type _size, chunk *old )
{
next = old;
size = _size;
}
mem_inline size_type available() const
{
return size;
}
public:
chunk *next;
size_type size;
};
public:
mem_inline pool()
{
pages = NULL;
chunks = NULL;
allocated = 0;
}
mem_inline ~pool()
{
destory();
}
mem_inline void destory()
{
page *p;
while( ( p = pages ) != NULL )
{
pages = p->next();
al.dealloc( p, p->get_size() );
}
pages = NULL;
chunks = NULL;
}
mem_inline bool search_chunk( void * & ptr, size_type size )
{
if( chunks && ( size <= chunks->available() ) )
{
ptr = (void *) chunks;
chunks = chunks->next;
return true;
}
else
return false;
}
mem_inline bool search_page( void * & ptr, size_type size )
{
if( pages && ( size <= pages->available() ) )
{
ptr = pages->alloc( size );
return true;
}
else
return false;
}
mem_inline void allocate_page( size_type size )
{
size_type asize = mem_max( size, mem_page_size );
pages = new (al.alloc( sizeof(page) + asize )) page( asize, pages );
}
mem_inline void *alloc( size_type size )
{
void *ptr;
++ allocated;
if( search_chunk( ptr, size ) )
return ptr;
else if( search_page( ptr, size ) )
return ptr;
else {
allocate_page( size );
if( search_page( ptr, size ) )
return ptr;
else
return NULL;
}
}
mem_inline void dealloc( void *ptr, size_type size )
{
-- allocated;
if( size >= sizeof(chunk) )
chunks = new (ptr) chunk( size, chunks );
if( allocated == 0 )
destory();
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== pool Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "number of allocations: " << allocated << std::endl;
std::cout << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << std::endl;
}
private:
page *pages;
chunk *chunks;
size_type allocated;
ALLOC al;
};
template < typename ALLOC >
class cache {
public:
class node;
class entry {
public:
mem_inline entry()
{
priority = ENTRY_PRIORITY;
last_use_time = pl.get_current_time();
locked = false;
node_ptr = NULL;
}
mem_inline entry( prior_type prior )
{
priority = prior;
last_use_time = pl.get_current_time();
locked = false;
node_ptr = NULL;
}
mem_inline virtual ~entry()
{
}
mem_inline void *alloc( size_type size )
{
return pl.alloc( size, this );
}
mem_inline void dealloc( void *ptr, size_type size )
{
pl.dealloc( ptr, size, this );
}
mem_inline void stream_begin()
{
locked = true;
stream_in();
last_use_time = pl.get_current_time();
}
mem_inline void stream_end()
{
locked = false;
}
mem_inline bool is_locked()
{
return locked;
}
mem_inline bool operator < ( const entry & right ) const
{
if( priority == right.priority )
return ( last_use_time < right.last_use_time );
else
return ( priority < right.priority );
}
public:
virtual void stream_in() = 0;
virtual size_type stream_size() = 0;
virtual void *stream_out() = 0;
public:
static cache< ALLOC > pl;
prior_type priority;
time_type last_use_time;
bool locked;
node *node_ptr;
};
class node {
public:
mem_inline node( entry *obj, node *old, node *g_old, node *phead, node *g_phead )
{
ptr = obj;
obj->node_ptr = this;
next = old;
prev = phead;
g_next = g_old;
g_prev = g_phead;
if( next )
next->prev = this;
if( prev )
prev->next = this;
if( g_next )
g_next->g_prev = this;
if( g_prev )
g_prev->g_next = this;
}
mem_inline node()
{
ptr = NULL;
next = NULL;
prev = NULL;
g_next = NULL;
g_prev = NULL;
}
mem_inline ~node()
{
void *p = NULL;
stream_out( p );
}
mem_inline time_type get_last_use_time() const
{
if( ptr )
return ptr->last_use_time;
else
return 0;
}
mem_inline bool is_locked() const
{
if( ptr )
return ptr->is_locked();
else
return false;
}
mem_inline size_type stream_size()
{
if( ptr )
return ptr->stream_size();
else
return 0;
}
mem_inline bool stream_out( void * & p )
{
if( ptr )
{
p = ptr->stream_out();
ptr->node_ptr = NULL;
++ num_stream_out;
return true;
}
else
return false;
}
mem_inline void detach()
{
if( prev )
prev->next = next;
if( next )
next->prev = prev;
}
mem_inline void g_detach()
{
if( g_prev )
g_prev->g_next = g_next;
if( g_next )
g_next->g_prev = g_prev;
}
public:
entry *ptr;
node *next, *prev;
node *g_next, *g_prev;
};
class page {
public:
mem_inline page( size_type _size, page *old )
{
size = _size;
base = get_base();
next = old;
prev = NULL;
if( next )
next->prev = this;
num_nodes = 0;
}
mem_inline ~page()
{
node *p = head.next;
while( p )
{
head.next = p->next;
p->g_detach();
p->~node();
node_pool.dealloc( p, sizeof(node) );
p = head.next;
}
}
mem_inline void recycle( page *old )
{
node *p = head.next;
while( p )
{
head.next = p->next;
p->g_detach();
p->~node();
node_pool.dealloc( p, sizeof(node) );
p = head.next;
}
head.next = NULL;
size = get_size();
base = get_base();
next = old;
prev = NULL;
if( next )
next->prev = this;
num_nodes = 0;
}
mem_inline byte *get_base()
{
return (byte *) this + sizeof(page);
}
mem_inline size_type get_size()
{
return static_cast<size_type>( base - get_base() + size );
}
mem_inline size_type available() const
{
return size;
}
mem_inline void *alloc( size_type req_size )
{
void *ptr = (void *) base;
base += req_size;
size -= req_size;
return ptr;
}
mem_inline time_type priority() const
{
time_type last_use_time = 0;
node *p = head.next;
while( p )
{
last_use_time += p->get_last_use_time();
p = p->next;
}
if( num_nodes != 0 )
last_use_time /= static_cast<time_type>( num_nodes );
return last_use_time;
}
mem_inline bool is_locked() const
{
node *p = head.next;
while( p )
{
if( p->is_locked() )
return true;
p = p->next;
}
return false;
}
mem_inline bool operator < ( const page & right ) const
{
return ( priority() < right.priority() );
}
public:
mem_align union {
struct {
byte *base;
page *next;
page *prev;
size_type size;
node head;
size_type num_nodes;
};
byte pad[mem_page_pad];
};
};
class chunk {
public:
mem_inline chunk( size_type _size, chunk *old )
{
size = _size;
next = old;
prev = NULL;
if( next )
next->prev = this;
}
mem_inline size_type available() const
{
return size;
}
public:
chunk *next;
chunk *prev;
size_type size;
};
public:
mem_inline cache()
{
current_time = 0;
pages = NULL;
chunks = NULL;
allocated = 0;
g_num_nodes = 0;
num_recycle = 0;
num_chunk_alloc = 0;
num_pages = 0;
num_chunks = 0;
num_stream_alloc = 0;
num_page_del = 0;
}
mem_inline ~cache()
{
destory();
}
mem_inline time_type get_current_time()
{
return ( ++ current_time );
}
mem_inline void *alloc( size_type size, entry *obj )
{
void *ptr = NULL;
++ allocated;
obj->node_ptr = NULL;
if( search_chunk( ptr, size ) )
return ptr;
else if( search_page( ptr, size, obj ) )
return ptr;
else if( (size + sizeof(page)) > al.available() )
{
if( search_entry( ptr, size, obj ) )
return ptr;
else
{
if( recycle_page( size ) )
{
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
else
{
free_page( size );
allocate_page( size );
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
}
}
else
{
allocate_page( size );
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
}
mem_inline void dealloc( void *ptr, size_type size, entry *obj )
{
-- allocated;
if( obj->node_ptr )
{
obj->node_ptr->detach();
obj->node_ptr->g_detach();
obj->node_ptr->~node();
node_pool.dealloc( obj->node_ptr, sizeof(node) );
obj->node_ptr = NULL;
-- g_num_nodes;
}
if( size >= sizeof(chunk) )
{
chunks = new (ptr) chunk( size, chunks );
++ num_chunks;
}
if( allocated == 0 )
destory();
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== cache Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "current time: " << current_time << std::endl;
std::cout << "number of allocations: " << allocated << std::endl;
std::cout << "number of chunks: " << num_chunks << std::endl;
std::cout << "number of chunk allocations: " << num_chunk_alloc << std::endl;
std::cout << "number of nodes: " << g_num_nodes << std::endl;
std::cout << "number of stream allocations: " << num_stream_alloc << std::endl;
std::cout << "number of pages: " << num_pages << std::endl;
std::cout << "number of page recycles: " << num_recycle << std::endl;
std::cout << "number of page deletions: " << num_page_del << std::endl;
std::cout << std::endl;
std::cout << "======================================" << std::endl;
std::cout << std::endl;
}
private:
mem_inline void destory()
{
page *p = pages;
while( p )
{
pages = p->next;
p->~page();
al.dealloc( p, p->get_size() );
p = pages;
}
chunks = NULL;
g_num_nodes = 0;
num_recycle = 0;
num_chunk_alloc = 0;
num_pages = 0;
num_chunks = 0;
num_stream_alloc = 0;
num_page_del = 0;
}
mem_inline bool search_chunk( void * & ptr, size_type size )
{
chunk *p = chunks;
while( p )
{
if( size <= p->available() )
{
ptr = (void *) p;
if( p->prev )
p->prev->next = p->next;
if( p->next )
p->next->prev = p->prev;
++ num_chunk_alloc;
-- num_chunks;
return true;
}
p = p->next;
}
return false;
}
mem_inline bool search_page( void * & ptr, size_type size, entry *obj )
{
page *p = pages;
while( p )
{
if( size <= p->available() )
{
ptr = p->alloc( size );
new (node_pool.alloc( sizeof(node) )) node( obj, p->head.next, g_head.g_next, &p->head, &g_head );
++ p->num_nodes;
++ g_num_nodes;
return true;
}
p = p->next;
}
return false;
}
mem_inline bool search_entry( void * & ptr, size_type size, entry *obj )
{
node *old = NULL;
node *p = g_head.g_next;
while( p )
{
if( !p->is_locked() &&
p->stream_size() >= size )
{
if( old )
{
if( *p->ptr < *old->ptr )
old = p;
}
else
old = p;
}
p = p->g_next;
}
if( old && old->stream_out( ptr ) )
{
old->ptr = obj;
obj->node_ptr = old;
++ num_stream_alloc;
return true;
}
return false;
}
mem_inline bool recycle_page( size_type size )
{
if( pages )
{
page *old = NULL;
page *p = pages;
while( p )
{
if( !p->is_locked() &&
p->get_size() >= size )
{
if( old )
{
if( *p < *old )
old = p;
}
else
old = p;
}
p = p->next;
}
if( old )
{
if( old != pages )
{
if( old->prev )
old->prev->next = old->next;
if( old->next )
old->next->prev = old->prev;
old->recycle( pages );
pages = old;
}
else
{
old->recycle( old->next );
}
++ num_recycle;
return true;
}
}
return false;
}
mem_inline bool delete_page( size_type & del_size )
{
if( pages )
{
page *old = NULL;
page *p = pages;
while( p )
{
if( !p->is_locked() )
{
if( old )
{
if( *p < *old )
old = p;
}
else
old = p;
}
p = p->next;
}
if( old )
{
if( old != pages )
{
if( old->prev )
old->prev->next = old->next;
if( old->next )
old->next->prev = old->prev;
}
else
{
pages = old->next;
if( pages )
pages->prev = NULL;
}
del_size = old->get_size();
old->~page();
al.dealloc( old, old->get_size() );
-- num_pages;
++ num_page_del;
return true;
}
}
del_size = 0;
return false;
}
mem_inline void free_page( size_type size )
{
size_type del_size = 0;
size_type freed_size = 0;
while( freed_size < size && delete_page( del_size ) )
{
freed_size += del_size;
}
}
mem_inline void allocate_page( size_type size )
{
size_type asize = mem_min( mem_max( sizeof(page) + size, mem_page_size ), al.available() );
pages = new (al.alloc( asize )) page( asize - sizeof(page), pages );
++ num_pages;
}
private:
time_type current_time;
time_type allocated;
ALLOC al;
node g_head;
size_type g_num_nodes;
page *pages;
size_type num_pages;
size_type num_recycle;
chunk *chunks;
size_type num_chunks;
size_type num_chunk_alloc;
size_type num_stream_alloc;
size_type num_page_del;
public:
static pool< ALLOC > node_pool;
};
class man {
public:
mem_inline man()
{
m_heap = NULL;
upl = NULL;
apl = NULL;
num_stream_out = 0;
}
mem_inline ~man()
{
if( apl )
delete apl;
if( upl )
delete upl;
if( m_heap )
delete m_heap;
}
mem_inline void begin( size_type heap_size )
{
m_heap = new heap( heap_size );
upl = new pool< allocator >;
apl = new pool< aligned_allocator >;
num_stream_out = 0;
}
mem_inline void end()
{
delete apl;
apl = NULL;
delete upl;
upl = NULL;
delete m_heap;
m_heap = NULL;
}
mem_inline void *alloc( size_type size )
{
return upl->alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
return upl->dealloc( ptr, size );
}
mem_inline void *aligned_alloc( size_type size )
{
return apl->alloc( size );
}
mem_inline void aligned_dealloc( void *ptr, size_type size )
{
return apl->dealloc( ptr, size );
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "********** MemMan Statistics **********" << std::endl;
std::cout << std::endl;
if( m_heap )
{
std::cout << "global heap: " << std::endl;
m_heap->print();
}
std::cout << std::endl;
std::cout << "page size: " << mem_page_size << " Byte" << std::endl;
std::cout << std::endl;
if( upl )
{
std::cout << "unaligned pool: " << std::endl;
upl->print();
}
if( apl )
{
std::cout << "aligned pool: " << std::endl;
apl->print();
}
std::cout << "unaligned node pool: " << std::endl;
cache< mem::man::allocator >::node_pool.print();
std::cout << "aligned node pool: " << std::endl;
cache< mem::man::aligned_allocator >::node_pool.print();
std::cout << "unaligned cache: " << std::endl;
cache< mem::man::allocator >::entry::pl.print();
std::cout << "aligned cache: " << std::endl;
cache< mem::man::aligned_allocator >::entry::pl.print();
std::cout << std::endl;
std::cout << "number of stream_out: " << num_stream_out << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "***************************************" << std::endl;
std::cout << std::endl;
}
public:
static heap *m_heap;
public:
class allocator {
public:
mem_inline void *alloc( size_type size )
{
return m_heap->alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
m_heap->dealloc( ptr, size );
}
mem_inline size_type available() const
{
return m_heap->available();
}
};
class aligned_allocator {
public:
mem_inline void *alloc( size_type size )
{
return m_heap->aligned_alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
m_heap->aligned_dealloc( ptr, size );
}
mem_inline size_type available() const
{
return m_heap->available();
}
};
public:
pool< allocator > *upl;
pool< aligned_allocator > *apl;
};
typedef cache< man::allocator >::entry resource;
typedef cache< man::aligned_allocator >::entry aligned_resource;
} // namespace mem
extern mem::man memman;
#pragma pack(pop)
#endif // __MEMMAN__
*
* MemMan 3.0.0.0 beta
*
* Copyright (C) 2007 - 2008 by Len3d
* All rights reserved.
*
*************************************************/
#ifndef __MEMMAN__
#define __MEMMAN__
#include <malloc.h>
#include <vector>
#include <algorithm>
#include <iostream>
#pragma pack(push,1)
namespace mem {
#define mem_inline __forceinline
#define mem_pool_pad 16
#define mem_page_pad 48
#define mem_page_size ( 2 << 18 )
#define mem_align_size 16
#define mem_align __declspec( align( mem_align_size ) )
typedef unsigned int prior_type;
typedef unsigned long time_type;
typedef unsigned long size_type;
typedef unsigned char byte;
#define mem_max( a, b ) ( ( (a) > (b) ) ? (a) : (b) )
#define mem_min( a, b ) ( ( (a) < (b) ) ? (a) : (b) )
#define mem_mbyte( a ) ( float(a) * (1.0f / float( 1024 * 1024 )) )
enum {
ENTRY_PRIORITY = 0,
};
extern time_type num_stream_out;
class heap {
public:
mem_inline heap( size_type max_size )
{
allocated_size = 0;
available_size = max_size;
}
mem_inline ~heap()
{
}
mem_inline void *alloc( size_type size )
{
if( size == 0 )
return NULL;
allocated_size += size;
available_size -= size;
return sys_alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
if( ptr && size != 0 )
{
sys_dealloc( ptr );
allocated_size -= size;
available_size += size;
}
}
mem_inline void *aligned_alloc( size_type size )
{
if( size == 0 )
return NULL;
allocated_size += size;
available_size -= size;
return sys_aligned_alloc( size );
}
mem_inline void aligned_dealloc( void *ptr, size_type size )
{
if( ptr && size != 0 )
{
sys_aligned_dealloc( ptr );
allocated_size -= size;
available_size += size;
}
}
mem_inline size_type available() const
{
return available_size;
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== heap Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "allocated size: " << mem_mbyte( allocated_size ) << " MB" << std::endl;
std::cout << "available size: " << mem_mbyte( available_size ) << " MB" << std::endl;
std::cout << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << std::endl;
}
private:
mem_inline void *sys_alloc( size_type size )
{
return malloc( size );
}
mem_inline void sys_dealloc( void *ptr )
{
free( ptr );
}
mem_inline void *sys_aligned_alloc( size_type size )
{
return _aligned_malloc( size, mem_align_size );
}
mem_inline void sys_aligned_dealloc( void *ptr )
{
_aligned_free( ptr );
}
private:
size_type allocated_size,
available_size;
};
template < typename ALLOC >
class pool {
private:
class page {
public:
mem_inline page( size_type _size, page *old )
{
base = get_base();
_next = old;
size = _size;
}
mem_inline byte *get_base()
{
return ( (byte *) this + sizeof(page) );
}
mem_inline size_type get_size()
{
return static_cast<size_type>( base - get_base() + size );
}
mem_inline size_type available() const
{
return size;
}
mem_inline void *alloc( size_type _size )
{
byte *ptr = base;
base += _size;
size -= _size;
return ptr;
}
mem_inline page *next()
{
return _next;
}
private:
mem_align union {
struct {
byte *base;
page *_next;
size_type size;
};
byte pad[mem_pool_pad];
};
};
class chunk {
public:
mem_inline chunk( size_type _size, chunk *old )
{
next = old;
size = _size;
}
mem_inline size_type available() const
{
return size;
}
public:
chunk *next;
size_type size;
};
public:
mem_inline pool()
{
pages = NULL;
chunks = NULL;
allocated = 0;
}
mem_inline ~pool()
{
destory();
}
mem_inline void destory()
{
page *p;
while( ( p = pages ) != NULL )
{
pages = p->next();
al.dealloc( p, p->get_size() );
}
pages = NULL;
chunks = NULL;
}
mem_inline bool search_chunk( void * & ptr, size_type size )
{
if( chunks && ( size <= chunks->available() ) )
{
ptr = (void *) chunks;
chunks = chunks->next;
return true;
}
else
return false;
}
mem_inline bool search_page( void * & ptr, size_type size )
{
if( pages && ( size <= pages->available() ) )
{
ptr = pages->alloc( size );
return true;
}
else
return false;
}
mem_inline void allocate_page( size_type size )
{
size_type asize = mem_max( size, mem_page_size );
pages = new (al.alloc( sizeof(page) + asize )) page( asize, pages );
}
mem_inline void *alloc( size_type size )
{
void *ptr;
++ allocated;
if( search_chunk( ptr, size ) )
return ptr;
else if( search_page( ptr, size ) )
return ptr;
else {
allocate_page( size );
if( search_page( ptr, size ) )
return ptr;
else
return NULL;
}
}
mem_inline void dealloc( void *ptr, size_type size )
{
-- allocated;
if( size >= sizeof(chunk) )
chunks = new (ptr) chunk( size, chunks );
if( allocated == 0 )
destory();
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== pool Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "number of allocations: " << allocated << std::endl;
std::cout << std::endl;
std::cout << "=====================================" << std::endl;
std::cout << std::endl;
}
private:
page *pages;
chunk *chunks;
size_type allocated;
ALLOC al;
};
template < typename ALLOC >
class cache {
public:
class node;
class entry {
public:
mem_inline entry()
{
priority = ENTRY_PRIORITY;
last_use_time = pl.get_current_time();
locked = false;
node_ptr = NULL;
}
mem_inline entry( prior_type prior )
{
priority = prior;
last_use_time = pl.get_current_time();
locked = false;
node_ptr = NULL;
}
mem_inline virtual ~entry()
{
}
mem_inline void *alloc( size_type size )
{
return pl.alloc( size, this );
}
mem_inline void dealloc( void *ptr, size_type size )
{
pl.dealloc( ptr, size, this );
}
mem_inline void stream_begin()
{
locked = true;
stream_in();
last_use_time = pl.get_current_time();
}
mem_inline void stream_end()
{
locked = false;
}
mem_inline bool is_locked()
{
return locked;
}
mem_inline bool operator < ( const entry & right ) const
{
if( priority == right.priority )
return ( last_use_time < right.last_use_time );
else
return ( priority < right.priority );
}
public:
virtual void stream_in() = 0;
virtual size_type stream_size() = 0;
virtual void *stream_out() = 0;
public:
static cache< ALLOC > pl;
prior_type priority;
time_type last_use_time;
bool locked;
node *node_ptr;
};
class node {
public:
mem_inline node( entry *obj, node *old, node *g_old, node *phead, node *g_phead )
{
ptr = obj;
obj->node_ptr = this;
next = old;
prev = phead;
g_next = g_old;
g_prev = g_phead;
if( next )
next->prev = this;
if( prev )
prev->next = this;
if( g_next )
g_next->g_prev = this;
if( g_prev )
g_prev->g_next = this;
}
mem_inline node()
{
ptr = NULL;
next = NULL;
prev = NULL;
g_next = NULL;
g_prev = NULL;
}
mem_inline ~node()
{
void *p = NULL;
stream_out( p );
}
mem_inline time_type get_last_use_time() const
{
if( ptr )
return ptr->last_use_time;
else
return 0;
}
mem_inline bool is_locked() const
{
if( ptr )
return ptr->is_locked();
else
return false;
}
mem_inline size_type stream_size()
{
if( ptr )
return ptr->stream_size();
else
return 0;
}
mem_inline bool stream_out( void * & p )
{
if( ptr )
{
p = ptr->stream_out();
ptr->node_ptr = NULL;
++ num_stream_out;
return true;
}
else
return false;
}
mem_inline void detach()
{
if( prev )
prev->next = next;
if( next )
next->prev = prev;
}
mem_inline void g_detach()
{
if( g_prev )
g_prev->g_next = g_next;
if( g_next )
g_next->g_prev = g_prev;
}
public:
entry *ptr;
node *next, *prev;
node *g_next, *g_prev;
};
class page {
public:
mem_inline page( size_type _size, page *old )
{
size = _size;
base = get_base();
next = old;
prev = NULL;
if( next )
next->prev = this;
num_nodes = 0;
}
mem_inline ~page()
{
node *p = head.next;
while( p )
{
head.next = p->next;
p->g_detach();
p->~node();
node_pool.dealloc( p, sizeof(node) );
p = head.next;
}
}
mem_inline void recycle( page *old )
{
node *p = head.next;
while( p )
{
head.next = p->next;
p->g_detach();
p->~node();
node_pool.dealloc( p, sizeof(node) );
p = head.next;
}
head.next = NULL;
size = get_size();
base = get_base();
next = old;
prev = NULL;
if( next )
next->prev = this;
num_nodes = 0;
}
mem_inline byte *get_base()
{
return (byte *) this + sizeof(page);
}
mem_inline size_type get_size()
{
return static_cast<size_type>( base - get_base() + size );
}
mem_inline size_type available() const
{
return size;
}
mem_inline void *alloc( size_type req_size )
{
void *ptr = (void *) base;
base += req_size;
size -= req_size;
return ptr;
}
mem_inline time_type priority() const
{
time_type last_use_time = 0;
node *p = head.next;
while( p )
{
last_use_time += p->get_last_use_time();
p = p->next;
}
if( num_nodes != 0 )
last_use_time /= static_cast<time_type>( num_nodes );
return last_use_time;
}
mem_inline bool is_locked() const
{
node *p = head.next;
while( p )
{
if( p->is_locked() )
return true;
p = p->next;
}
return false;
}
mem_inline bool operator < ( const page & right ) const
{
return ( priority() < right.priority() );
}
public:
mem_align union {
struct {
byte *base;
page *next;
page *prev;
size_type size;
node head;
size_type num_nodes;
};
byte pad[mem_page_pad];
};
};
class chunk {
public:
mem_inline chunk( size_type _size, chunk *old )
{
size = _size;
next = old;
prev = NULL;
if( next )
next->prev = this;
}
mem_inline size_type available() const
{
return size;
}
public:
chunk *next;
chunk *prev;
size_type size;
};
public:
mem_inline cache()
{
current_time = 0;
pages = NULL;
chunks = NULL;
allocated = 0;
g_num_nodes = 0;
num_recycle = 0;
num_chunk_alloc = 0;
num_pages = 0;
num_chunks = 0;
num_stream_alloc = 0;
num_page_del = 0;
}
mem_inline ~cache()
{
destory();
}
mem_inline time_type get_current_time()
{
return ( ++ current_time );
}
mem_inline void *alloc( size_type size, entry *obj )
{
void *ptr = NULL;
++ allocated;
obj->node_ptr = NULL;
if( search_chunk( ptr, size ) )
return ptr;
else if( search_page( ptr, size, obj ) )
return ptr;
else if( (size + sizeof(page)) > al.available() )
{
if( search_entry( ptr, size, obj ) )
return ptr;
else
{
if( recycle_page( size ) )
{
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
else
{
free_page( size );
allocate_page( size );
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
}
}
else
{
allocate_page( size );
if( search_page( ptr, size, obj ) )
return ptr;
else
{
std::cout << "fatal: failed to allocate memory!" << std::endl;
return NULL;
}
}
}
mem_inline void dealloc( void *ptr, size_type size, entry *obj )
{
-- allocated;
if( obj->node_ptr )
{
obj->node_ptr->detach();
obj->node_ptr->g_detach();
obj->node_ptr->~node();
node_pool.dealloc( obj->node_ptr, sizeof(node) );
obj->node_ptr = NULL;
-- g_num_nodes;
}
if( size >= sizeof(chunk) )
{
chunks = new (ptr) chunk( size, chunks );
++ num_chunks;
}
if( allocated == 0 )
destory();
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "========== cache Statistics ==========" << std::endl;
std::cout << std::endl;
std::cout << "current time: " << current_time << std::endl;
std::cout << "number of allocations: " << allocated << std::endl;
std::cout << "number of chunks: " << num_chunks << std::endl;
std::cout << "number of chunk allocations: " << num_chunk_alloc << std::endl;
std::cout << "number of nodes: " << g_num_nodes << std::endl;
std::cout << "number of stream allocations: " << num_stream_alloc << std::endl;
std::cout << "number of pages: " << num_pages << std::endl;
std::cout << "number of page recycles: " << num_recycle << std::endl;
std::cout << "number of page deletions: " << num_page_del << std::endl;
std::cout << std::endl;
std::cout << "======================================" << std::endl;
std::cout << std::endl;
}
private:
mem_inline void destory()
{
page *p = pages;
while( p )
{
pages = p->next;
p->~page();
al.dealloc( p, p->get_size() );
p = pages;
}
chunks = NULL;
g_num_nodes = 0;
num_recycle = 0;
num_chunk_alloc = 0;
num_pages = 0;
num_chunks = 0;
num_stream_alloc = 0;
num_page_del = 0;
}
mem_inline bool search_chunk( void * & ptr, size_type size )
{
chunk *p = chunks;
while( p )
{
if( size <= p->available() )
{
ptr = (void *) p;
if( p->prev )
p->prev->next = p->next;
if( p->next )
p->next->prev = p->prev;
++ num_chunk_alloc;
-- num_chunks;
return true;
}
p = p->next;
}
return false;
}
mem_inline bool search_page( void * & ptr, size_type size, entry *obj )
{
page *p = pages;
while( p )
{
if( size <= p->available() )
{
ptr = p->alloc( size );
new (node_pool.alloc( sizeof(node) )) node( obj, p->head.next, g_head.g_next, &p->head, &g_head );
++ p->num_nodes;
++ g_num_nodes;
return true;
}
p = p->next;
}
return false;
}
mem_inline bool search_entry( void * & ptr, size_type size, entry *obj )
{
node *old = NULL;
node *p = g_head.g_next;
while( p )
{
if( !p->is_locked() &&
p->stream_size() >= size )
{
if( old )
{
if( *p->ptr < *old->ptr )
old = p;
}
else
old = p;
}
p = p->g_next;
}
if( old && old->stream_out( ptr ) )
{
old->ptr = obj;
obj->node_ptr = old;
++ num_stream_alloc;
return true;
}
return false;
}
mem_inline bool recycle_page( size_type size )
{
if( pages )
{
page *old = NULL;
page *p = pages;
while( p )
{
if( !p->is_locked() &&
p->get_size() >= size )
{
if( old )
{
if( *p < *old )
old = p;
}
else
old = p;
}
p = p->next;
}
if( old )
{
if( old != pages )
{
if( old->prev )
old->prev->next = old->next;
if( old->next )
old->next->prev = old->prev;
old->recycle( pages );
pages = old;
}
else
{
old->recycle( old->next );
}
++ num_recycle;
return true;
}
}
return false;
}
mem_inline bool delete_page( size_type & del_size )
{
if( pages )
{
page *old = NULL;
page *p = pages;
while( p )
{
if( !p->is_locked() )
{
if( old )
{
if( *p < *old )
old = p;
}
else
old = p;
}
p = p->next;
}
if( old )
{
if( old != pages )
{
if( old->prev )
old->prev->next = old->next;
if( old->next )
old->next->prev = old->prev;
}
else
{
pages = old->next;
if( pages )
pages->prev = NULL;
}
del_size = old->get_size();
old->~page();
al.dealloc( old, old->get_size() );
-- num_pages;
++ num_page_del;
return true;
}
}
del_size = 0;
return false;
}
mem_inline void free_page( size_type size )
{
size_type del_size = 0;
size_type freed_size = 0;
while( freed_size < size && delete_page( del_size ) )
{
freed_size += del_size;
}
}
mem_inline void allocate_page( size_type size )
{
size_type asize = mem_min( mem_max( sizeof(page) + size, mem_page_size ), al.available() );
pages = new (al.alloc( asize )) page( asize - sizeof(page), pages );
++ num_pages;
}
private:
time_type current_time;
time_type allocated;
ALLOC al;
node g_head;
size_type g_num_nodes;
page *pages;
size_type num_pages;
size_type num_recycle;
chunk *chunks;
size_type num_chunks;
size_type num_chunk_alloc;
size_type num_stream_alloc;
size_type num_page_del;
public:
static pool< ALLOC > node_pool;
};
class man {
public:
mem_inline man()
{
m_heap = NULL;
upl = NULL;
apl = NULL;
num_stream_out = 0;
}
mem_inline ~man()
{
if( apl )
delete apl;
if( upl )
delete upl;
if( m_heap )
delete m_heap;
}
mem_inline void begin( size_type heap_size )
{
m_heap = new heap( heap_size );
upl = new pool< allocator >;
apl = new pool< aligned_allocator >;
num_stream_out = 0;
}
mem_inline void end()
{
delete apl;
apl = NULL;
delete upl;
upl = NULL;
delete m_heap;
m_heap = NULL;
}
mem_inline void *alloc( size_type size )
{
return upl->alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
return upl->dealloc( ptr, size );
}
mem_inline void *aligned_alloc( size_type size )
{
return apl->alloc( size );
}
mem_inline void aligned_dealloc( void *ptr, size_type size )
{
return apl->dealloc( ptr, size );
}
mem_inline void print()
{
std::cout << std::endl;
std::cout << "********** MemMan Statistics **********" << std::endl;
std::cout << std::endl;
if( m_heap )
{
std::cout << "global heap: " << std::endl;
m_heap->print();
}
std::cout << std::endl;
std::cout << "page size: " << mem_page_size << " Byte" << std::endl;
std::cout << std::endl;
if( upl )
{
std::cout << "unaligned pool: " << std::endl;
upl->print();
}
if( apl )
{
std::cout << "aligned pool: " << std::endl;
apl->print();
}
std::cout << "unaligned node pool: " << std::endl;
cache< mem::man::allocator >::node_pool.print();
std::cout << "aligned node pool: " << std::endl;
cache< mem::man::aligned_allocator >::node_pool.print();
std::cout << "unaligned cache: " << std::endl;
cache< mem::man::allocator >::entry::pl.print();
std::cout << "aligned cache: " << std::endl;
cache< mem::man::aligned_allocator >::entry::pl.print();
std::cout << std::endl;
std::cout << "number of stream_out: " << num_stream_out << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "***************************************" << std::endl;
std::cout << std::endl;
}
public:
static heap *m_heap;
public:
class allocator {
public:
mem_inline void *alloc( size_type size )
{
return m_heap->alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
m_heap->dealloc( ptr, size );
}
mem_inline size_type available() const
{
return m_heap->available();
}
};
class aligned_allocator {
public:
mem_inline void *alloc( size_type size )
{
return m_heap->aligned_alloc( size );
}
mem_inline void dealloc( void *ptr, size_type size )
{
m_heap->aligned_dealloc( ptr, size );
}
mem_inline size_type available() const
{
return m_heap->available();
}
};
public:
pool< allocator > *upl;
pool< aligned_allocator > *apl;
};
typedef cache< man::allocator >::entry resource;
typedef cache< man::aligned_allocator >::entry aligned_resource;
} // namespace mem
extern mem::man memman;
#pragma pack(pop)
#endif // __MEMMAN__
/**************************************************
*
* MemMan 3.0.0.0 beta
*
* Copyright (C) 2007 - 2008 by Len3d
* All rights reserved.
*
*************************************************/
#ifndef __MEMMAN_DEF__
#define __MEMMAN_DEF__
#include "memman3.h"
mem::man memman;
mem::heap *mem::man::m_heap;
mem::pool< mem::man::allocator > mem::cache< mem::man::allocator >::node_pool;
mem::pool< mem::man::aligned_allocator > mem::cache< mem::man::aligned_allocator >::node_pool;
mem::time_type mem::num_stream_out;
mem::cache< mem::man::allocator > mem::cache< mem::man::allocator >::entry::pl;
mem::cache< mem::man::aligned_allocator > mem::cache< mem::man::aligned_allocator >::entry::pl;
#endif // __MEMMAN_DEF__
*
* MemMan 3.0.0.0 beta
*
* Copyright (C) 2007 - 2008 by Len3d
* All rights reserved.
*
*************************************************/
#ifndef __MEMMAN_DEF__
#define __MEMMAN_DEF__
#include "memman3.h"
mem::man memman;
mem::heap *mem::man::m_heap;
mem::pool< mem::man::allocator > mem::cache< mem::man::allocator >::node_pool;
mem::pool< mem::man::aligned_allocator > mem::cache< mem::man::aligned_allocator >::node_pool;
mem::time_type mem::num_stream_out;
mem::cache< mem::man::allocator > mem::cache< mem::man::allocator >::entry::pl;
mem::cache< mem::man::aligned_allocator > mem::cache< mem::man::aligned_allocator >::entry::pl;
#endif // __MEMMAN_DEF__