Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Session of low-level optimization of memory usage in C++ programs with total exposure

, , 22 Jun 2009
In this article, we will try to make our algorithms work faster using the methods of low-level optimization of memory allocation in C++.
make-it-faster.zip
src
make_it_faster
make_it_faster_80.vcproj.DEV.ligen.user
alloc
win32
make_it_faster_win32
make_it_faster_win32_80.vcproj.DEV.ligen.user
win32_arena_local_sample
arena_local_sample_80.vcproj.DEV.ligen.user
win32_arena_sample
arena_sample_80.vcproj.DEV.ligen.user
win32_arena_tests
arena_tests_80.vcproj.DEV.ligen.user
win32_fast_object_sample
fast_object_sample_80.vcproj.DEV.ligen.user
#ifndef ARENA_H
#define ARENA_H

#include "alloc\crt_stl_allocators.h"
#include "assert.h"
#include "cmnFastObjects.h"

namespace utils
{

struct IArena
{
    virtual ~IArena(){}
    virtual void * Allocate(size_t size) = 0;
    virtual void * AllocateNoThrow(size_t size) = 0;
    virtual void Deallocate(void * p) = 0;
    virtual void Clear() = 0;
};


struct IArenaGlobalCounter
{
    virtual ~IArenaGlobalCounter(){}
    // debug api
    virtual void ChangeGlobalCount(int iValue)=0;
    virtual long GetGlobalCount() const =0;
};

struct IArenaContext
{
    virtual ~IArenaContext(){}
    // arena api
    virtual IArena * GetArena() const=0;
    virtual void SetArena(IArena * pArena)=0;
};

const int g_iMaxArenaContextSizeInBytes = 16;

typedef utils::CFastObject<g_iMaxArenaContextSizeInBytes, IArenaContext> ArenaContext_type;

struct IArenaProvider
{
    virtual ~IArenaProvider(){}
    // item api
    virtual void QueryThreadAssociatedItem(ArenaContext_type * pContext)=0;
};

void Arena_InitLib(IArenaProvider * pProvider, //  IN, OPTIONAL
                   IArenaGlobalCounter * pCounter=0); //  IN, OPTIONAL

void Arena_UnregisterLib();

class CArenaLib
{
    CArenaLib(const CArenaLib &);
    CArenaLib & operator =(const CArenaLib &);
public:
    CArenaLib(IArenaProvider * pProvider, //  IN, OPTIONAL
              IArenaGlobalCounter * pCounter=0)
    {
        Arena_InitLib(pProvider, pCounter);
    }
    ~CArenaLib()
    {
        Arena_UnregisterLib();
    }
};

void RegisterArena(IArena * pArena);
IArena * ExchangeArena(IArena * pArena);
void UnregisterArena();
void Arena_ChangeGlobalCount(int iDelta);
long Arena_GetGlobalCount();

// base template CArena
template<class BufferType>
class CArena:public IArena
{
    BufferType m_buffer;
    size_t m_iIndex;
    
    CArena(const CArena &);
    CArena & operator =(const CArena &);

protected:

#ifdef _DEBUG
    typedef utils::crt_set<void *>::result SetType;
    SetType m_ptrSet;
    void DbgRegisterAllocate(void * pData)
    {
        std::pair<typename SetType::iterator, bool> res = m_ptrSet.insert(pData);
        if (!res.second)
        {
            abort(); // "DBG: Cannot unregister ptr"
        }
    }
    void DbgRegisterDeallocate(void * pData)
    {
        typename SetType::iterator it = m_ptrSet.find(pData);
        if (it == m_ptrSet.end())
            abort(); // "DBG: Cannot unregister ptr"
        else
            m_ptrSet.erase(it);
    }
    void DbgCheck()
    {
        if (!m_ptrSet.empty())
        {
            abort();
        }
    }
#else
    void DbgRegisterAllocate(void * ) {}
    void DbgRegisterDeallocate(void * ){}
    void DbgCheck() {}
#endif

