project64/Source/Project64-core/N64System/ProfilingClass.cpp

189 lines
6.4 KiB
C++
Raw Normal View History

2012-12-19 09:30:18 +00:00
/****************************************************************************
* *
2015-11-10 05:21:49 +00:00
* Project64 - A Nintendo 64 emulator. *
2012-12-19 09:30:18 +00:00
* http://www.pj64-emu.com/ *
* Copyright (C) 2012 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
#include "stdafx.h"
2015-12-06 09:59:58 +00:00
#include "ProfilingClass.h"
#include <Common/LogClass.h>
enum { MAX_FRAMES = 13 };
2015-12-23 19:51:37 +00:00
CProfiling::CProfiling() :
m_CurrentTimerAddr(Timer_None),
m_CurrentDisplayCount(MAX_FRAMES),
m_StartTimeHi(0),
m_StartTimeLo(0)
{
}
2015-12-23 19:51:37 +00:00
SPECIAL_TIMERS CProfiling::StartTimer(SPECIAL_TIMERS Address)
{
2015-12-23 19:51:37 +00:00
SPECIAL_TIMERS OldTimerAddr = StopTimer();
m_CurrentTimerAddr = Address;
#ifdef _M_IX86
2015-12-06 09:59:58 +00:00
uint32_t HiValue, LoValue;
_asm
{
2015-12-23 19:51:37 +00:00
pushad
rdtsc
mov HiValue, edx
mov LoValue, eax
popad
}
m_StartTimeHi = HiValue;
m_StartTimeLo = LoValue;
#else
2015-12-23 19:51:37 +00:00
g_Notify->BreakPoint(__FILE__, __LINE__);
#endif
2015-12-23 19:51:37 +00:00
return OldTimerAddr;
}
SPECIAL_TIMERS CProfiling::StopTimer() {
2015-12-06 09:59:58 +00:00
uint32_t HiValue, LoValue;
2015-12-23 19:51:37 +00:00
if (m_CurrentTimerAddr == Timer_None) { return m_CurrentTimerAddr; }
#ifdef _M_IX86
2015-12-23 19:51:37 +00:00
_asm {
pushad
rdtsc
mov HiValue, edx
mov LoValue, eax
popad
}
#else
2015-12-23 19:51:37 +00:00
g_Notify->BreakPoint(__FILE__, __LINE__);
#endif
2015-12-23 19:51:37 +00:00
int64_t StopTime = ((uint64_t)HiValue << 32) + (uint64_t)LoValue;
int64_t StartTime = ((uint64_t)m_StartTimeHi << 32) + (uint64_t)m_StartTimeLo;
int64_t TimeTaken = StopTime - StartTime;
2015-12-23 19:51:37 +00:00
PROFILE_ENRTY Entry = m_Entries.find(m_CurrentTimerAddr);
if (Entry != m_Entries.end()) {
Entry->second += TimeTaken;
}
else {
m_Entries.insert(PROFILE_ENRTIES::value_type(m_CurrentTimerAddr, TimeTaken));
}
SPECIAL_TIMERS OldTimerAddr = m_CurrentTimerAddr;
m_CurrentTimerAddr = Timer_None;
return OldTimerAddr;
}
void CProfiling::ShowCPU_Usage() {
int64_t TotalTime, CPU = 0, Alist = 0, Dlist = 0, Idle = 0;
2015-12-23 19:51:37 +00:00
PROFILE_ENRTY Entry;
if (m_CurrentDisplayCount > 0) { m_CurrentDisplayCount -= 1; return; }
m_CurrentDisplayCount = MAX_FRAMES;
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_R4300);
if (Entry != m_Entries.end()) { CPU = Entry->second; }
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_RefreshScreen);
if (Entry != m_Entries.end()) { CPU += Entry->second; }
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_RSP_Dlist);
if (Entry != m_Entries.end()) { Dlist = Entry->second; }
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_UpdateScreen);
if (Entry != m_Entries.end()) { Dlist += Entry->second; }
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_RSP_Alist);
if (Entry != m_Entries.end()) { Alist = Entry->second; }
2015-12-23 19:51:37 +00:00
Entry = m_Entries.find(Timer_Idel);
if (Entry != m_Entries.end()) { Idle = Entry->second; }
2015-12-23 19:51:37 +00:00
TotalTime = CPU + Alist + Dlist + Idle;
2015-12-23 19:51:37 +00:00
g_Notify->DisplayMessage(0, stdstr_f("r4300i: %0.1f%c GFX: %0.1f%c Alist: %0.1f%c Idle: %0.1f%c",
(float)(((double)CPU / (double)TotalTime) * 100), '%',
(float)(((double)Dlist / (double)TotalTime) * 100), '%',
(float)(((double)Alist / (double)TotalTime) * 100), '%',
(float)(((double)Idle / (double)TotalTime) * 100), '%').ToUTF16().c_str());
2015-12-23 19:51:37 +00:00
ResetCounters();
}
void CProfiling::ResetCounters() {
2015-12-23 19:51:37 +00:00
m_Entries.clear();
}
struct TIMER_NAME {
2015-12-23 19:51:37 +00:00
SPECIAL_TIMERS Timer;
char * Name;
};
void CProfiling::GenerateLog() {
2015-12-23 19:51:37 +00:00
stdstr LogFileName;
{
CLog Log;
Log.Open("Profiling.txt");
LogFileName = Log.FileName();
2015-12-23 19:51:37 +00:00
//Get the total time
int64_t TotalTime = 0;
2015-12-23 19:51:37 +00:00
for (PROFILE_ENRTY itemTime = m_Entries.begin(); itemTime != m_Entries.end(); itemTime++) {
TotalTime += itemTime->second;
}
//Create a sortable list of items
std::vector<PROFILE_VALUE *> ItemList;
for (PROFILE_ENRTY Entry = m_Entries.begin(); Entry != m_Entries.end(); Entry++) {
ItemList.push_back(&(*Entry));
}
//sort the list with a basic bubble sort
for (size_t OuterPass = 0; OuterPass < (ItemList.size() - 1); OuterPass++) {
for (size_t InnerPass = 0; InnerPass < (ItemList.size() - 1); InnerPass++) {
if (ItemList[InnerPass]->second < ItemList[InnerPass + 1]->second) {
PROFILE_VALUE * TempPtr = ItemList[InnerPass];
ItemList[InnerPass] = ItemList[InnerPass + 1];
ItemList[InnerPass + 1] = TempPtr;
}
}
}
TIMER_NAME TimerNames[] = {
{ Timer_R4300, "R4300" },
{ Timer_RSP_Dlist, "RSP: Dlist" },
{ Timer_RSP_Alist, "RSP: Alist" },
{ Timer_RSP_Unknown, "RSP: Unknown" },
{ Timer_RefreshScreen, "Refresh Screen" },
{ Timer_UpdateScreen, "Update Screen" },
{ Timer_UpdateFPS, "Update FPS" },
{ Timer_FuncLookup, "Function Lookup" },
{ Timer_Done, "Timer_Done" },
{ Timer_GetBlockInfo, "Timer_GetBlockInfo" },
{ Timer_AnalyseBlock, "Timer_AnalyseBlock" },
{ Timer_CompileBlock, "Timer_CompileBlock" },
{ Timer_CompileDone, "Timer_CompileDone" },
};
for (size_t count = 0; count < ItemList.size(); count++) {
char Buffer[255];
double CpuUsage = ((double)ItemList[count]->second / (double)TotalTime) * 100;
if (CpuUsage <= 0.2) { continue; }
sprintf(Buffer, "Func 0x%08X", ItemList[count]->first);
for (int NameID = 0; NameID < (sizeof(TimerNames) / sizeof(TIMER_NAME)); NameID++) {
if (ItemList[count]->first == TimerNames[NameID].Timer) {
strcpy(Buffer, TimerNames[NameID].Name);
break;
}
}
Log.LogF("%s\t%2.2f", Buffer, CpuUsage);
}
}
ResetCounters();
}