You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
7.1 KiB
C++
252 lines
7.1 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
#include <ITimer.h>
|
|
#include <CrySizer.h>
|
|
#include "CrySizerImpl.h"
|
|
|
|
CrySizerImpl::CrySizerImpl()
|
|
: m_pResourceCollector(0)
|
|
{
|
|
m_nFlags = 0;
|
|
m_nTotalSize = 0;
|
|
// to avoid reallocations during walk through the memory tree, reserve the space for the names
|
|
clear();
|
|
}
|
|
|
|
CrySizerImpl::~CrySizerImpl()
|
|
{
|
|
}
|
|
|
|
void CrySizerImpl::Push (const char* szComponentName)
|
|
{
|
|
m_stackNames.push_back (getNameIndex(getCurrentName(), szComponentName));
|
|
// if the depth is too deep, something is wrong, perhaps an infinite loop
|
|
assert (m_stackNames.size() < 128);
|
|
}
|
|
|
|
void CrySizerImpl::PushSubcomponent (const char* szSubcomponentName)
|
|
{
|
|
Push (szSubcomponentName);
|
|
}
|
|
|
|
|
|
void CrySizerImpl::Pop ()
|
|
{
|
|
if (!m_stackNames.empty())
|
|
{
|
|
m_stackNames.pop_back();
|
|
}
|
|
else
|
|
{
|
|
assert (0);
|
|
}
|
|
}
|
|
|
|
// returns the index of the current name on the top of the name stack
|
|
size_t CrySizerImpl::getCurrentName() const
|
|
{
|
|
assert(!m_stackNames.empty());
|
|
return m_stackNames.empty() ? 0 : m_stackNames.back();
|
|
}
|
|
|
|
|
|
|
|
// searches for the name in the name array; adds the name if it's not there and returns the index
|
|
size_t CrySizerImpl::getNameIndex(size_t nParent, const char* szComponentName)
|
|
{
|
|
NameArray::const_iterator it = m_arrNames.begin(), itEnd = it + m_arrNames.size();
|
|
for (; it != itEnd; ++it)
|
|
{
|
|
#if defined(LINUX)
|
|
if (!strcasecmp(it->strName.c_str(), szComponentName) && it->nParent == nParent)
|
|
#else
|
|
if (!strcmp(it->strName.c_str(), szComponentName) && it->nParent == nParent)
|
|
#endif
|
|
{
|
|
return (size_t)(it - m_arrNames.begin());//it-m_arrNames.begin();
|
|
}
|
|
}
|
|
|
|
size_t nNewName = m_arrNames.size();
|
|
m_arrNames.resize(nNewName + 1);
|
|
|
|
m_arrNames[nNewName].assign(szComponentName, nParent);
|
|
|
|
m_arrNames[nParent].arrChildren.push_back(nParent);
|
|
|
|
return nNewName;
|
|
}
|
|
|
|
static NullResCollector s_nullCollector;
|
|
|
|
IResourceCollector* CrySizerImpl::GetResourceCollector()
|
|
{
|
|
return m_pResourceCollector != 0 ? m_pResourceCollector : &s_nullCollector;
|
|
}
|
|
|
|
void CrySizerImpl::Reset()
|
|
{
|
|
clear();
|
|
|
|
m_nTotalSize = 0;
|
|
|
|
//m_arrNames.resize(0);
|
|
//m_arrNames.push_back("TOTAL"); // the default name, with index 0
|
|
//m_LastObject.clear();
|
|
////m_nFlags;
|
|
//m_nTotalSize=0;
|
|
//if (m_pResourceCollector)
|
|
//{
|
|
// m_pResourceCollector->Reset();
|
|
//}
|
|
//m_setObjects->clear();
|
|
//m_stackNames.resize(0);
|
|
//m_stackNames.push_back(0);
|
|
}
|
|
|
|
|
|
// adds an object identified by the unique pointer (it needs not be
|
|
// the actual object position in the memory, though it would be nice,
|
|
// but it must be unique throughout the system and unchanging for this object)
|
|
// RETURNS: true if the object has actually been added (for the first time)
|
|
// and calculated
|
|
bool CrySizerImpl::AddObject (const void* pIdentifier, size_t sizeBytes, int nCount)
|
|
{
|
|
if (!pIdentifier || !sizeBytes)
|
|
{
|
|
return false; // we don't add the NULL objects
|
|
}
|
|
Object NewObject(pIdentifier, sizeBytes, getCurrentName());
|
|
|
|
// check if the last object was the same
|
|
if (NewObject == m_LastObject)
|
|
{
|
|
assert (m_LastObject.nSize == sizeBytes);
|
|
return false;
|
|
}
|
|
|
|
ObjectSet& rSet = m_setObjects[getHash(pIdentifier)];
|
|
ObjectSet::iterator it = rSet.find (NewObject);
|
|
if (it == rSet.end())
|
|
{
|
|
// there's no such object in the map, add it
|
|
rSet.insert (NewObject);
|
|
ComponentName& CompName = m_arrNames[getCurrentName()];
|
|
CompName.numObjects += nCount;
|
|
CompName.sizeObjects += sizeBytes;
|
|
|
|
m_nTotalSize += sizeBytes;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Object* pObj = const_cast<Object*>(&(*it));
|
|
|
|
// if we do an heap check, don't accept the same object twice
|
|
if (sizeBytes != pObj->nSize)
|
|
{
|
|
// if the following assert fails:
|
|
// assert (0);
|
|
// .. it means we have one object that's added two times with different sizes; that's screws up the whole idea
|
|
// we assume there are two different objects that are for some reason assigned the same id
|
|
pObj->nSize += sizeBytes; // anyway it's an invalid situation
|
|
ComponentName& CompName = m_arrNames[getCurrentName()];
|
|
CompName.sizeObjects += sizeBytes;
|
|
return true; // yes we added the object, though there were an error condition
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
size_t CrySizerImpl::GetObjectCount()
|
|
{
|
|
size_t count = m_stackNames.size();
|
|
for (int i = 0; i < g_nHashSize; i++)
|
|
{
|
|
count += m_setObjects[i].size();
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
// finalizes data collection, should be called after all objects have been added
|
|
void CrySizerImpl::End()
|
|
{
|
|
// clean up the totals of each name
|
|
int i;
|
|
for (i = 0; i < m_arrNames.size(); ++i)
|
|
{
|
|
assert (i == 0 || ((int)m_arrNames[i].nParent < i && m_arrNames[i].nParent >= 0));
|
|
m_arrNames[i].sizeObjectsTotal = m_arrNames[i].sizeObjects;
|
|
}
|
|
|
|
// add the component's size to the total size of the parent.
|
|
// for every component, all their children are put after them in the name array
|
|
// we don't include the root because it doesn't belong to any other parent (nowhere further to add)
|
|
for (i = m_arrNames.size() - 1; i > 0; --i)
|
|
{
|
|
// the parent's total size is increased by the _total_ size (already calculated) of this object
|
|
m_arrNames[m_arrNames[i].nParent].sizeObjectsTotal += m_arrNames[i].sizeObjectsTotal;
|
|
}
|
|
}
|
|
|
|
|
|
void CrySizerImpl::clear()
|
|
{
|
|
for (unsigned i = 0; i < g_nHashSize; ++i)
|
|
{
|
|
m_setObjects[i].clear();
|
|
}
|
|
|
|
m_arrNames.clear();
|
|
m_arrNames.push_back("TOTAL"); // the default name, with index 0
|
|
m_stackNames.clear();
|
|
m_stackNames.push_back(0);
|
|
m_LastObject.pId = NULL;
|
|
|
|
if (m_pResourceCollector)
|
|
{
|
|
m_pResourceCollector->Reset();
|
|
}
|
|
}
|
|
|
|
// hash function for an address; returns value 0..1<<g_nHashSize
|
|
unsigned CrySizerImpl::getHash (const void* pId)
|
|
{
|
|
//return (((unsigned)pId) >> 4) & (g_nHashSize-1);
|
|
|
|
// pseudorandomizing transform
|
|
ldiv_t Qrem = (ldiv_t)ldiv(((uint32)(UINT_PTR)pId >> 2), 127773);
|
|
Qrem.rem = 16807 * Qrem.rem - 2836 * Qrem.quot;
|
|
if (Qrem.rem < 0)
|
|
{
|
|
Qrem.rem += 2147483647; // 0x7FFFFFFF
|
|
}
|
|
return ((unsigned)Qrem.rem) & (g_nHashSize - 1);
|
|
}
|
|
unsigned CrySizerImpl::GetDepthLevel(unsigned nCurrent)
|
|
{
|
|
uint32 nDepth = 0;
|
|
nCurrent = m_arrNames[nCurrent].nParent;
|
|
while (nCurrent != 0)
|
|
{
|
|
nDepth++;
|
|
nCurrent = m_arrNames[nCurrent].nParent;
|
|
}
|
|
return nDepth;
|
|
}
|
|
|