    // interface for childs
    size_t GetIndex() { return m_iIndex; }
    void SetIndex(size_t index) { m_iIndex = index; }

public:
    CArena() : m_iIndex (0)
    {
        Arena_ChangeGlobalCount(1);
    }
    template<class ParamType>
    CArena(ParamType param) : m_buffer(param), m_iIndex (0) 
    {
        Arena_ChangeGlobalCount(1);
    }
    ~CArena()
    {
        Clear();
        Arena_ChangeGlobalCount(-1);
    }
    void * Allocate(size_t size)
    {
        const size_t bufSize = m_buffer.GetTotalSize();
        if (bufSize <= m_iIndex)
            throw std::bad_alloc("bad_alloc");
        if (bufSize - m_iIndex < size)
            throw std::bad_alloc("bad_alloc");

        void * pResult = m_buffer.GetPtr() + m_iIndex;
        m_iIndex += size;

        DbgRegisterAllocate(pResult);
        return pResult;
    }
    virtual void * AllocateNoThrow(size_t size) 
    {
        const size_t bufSize = m_buffer.GetTotalSize();
        if (bufSize <= m_iIndex)
            return 0;
        if (bufSize - m_iIndex < size)
            return 0;

        void * pResult = m_buffer.GetPtr() + m_iIndex;
        m_iIndex += size;

        DbgRegisterAllocate(pResult);
        return pResult;
    }
    void Deallocate(void * p)
    {
        DbgRegisterDeallocate(p);
    }
    void Clear()
    {
        DbgCheck();
        m_iIndex = 0;
    }
    // user api
    BufferType * GetBuffer() { return &m_buffer; }
    const BufferType * GetBuffer() const { return &m_buffer; }
};

// buffers
template<size_t iMaxSize>
class CConstBuffer
{
    char m_buffer[iMaxSize];
public:
    char * GetPtr() { return m_buffer; }
    size_t GetTotalSize() { return iMaxSize; }
};
class CDynamicBuffer
{
    typedef utils::crt_vector<char>::result Buffer_type;
    Buffer_type m_buffer;
public:
    CDynamicBuffer()
    {
    }
    CDynamicBuffer(size_t size)
        : m_buffer( size )
    {
    }
    char * GetPtr() { return &m_buffer.front(); }
    size_t GetTotalSize() { return m_buffer.size(); }
    void Resize(size_t size) { return m_buffer.resize(size); }  
};

template<size_t iMaxArenaSize>
class CConstArena:public CArena<CConstBuffer<iMaxArenaSize> >
{
};

class CDynamicArena:public CArena<CDynamicBuffer>
{
public:
    CDynamicArena()
        : CArena<CDynamicBuffer>(0)
    {
    }
    CDynamicArena(size_t size)
        : CArena<CDynamicBuffer>(size)
    {
    }
};

// class CAutoCleaner helps to clean IArena at the end of iteration
class CAutoCleaner
{
    IArena * m_pArena;

    CAutoCleaner(const CAutoCleaner &);
    CAutoCleaner&operator = (const CAutoCleaner &);
public:
    CAutoCleaner(IArena * pArena)
        : m_pArena(pArena)
    {
    }
    ~CAutoCleaner()
    {
        m_pArena->Clear();
    }
};


// class CExclusiveAutoArena provides IArena exclusive registration procedure
class CExclusiveAutoArena
{
    IArena * m_pArena;

    CExclusiveAutoArena(const CExclusiveAutoArena&);
    CExclusiveAutoArena&operator = (const CExclusiveAutoArena&);
public:
    CExclusiveAutoArena(IArena * pArena)
        : m_pArena(pArena)
    {
        RegisterArena( pArena );
    }
    ~CExclusiveAutoArena()
    {
        UnregisterArena();
    }
};

// class CExclusiveAutoArena provides IArena registration procedure
class CAutoArena
{
    IArena * m_pArena;
    IArena * m_pOldArena;

    CAutoArena(const CAutoArena&);
    CAutoArena&operator = (const CAutoArena&);
public:
    CAutoArena(IArena * pArena)
        : m_pArena(pArena), m_pOldArena(0)
    {
        m_pOldArena = ExchangeArena( pArena );
    }
    ~CAutoArena()
    {
        IArena * pCurrentArena = ExchangeArena( m_pOldArena );
        &pCurrentArena;
        assert(pCurrentArena == m_pArena);
    }
};


// Arena API
void * Arena_Alloc(size_t size);
void * Arena_AllocNoThrow(size_t size);
void Arena_Free(void * p);

} // utils


#define ARENA_DEFINE_GLOBAL_OPERATORS        \
    void  * __cdecl operator new(size_t size) \
    {\
        return utils::Arena_Alloc(size);\
        \
    }\
    void  * __cdecl operator new[](size_t size)\
    {\
        return utils::Arena_Alloc(size);\
    }\
    void  __cdecl operator delete[](void* pData)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  __cdecl operator delete(void* pData)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  * __cdecl operator new(size_t size,const std::nothrow_t&) \
    {\
        return utils::Arena_AllocNoThrow(size);\
        \
    }\
    void  * __cdecl operator new[](size_t size,const std::nothrow_t&)\
    {\
        return utils::Arena_AllocNoThrow(size);\
    }\
    void  __cdecl operator delete[](void* pData,const std::nothrow_t&)\
    {\
        utils::Arena_Free(pData);\
    }\
    void  __cdecl operator delete(void* pData,const std::nothrow_t&)\
    {\
        utils::Arena_Free(pData);\
    }

#define ARENA_DEFINE_CLASS_OPERATORS        \
    static void* operator new(std::size_t size)\
    {\
        return utils::Arena_Alloc( size );\
    }\
    static void* operator new(std::size_t size, std::nothrow_t) \
    {\
        return utils::Arena_AllocNoThrow( size );\
    }\
    static void operator delete( void * address )\
    {\
        return utils::Arena_Free( address );\
    }\
    void operator delete( void * address , std::nothrow_t)\
    {\
        return utils::Arena_Free( address );\
    }

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Authors

No Biography provided

Apriorit Inc
Apriorit Inc.
Ukraine Ukraine
ApriorIT is a Software Research and Development company that works in advanced knowledge-intensive scopes.
 
Company offers integrated research&development services for the software projects in such directions as Corporate Security, Remote Control, Mobile Development, Embedded Systems, Virtualization, Drivers and others.
 
Official site http://www.apriorit.com
Group type: Organisation

31 members

Follow on   LinkedIn

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 23 Jun 2009
Article Copyright 2009 by Victor A. Milokum, Apriorit Inc
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid