pureikyubu/SRC/UI/UserProfiler.cpp
2020-05-03 19:54:09 +03:00

164 lines
4.8 KiB
C++

// emulator is profiled every real-time second.
// status bar should present and contain at least two sections :
// first (largest) is used for frame timing percentage
// second (small) is used for FPS
#include "pch.h"
//
// local data
//
static BOOL Profiler; // uservar
static int64_t startTime, stopTime;
static int64_t gfxStartTime, gfxStopTime;
static int64_t sfxStartTime, sfxStopTime;
static int64_t dvdStartTime, dvdStopTime;
static int64_t cpuTime, gfxTime, sfxTime, dvdTime;
static int64_t ONE_SECOND;
static DWORD checkTime;
// ---------------------------------------------------------------------------
// precede timer utility
static void __fastcall MyReadTimeStampCounter(int64_t *ptr)
{
*ptr = __rdtsc();
}
// get average CPU speed (in MHz)
static float GetClockSpeed()
{
int i = 0;
LARGE_INTEGER t0, t1, perfFreq;
int64_t stamp0 = 0, stamp1 = 0;
int64_t diffStamp, diffTicks;
if(QueryPerformanceFrequency(&perfFreq))
{
while(i < 3)
{
i++;
QueryPerformanceCounter(&t0);
t1.LowPart = t0.LowPart;
t1.HighPart = t0.HighPart;
while((t1.LowPart - t0.LowPart) < 50)
{
QueryPerformanceCounter(&t1);
MyReadTimeStampCounter(&stamp0);
}
t0.LowPart = t1.LowPart;
t0.HighPart = t1.HighPart;
while((t1.LowPart - t0.LowPart) < 1000)
{
QueryPerformanceCounter(&t1);
MyReadTimeStampCounter(&stamp1);
}
}
diffStamp = stamp1 - stamp0;
diffTicks = t1.LowPart - t0.LowPart;
diffTicks *= 100000;
diffTicks = diffTicks / (perfFreq.LowPart / 10);
return (float)((float)diffStamp / (float)diffTicks);
}
else return 0.0f;
}
// ---------------------------------------------------------------------------
void OpenProfiler(bool enable)
{
// load user variable
Profiler = enable;
// status window should be valid
if(!IsWindow(wnd.hStatusWindow)) Profiler = FALSE;
// high-precision timer should exist
LARGE_INTEGER freq;
if(!QueryPerformanceFrequency(&freq)) Profiler = FALSE;
// reset counters
if(Profiler)
{
cpuTime = gfxTime = sfxTime = dvdTime = 0;
ONE_SECOND = (int64_t)((double)GetClockSpeed() * (double)1000000.0);
MyReadTimeStampCounter(&startTime);
}
checkTime = GetTickCount();
}
// update after every fifo call
void UpdateProfiler()
{
TCHAR gcTime[256];
if(Profiler)
{
TCHAR buf[128], mips[128];
if((GetTickCount() - checkTime) < 1000) return;
checkTime = GetTickCount();
// measure time
MyReadTimeStampCounter(&stopTime);
int64_t total = stopTime - startTime;
cpuTime = total - gfxTime - sfxTime - dvdTime;
int64_t cur; MyReadTimeStampCounter(&cur);
int64_t diff = cur - startTime;
// frames per second
_stprintf_s(buf, _countof(buf) - 1, _T("FPS:%zi"), vi.frames);
vi.frames = 0;
SetStatusText(STATUS_ENUM::Fps, buf);
// MIPS
_stprintf_s (mips, _countof(mips) - 1, _T("%.1f"), (float)Gekko::Gekko->GetOpcodeCount() / 1000000.0f);
Gekko::Gekko->ResetOpcodeCount();
// update status bar
{
_stprintf_s (buf, _countof(buf) - 1, _T("mips:%s core:%-2.1f video:%-2.1f sound:%-2.1f dvd:%-2.1f"),
mips,
(double)cpuTime * 100 / (double)total,
(double)gfxTime * 100 / (double)total,
(double)sfxTime * 100 / (double)total,
(double)dvdTime * 100 / (double)total
);
SetStatusText(STATUS_ENUM::Progress, buf);
}
// reset counters
cpuTime = gfxTime = sfxTime = dvdTime = 0;
MyReadTimeStampCounter(&startTime);
// show system time
HLE::OSTimeFormat(gcTime, Gekko::Gekko->GetTicks(), false);
SetStatusText(STATUS_ENUM::Time, gcTime);
}
}
// ---------------------------------------------------------------------------
// profilers set
void BeginProfileGfx() { if(Profiler) MyReadTimeStampCounter(&gfxStartTime); }
void EndProfileGfx() { if(Profiler) { MyReadTimeStampCounter(&gfxStopTime);
gfxTime += gfxStopTime - gfxStartTime; } }
void BeginProfileSfx() { if(Profiler) MyReadTimeStampCounter(&sfxStartTime); }
void EndProfileSfx() { if(Profiler) { MyReadTimeStampCounter(&sfxStopTime);
sfxTime += sfxStopTime - sfxStartTime; } }
void BeginProfileDVD() { if(Profiler) MyReadTimeStampCounter(&dvdStartTime); }
void EndProfileDVD() { if(Profiler) { MyReadTimeStampCounter(&dvdStopTime);
dvdTime += dvdStopTime - dvdStartTime; } }