Files
FC1/CrySystem/CrySizerStats.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

364 lines
11 KiB
C++

#include "stdafx.h"
#include "ILog.h"
#include "ITimer.h"
#include "ISystem.h"
#include "IConsole.h"
#include "IRenderer.h"
#include "Font.h"
#include "CrySizerImpl.h"
#include "CrySizerStats.h"
CrySizerStatsBuilder::CrySizerStatsBuilder (CrySizerImpl* pSizer, int nMinSubcomponentBytes):
m_pSizer (pSizer),
m_nMinSubcomponentBytes (nMinSubcomponentBytes < 0 || nMinSubcomponentBytes > 0x10000000 ? 0 : nMinSubcomponentBytes)
{
}
// creates the map of names from old (in the sizer Impl) to new (in the Stats)
void CrySizerStatsBuilder::processNames()
{
size_t numCompNames = m_pSizer->m_arrNames.size();
m_pStats->m_arrComponents.reserve (numCompNames);
m_pStats->m_arrComponents.clear();
m_mapNames.resize (numCompNames, -1);
// add all root objects
addNameSubtree(0,0);
}
//////////////////////////////////////////////////////////////////////////
// given the name in the old system, adds the subtree of names to the
// name map and components. In case all the subtree is empty, returns false and
// adds nothing
size_t CrySizerStatsBuilder::addNameSubtree (unsigned nDepth, size_t nName)
{
assert (nName < m_pSizer->m_arrNames.size());
CrySizerImpl::ComponentName& rCompName = m_pSizer->m_arrNames[nName];
size_t sizeObjectsTotal = rCompName.sizeObjectsTotal;
if (sizeObjectsTotal <= m_nMinSubcomponentBytes)
return sizeObjectsTotal; // the subtree didn't pass
// the index of the component in the stats object (sorted by the depth-first traverse order)
size_t nNewName = m_pStats->m_arrComponents.size();
m_pStats->m_arrComponents.resize (nNewName+1);
Component& rNewComp = m_pStats->m_arrComponents[nNewName];
rNewComp.strName = rCompName.strName;
rNewComp.nDepth = nDepth;
rNewComp.numObjects = rCompName.numObjects;
rNewComp.sizeBytes = rCompName.sizeObjects;
rNewComp.sizeBytesTotal = sizeObjectsTotal;
m_mapNames[nName] = nNewName;
// find the immediate children and sort them by their total size
typedef std::map<size_t,size_t> UintUintMap;
UintUintMap mapSizeName; // total size -> child index (name in old indexation)
for (size_t i = nName + 1; i < m_pSizer->m_arrNames.size(); ++i)
{
CrySizerImpl::ComponentName& rChild = m_pSizer->m_arrNames[i];
if (rChild.nParent == nName && rChild.sizeObjectsTotal > m_nMinSubcomponentBytes)
mapSizeName.insert (UintUintMap::value_type(rChild.sizeObjectsTotal,i));
}
// add the sorted components
/*
for (unsigned i = nName + 1; i < m_pSizer->m_arrNames.size(); ++i)
if (m_pSizer->m_arrNames[i].nParent == nName)
addNameSubtree(nDepth+1,i);
*/
for (UintUintMap::reverse_iterator it = mapSizeName.rbegin(); it != mapSizeName.rend(); ++it)
{
addNameSubtree(nDepth + 1, it->second);
}
return sizeObjectsTotal;
}
//////////////////////////////////////////////////////////////////////////
// creates the statistics out of the given CrySizerImpl into the given CrySizerStats
// Maps the old to new names according to the depth-walk tree rule
void CrySizerStatsBuilder::build (CrySizerStats* pStats)
{
m_pStats = pStats;
m_mapNames.clear();
processNames();
m_pSizer->clear();
pStats->refresh();
pStats->m_nAgeFrames = 0;
}
//////////////////////////////////////////////////////////////////////////
// constructs the statistics based on the given cry sizer
CrySizerStats::CrySizerStats (CrySizerImpl* pCrySizer)
{
CrySizerStatsBuilder builder (pCrySizer);
builder.build(this);
}
CrySizerStats::CrySizerStats ()
{
}
// if there is already such name in the map, then just returns the index
// of the compoentn in the component array; otherwise adds an entry to themap
// and to the component array nad returns its index
CrySizerStatsBuilder::Component& CrySizerStatsBuilder::mapName (unsigned nName)
{
assert (m_mapNames[nName] != -1);
return m_pStats->m_arrComponents[m_mapNames[nName]];
/*
IdToIdMap::iterator it = m_mapNames.find (nName);
if (it == m_mapNames.end())
{
unsigned nNewName = m_arrComponents.size();
m_mapNames.insert (IdToIdMap::value_type(nName, nNewName));
m_arrComponents.resize(nNewName + 1);
m_arrComponents[nNewName].strName.swap(m_pSizer->m_arrNames[nName]);
return m_arrComponents.back();
}
else
{
assert (it->second < m_arrComponents.size());
return m_arrComponents[it->second];
}
*/
}
// refreshes the statistics built after the component array is built
void CrySizerStats::refresh()
{
m_nMaxNameLength = 0;
for (size_t i = 0; i < m_arrComponents.size(); ++i)
{
size_t nLength = m_arrComponents[i].strName.length()+m_arrComponents[i].nDepth;
if (nLength > m_nMaxNameLength)
m_nMaxNameLength = nLength;
}
}
bool CrySizerStats::Component::GenericOrder::operator () (const Component& left, const Component& right)const
{
return left.strName < right.strName;
}
CrySizerStatsRenderer::CrySizerStatsRenderer (ISystem* pSystem, CrySizerStats* pStats, unsigned nMaxSubcomponentDepth, int nMinSubcomponentBytes):
m_pStats(pStats),
m_pRenderer(pSystem->GetIRenderer()),
m_pLog (pSystem->GetILog()),
m_pFont (pSystem->GetIConsole()->GetFont()),
m_nMinSubcomponentBytes (nMinSubcomponentBytes < 0 || nMinSubcomponentBytes > 0x10000000 ? 0x8000 : nMinSubcomponentBytes),
m_nMaxSubcomponentDepth (nMaxSubcomponentDepth)
{
}
void CrySizerStatsRenderer::render(bool bRefreshMark)
{
if (!m_pStats->size())
return;
int x,y,dx,dy;
m_pRenderer->GetViewport(&x,&y,&dx,&dy);
// left coordinate of the text
unsigned nNameWidth = (unsigned)(m_pStats->getMaxNameLength()+1);
if (nNameWidth < 25)
nNameWidth = 25;
float fCharScaleX = 0.375f, fCharScaleY = 0.5f;
float fCharSizeX = m_pFont->m_charsize*fCharScaleX, fCharSizeY = m_pFont->m_charsize*fCharScaleY;
float fLeft = 0;
float fTop = 48;
float fVStep = 10;
#ifdef _XBOX
fTop = 20;
#endif
m_pRenderer->WriteXY (m_pFont, (int)fLeft, (int)(fTop), fCharScaleX, fCharScaleY, 0.9f,0.85f,1,0.85f,
"%-*s TOTAL partial count",nNameWidth,bRefreshMark?"Memory usage (refresh*)":"Memory usage (refresh )");
m_pRenderer->WriteXY (m_pFont, (int)fLeft, (int)(fTop + fVStep*0.25f), fCharScaleX, fCharScaleY, 0.85f,0.9f,1,0.85f,
"%*s _____ _______ _____",nNameWidth,"");
unsigned nSubgroupDepth = 1;
// different colors used to paint the statistics subgroups
// a new statistic subgroup starts with a new subtree of depth <= specified
float fGray = 0;//0.45f;
float fLightGray = 0.5f;//0.8f;
float fColors[] =
{
fLightGray,fLightGray,fGray, 1,
1,1,1,1,
fGray,1,1,1,
1,fGray,1,1,
1,1,fGray,1,
fGray,fLightGray,1,1,
fGray,1,fGray,1,
1,fGray,fGray,1
};
float*pColor = fColors;
for (unsigned i = 0; i < m_pStats->size(); ++i)
{
const Component& rComp = (*m_pStats)[i];
if (rComp.nDepth <= nSubgroupDepth)
{
//switch the color
pColor += 4;
if (pColor >= fColors + sizeof(fColors)/sizeof(fColors[0]))
pColor = fColors;
fTop += fVStep*(0.333333f + (nSubgroupDepth - rComp.nDepth) * 0.15f);
}
if (rComp.sizeBytesTotal <= m_nMinSubcomponentBytes || rComp.nDepth > m_nMaxSubcomponentDepth)
continue;
fTop += fVStep;
//m_pRenderer->WriteXY(m_pFont, (int)fLeft+fCharSizeX*(nNameWidth-rComp.strName.length()), (int)fTop, fCharScale, fCharScale, 1,1,1,1,
// "%s:%7.3f",rComp.strName.c_str(), rComp.getSizeMBytes());
char szDepth[32] = " ..............................";
if (rComp.nDepth < sizeof(szDepth))
szDepth[rComp.nDepth] = '\0';
char szSize[32];
if (rComp.sizeBytes > 0)
{
if (rComp.sizeBytesTotal > rComp.sizeBytes)
sprintf (szSize, "%7.3f %7.3f", rComp.getTotalSizeMBytes(), rComp.getSizeMBytes());
else
sprintf (szSize, " %7.3f", rComp.getSizeMBytes());
}
else
{
assert (rComp.sizeBytesTotal > 0);
sprintf (szSize, "%7.3f ", rComp.getTotalSizeMBytes());
}
char szCount[16];
#ifdef _DEBUG
if (rComp.numObjects)
sprintf (szCount, "%8u", rComp.numObjects);
else
#endif
szCount[0] = '\0';
m_pRenderer->WriteXY(m_pFont, (int)fLeft, (int)(fTop), fCharScaleX, fCharScaleY, pColor[0],pColor[1],pColor[2],pColor[3],
"%s%-*s:%s%s",szDepth, nNameWidth-rComp.nDepth,rComp.strName.c_str(), szSize, szCount);
}
fTop += 0.25f*fVStep;
m_pRenderer->WriteXY(m_pFont, (int)fLeft, (int)(fTop), fCharScaleX, fCharScaleY, fLightGray,fLightGray,fLightGray,1,
"%-*s %s",nNameWidth,"___________________________", "________________");
fTop += fVStep;
const char* szOverheadNames[CrySizerStats::g_numTimers] =
{
".Collection",
".Transformation",
".Cleanup"
};
bool bOverheadsHeaderPrinted = false;
for (unsigned i = 0; i < CrySizerStats::g_numTimers; ++i)
{
float fTime = m_pStats->getTime(i);
if (fTime < 20)
continue;
// print the header
if (!bOverheadsHeaderPrinted)
{
m_pRenderer->WriteXY(m_pFont, (int)fLeft, (int)(fTop), fCharScaleX, fCharScaleY, fLightGray,fLightGray,fLightGray,1,
"%-*s",nNameWidth,"Overheads");
fTop += fVStep;
bOverheadsHeaderPrinted = true;
}
m_pRenderer->WriteXY(m_pFont, (int)fLeft, (int)(fTop), fCharScaleX, fCharScaleY, fLightGray,fLightGray,fLightGray,1,
"%-*s:%7.1f ms",nNameWidth,szOverheadNames[i], fTime);
fTop += fVStep;
}
}
void CrySizerStatsRenderer::dump()
{
if (!m_pStats->size())
return;
unsigned nNameWidth = (unsigned)(m_pStats->getMaxNameLength()+1);
// left coordinate of the text
m_pLog->LogToFile ("Memory Statistics:");
m_pLog->LogToFile("%-*s TOTAL partial count",nNameWidth,"");
unsigned nSubgroupDepth = 1;
// different colors used to paint the statistics subgroups
// a new statistic subgroup starts with a new subtree of depth <= specified
for (unsigned i = 0; i < m_pStats->size(); ++i)
{
const Component& rComp = (*m_pStats)[i];
if (rComp.sizeBytesTotal <= m_nMinSubcomponentBytes || rComp.nDepth > m_nMaxSubcomponentDepth)
continue;
char szDepth[32] = " ..............................";
if (rComp.nDepth < sizeof(szDepth))
szDepth[rComp.nDepth] = '\0';
char szSize[32];
if (rComp.sizeBytes > 0)
{
if (rComp.sizeBytesTotal > rComp.sizeBytes)
sprintf (szSize, "%7.3f %7.3f", rComp.getTotalSizeMBytes(), rComp.getSizeMBytes());
else
sprintf (szSize, " %7.3f", rComp.getSizeMBytes());
}
else
{
assert (rComp.sizeBytesTotal > 0);
sprintf (szSize, "%7.3f ", rComp.getTotalSizeMBytes());
}
char szCount[16];
if (rComp.numObjects)
sprintf (szCount, "%8u", rComp.numObjects);
else
szCount[0] = '\0';
m_pLog->LogToFile ("%s%-*s:%s%s",szDepth, nNameWidth-rComp.nDepth,rComp.strName.c_str(), szSize, szCount);
}
}
void CrySizerStats::startTimer(unsigned nTimer, ITimer* pTimer)
{
assert (nTimer < g_numTimers);
m_fTime[nTimer] = pTimer->GetAsyncCurTime();
}
void CrySizerStats::stopTimer(unsigned nTimer, ITimer* pTimer)
{
assert (nTimer < g_numTimers);
m_fTime[nTimer] = 1000*(pTimer->GetAsyncCurTime() - m_fTime[nTimer]);
}