Saturday, September 12, 2015

Short Term Memory

Funny thing about doing your own tech is that you sometimes need to do some funny stuff. This week I needed done Short Term Memory Manager. My comment in code describe it like this:
Short Term Memory Manager (STM Manager). STM is memory which you want to use for short one-shot tasks:             Create->Execute->[GetResult]->Destroy It is limited by capacity so you never can use more than you pre-allocated for it. Right now it's use to transfer resource data CPU->GPU and in animations tasks.
For me this is temporary memory which I use for example to load texture data and then passing it to GPU upload (which will remove it). There are also other usage where I think using normal allocation would be a little bit overkill.

So my short term memory manager use my new memory ring buffer which look like this:

wrMemoryRingBuffer.h

wrMemoryRingBuffer.cpp

After creating this code the rest was easy:

    //////////////////////////////////////////////////////////////////////////
    uint8* CShortTermMemoryMgr::cpuAlloc( uint32 a_Nbytes, uint32 a_alignment )
    {
        // memory is HEADER + ALIGNMENT_MEMORY(ALIGNMENT-1) + HEADER_OFFSET(+1) + a_Nbytes
        uint32 memorySize = sizeof(SHeaderCPU) + a_alignment +a_Nbytes;

        uint8* memory = nullptr;

        {
            CMutexAutoLock lock(m_cpuMutex);

            memory = (uint8*)m_cpuMemory.alloc(memorySize);

            if (!memory)
            {
                if (cpuRecoverMemory(memorySize))
                {
                    memory = (uint8*)m_cpuMemory.alloc(memorySize);
                }
                else
                {
                    WR_ERROR(false, "There is not enough memory for this allocation.");
                    return nullptr;
                }
            }
        }

        // Create memory header
        SHeaderCPU* header = (SHeaderCPU*)memory;
        header->isUse = true;
        header->size = a_Nbytes;

        // Fill offset info
        uint8* data = wrAlignAdress(memory + sizeof(SHeaderCPU)+1, a_alignment);
        data[-1] = static_cast<uint8>(data-memory);

        return data; 
    }

    //////////////////////////////////////////////////////////////////////////
    void CShortTermMemoryMgr::cpuFree( uint8* memory )
    {
        if (memory)
        {
            CMutexAutoLock lock(m_cpuMutex);
            SHeaderCPU* header = (SHeaderCPU*)(memory - memory[-1]);
            header->isUse = false;
        }
    }
    //////////////////////////////////////////////////////////////////////////
    bool CShortTermMemoryMgr::cpuRecoverMemory( uint32 a_memoryNeed )
    {
        const void* memory = nullptr;

        while(m_cpuMemory.getBiggestAllocSize() < a_memoryNeed && (memory = m_cpuMemory.peek()))
        {
            const SHeaderCPU* header = (const SHeaderCPU*)memory;

            if (!header->isUse)
            {
                m_cpuMemory.free();
            }
            else
            {
                break;
            }
        }

        return m_cpuMemory.getBiggestAllocSize() >= a_memoryNeed;
    }
I added also two helper functions:
    
    template<class t="">
    T* CShortTermMemoryMgr::cpuAllocT( uint32 a_alignment )
    {
        if (uint8* memory = cpuAlloc(sizeof(T), a_alignment))
        {
            return wrNewExt(memory) T;
        }

        return nullptr;
    }

    template<class t="">
    void CShortTermMemoryMgr::cpuFreeT( T* a_memory )
    {
        if (a_memory)
        {
            a_memory->~T();
            cpuFree((uint8*)a_memory);
        }
    }


And this finalized my work :] Personally I really like how this came out. Its simple and pretty efficient but well I'm curious what you think about this? Maybe you have some betters idea how to resolve problems like this?

Greg

No comments:

Post a Comment