len3d

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

/**************************************************
 *
 * 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    ( 1 << 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) )

    
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 
<< 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 
<< 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 
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    *= 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    
*= 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    
*= 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    
*= 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 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;
        }


        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
                
{
                    recycle_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 );
        
            
if( allocated == 0 )
                destory();
        }


        mem_inline 
void print()
        
{
            std::cout 
<< std::endl;
            std::cout 
<< "========== cache Statistics ==========" << std::endl;
            std::cout 
<< std::endl;

            std::cout 
<< std::endl;
            std::cout 
<< "======================================" << std::endl;
            std::cout 
<< std::endl;
        }


    
private:
        mem_inline 
void destory()
        
{
            page    
*= pages;
        
            
while( p )
            
{
                pages 
= p->next;
                p
->~page();
                al.dealloc( p, p
->get_size() );
                p 
= pages;
            }


            chunks 
= NULL;

            g_num_nodes 
= 0;
        }


        mem_inline 
bool search_chunk( void * & ptr, size_type size )
        
{
            chunk    
*= 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;
                    
                    
return true;
                }


                p 
= p->next;
            }


            
return false;
        }


        mem_inline 
bool search_page( void * & ptr, size_type size, entry *obj )
        
{
            page    
*= 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    
*= 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;
                    
                
return true;
            }


            
return false;
        }


        mem_inline 
void recycle_page( size_type size )
        
{
            
if( pages )
            
{
                page    
*p, *old;

                old 
= pages;
                p 
= pages->next;

                
while( p )
                
{
                    
if*< *old )
                        old 
= p;

                    p 
= p->next;
                }


                
if( old != pages )
                
{
                    
if( old->prev )
                        old
->prev->next = old->next;
                    
if( old->next )
                        old
->next->prev = old->prev;

                    old
->recycle( pages );
                    pages 
= old;
                }

            }

        }


        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 );
        }


    
private:
        time_type                        current_time;
        time_type                        allocated;
        ALLOC                            al;
        node                            g_head;
        size_type                        g_num_nodes;
        page                            
*pages;
        chunk                            
*chunks;
        
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 )
                m_heap
->print();

            
if( upl )
                upl
->print();

            
if( apl )
                apl
->print();

            cache
< mem::man::allocator >::entry::pl.print();

            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__

 

posted on 2007-12-12 15:32  Len3d  阅读(241)  评论(0编辑  收藏  举报