server/game/src/profiler.h

275 lines
5.8 KiB
C
Raw Normal View History

2022-03-05 12:44:06 +02:00
#ifndef __INC_METIN_II_GAME_PROFILER_H__
#define __INC_METIN_II_GAME_PROFILER_H__
#include <unordered_map>
2022-03-05 12:44:06 +02:00
class CProfiler : public singleton<CProfiler>
{
public:
enum
{
STACK_DATA_MAX_NUM = 64,
};
public:
typedef struct SProfileStackData
{
int iCallStep;
int iStartTime;
int iEndTime;
2022-03-05 12:44:06 +02:00
std::string strName;
} TProfileStackData;
typedef struct SProfileAccumData
{
int iStartTime;
int iCallingCount;
int iCollapsedTime;
int iDepth;
std::string strName;
} TProfileAccumData;
struct stringhash
{
size_t operator () (const std::string& str) const
{
const unsigned char * s = (const unsigned char *) str.c_str();
const unsigned char * end = s + str.size();
size_t h = 0;
while (s < end)
{
h *= 16777619;
h ^= (unsigned char) *(unsigned char *) (s++);
}
return h;
}
};
typedef std::unordered_map<std::string, TProfileAccumData> TProfileAccumDataMap;
2022-03-05 12:44:06 +02:00
public:
CProfiler()
{
Initialize();
}
virtual ~CProfiler()
{
}
void Initialize()
{
m_iAccumDepth = 0;
m_ProfileStackDataCount = 0;
m_iCallStep = 0;
}
void Clear()
{
TProfileAccumDataMap::iterator it = m_ProfileAccumDataMap.begin();
for (; it != m_ProfileAccumDataMap.end(); ++it)
{
TProfileAccumData & rData = it->second;
rData.iCallingCount = 0;
rData.iCollapsedTime = 0;
}
Initialize();
}
void Push(const char * c_szName)
{
assert(m_ProfileStackDataCount < STACK_DATA_MAX_NUM);
TProfileStackData & rProfileStackData = m_ProfileStackDatas[m_ProfileStackDataCount++];
rProfileStackData.iCallStep = m_iCallStep;
rProfileStackData.iStartTime = get_dword_time();
rProfileStackData.strName = c_szName;
++m_iCallStep;
}
void Pop(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
{
assert(!"The name doesn't exist");
return;
}
pProfileStackData->iEndTime = get_dword_time();
--m_iCallStep;
}
__inline void PushAccum(const char * c_szName)
{
TProfileAccumDataMap::iterator it = m_ProfileAccumDataMap.find(c_szName);
if (it == m_ProfileAccumDataMap.end())
{
TProfileAccumData ProfileAccumData;
ProfileAccumData.iCollapsedTime = 0;
ProfileAccumData.iCallingCount = 0;
ProfileAccumData.strName = c_szName;
ProfileAccumData.iDepth = m_iAccumDepth;
m_ProfileAccumDataMap.insert(TProfileAccumDataMap::value_type(c_szName, ProfileAccumData));
it = m_ProfileAccumDataMap.find(c_szName);
m_vec_Accum.push_back(&it->second);
}
TProfileAccumData & rData = it->second;
rData.iStartTime = get_dword_time();
++m_iAccumDepth;
}
__inline void PopAccum(const char * c_szName)
{
TProfileAccumDataMap::iterator it = m_ProfileAccumDataMap.find(c_szName);
if (it == m_ProfileAccumDataMap.end())
return;
TProfileAccumData & rData = it->second;
rData.iCollapsedTime += get_dword_time() - rData.iStartTime;
++rData.iCallingCount;
--m_iAccumDepth;
}
void Log(const char * c_pszFileName)
{
FILE * fp = fopen(c_pszFileName, "w");
if (!fp)
return;
Print(fp);
fclose(fp);
}
void Print(FILE * fp = stderr)
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
TProfileStackData & rProfileStackData = m_ProfileStackDatas[i];
for (int i = 0; i < rProfileStackData.iCallStep; ++i)
fprintf(fp, "\t");
fprintf(fp, "%-24s: %d\n", rProfileStackData.strName.c_str(), rProfileStackData.iEndTime - rProfileStackData.iStartTime);
2022-03-05 12:44:06 +02:00
}
fprintf(fp, "Name Call/Load Ratio\n");
std::string stLine;
for (DWORD k = 0; k < m_vec_Accum.size(); ++k)
{
TProfileAccumData * p = m_vec_Accum[k];
stLine.assign(p->iDepth * 5, ' ');
stLine += p->strName;
fprintf(fp, "%-30s %10d/%-10d %.2f\n",
stLine.c_str(),
p->iCallingCount, p->iCollapsedTime,
p->iCallingCount != 0 ? (float) p->iCollapsedTime / p->iCallingCount : 0.0f);
}
}
void PrintOneStackData(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
return;
sys_log(0, "%-10s: %3d", pProfileStackData->strName.c_str(), pProfileStackData->iEndTime - pProfileStackData->iStartTime);
}
void PrintOneAccumData(const char * c_szName)
{
TProfileAccumDataMap::iterator it = m_ProfileAccumDataMap.find(c_szName);
if (it == m_ProfileAccumDataMap.end())
return;
TProfileAccumData & rData = it->second;
sys_log(0, "%-10s : [CollapsedTime : %3d] / [CallingCount : %3d]",
rData.strName.c_str(),
rData.iCollapsedTime,
rData.iCallingCount);
}
protected:
bool GetProfileStackDataPointer(const char * c_szName, TProfileStackData ** ppProfileStackData)
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
if (0 == m_ProfileStackDatas[i].strName.compare(c_szName))
{
*ppProfileStackData = &m_ProfileStackDatas[i];
return true;
}
}
return false;
}
protected:
// Profile Stack Data
int m_ProfileStackDataCount;
TProfileStackData m_ProfileStackDatas[STACK_DATA_MAX_NUM];
// Profile Accum Data
TProfileAccumDataMap m_ProfileAccumDataMap;
std::vector<TProfileAccumData *> m_vec_Accum;
int m_iAccumDepth;
int m_iCallStep;
};
template <typename T> class CProfileUnit
{
public:
CProfileUnit(const char * c_pszName)
{
m_stName = c_pszName;
CProfiler::instance().PushAccum(m_stName.c_str());
m_bPushed = true;
}
~CProfileUnit()
{
if (m_bPushed)
Pop();
}
void Pop()
{
if (m_bPushed)
{
CProfiler::instance().PopAccum(m_stName.c_str());
m_bPushed = false;
}
}
std::string m_stName;
bool m_bPushed;
};
#define PROF_UNIT CProfileUnit<void>
#endif