nulldc-360/nullDC/profiler/profiler.cpp
2022-02-11 13:27:24 +01:00

236 lines
No EOL
5.2 KiB
C++

/*
--nullDC Runtime profiler--
The runtime profiler is a mini-sampling profiler.
A background thread collects samples of EIP , and it determines
in witch dll the EIP points to.After we have some samples (MAX_TICK_COUNT)
we print the usage statistics on the console and reset the counters
*/
#include "profiler.h"
#include "dc\sh4\rec_v1\blockmanager.h"
#include "plugins/plugin_manager.h"
#include <windows.h>
#define MAX_TICK_COUNT 800
prof_info profile_info;
cThread* prof_thread;
u32 THREADCALL ProfileThead(void* param);
extern s32 rtc_cycles;
struct Module
{
u32 base;
u32 end;
u32 len;
bool Inside(u32 val) { return val>=base && val<=end; }
void FromAddress(void* ptr)
{
char filename[512];
char filename2[512];
static void* ptr_old=0;
if (ptr_old==ptr)
return;
ptr_old=ptr;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(ptr,&mbi,sizeof(mbi));
base=(u32)mbi.AllocationBase;
GetModuleFileName((HMODULE)mbi.AllocationBase,filename,512);
len=(u8*)mbi.BaseAddress-(u8*)mbi.AllocationBase+mbi.RegionSize;
for(;;)
{
VirtualQuery(((u8*)base)+len,&mbi,sizeof(mbi));
if (!(mbi.Type&MEM_IMAGE))
break;
if (!GetModuleFileName((HMODULE)mbi.AllocationBase,filename2,512))
break;
if (wcscmp(filename,filename2)!=0)
break;
len+=mbi.RegionSize;
}
end=base+len-1;
}
void FromValues(void* b,u32 s)
{
base= (u32)b;
len=s;
end=base+len-1;
}
};
Module main_mod,aica_mod,arm_mod,pvr_mod,gdrom_mod,dyna_mod;
u64 oldcycles;
u64 CycleDiff()
{
u64 oo=oldcycles;
oldcycles=200*1000*1000-rtc_cycles+(u64)settings.dreamcast.RTC*200*1000*1000;
return oldcycles-oo;
}
bool RunProfiler;
bool TBP_Enabled;
bool Reset_Stats;
void init_ProfilerModules()
{
main_mod.FromAddress(init_ProfilerModules);
aica_mod.FromAddress(libAICA.Load);
arm_mod.FromAddress(libARM.Load);
pvr_mod.FromAddress(libPvr.Load);
gdrom_mod.FromAddress(libGDR.Load);
dyna_mod.FromValues(DynarecCache,DynarecCacheSize);
}
void init_Profiler(void* param)
{
//Clear profile info
memset(&profile_info,0,sizeof(prof_info));
RunProfiler=true;
prof_thread = new cThread(ProfileThead,param);
SetThreadPriority(prof_thread->hThread,THREAD_PRIORITY_TIME_CRITICAL);
//prof_thread->Start();
}
void start_Profiler()
{
init_ProfilerModules();
TBP_Enabled=true;
CycleDiff();
if (prof_thread) prof_thread->Start();
}
void stop_Profiler()
{
TBP_Enabled = false;
Reset_Stats = true;
if (prof_thread) prof_thread->Suspend();
}
void term_Profiler()
{
RunProfiler=false;
prof_thread->Start();//make sure it is started
prof_thread->WaitToEnd(-1);
delete prof_thread;
//Clear profile info
memset(&profile_info,0,sizeof(prof_info));
}
extern void* Dynarec_Mainloop_no_update;
extern void* Dynarec_Mainloop_do_update;
extern void* Dynarec_Mainloop_end;
void AnalyseTick(u32 pc,prof_info* to)
{
if (aica_mod.Inside(pc))
{
to->current_count[AICA_TC]++;
}
else if (arm_mod.Inside(pc))
{
to->current_count[ARM_TC]++;
}
else if (pvr_mod.Inside(pc))
{
to->current_count[GFX_TC]++;
}
else if (gdrom_mod.Inside(pc))
{
to->current_count[GDROM_TC]++;
}
else if (main_mod.Inside(pc))
{
if (pc >= (u32)Dynarec_Mainloop_no_update && pc <= (u32)Dynarec_Mainloop_end)
to->current_count[DYNA_LOOP_TC]++;
else
to->current_count[MAIN_TC]++;
}
else if (dyna_mod.Inside(pc))
{
//dyna_profiler_tick((void*)pc);
to->current_count[DYNA_TC]++;
}
else
to->current_count[REST_TC]++;
}
extern u32 no_interrupts,yes_interrupts;
u32 THREADCALL ProfileThead(void* param)
{
prof_info info;
prof_stats stats;
memset(&info,0,sizeof(prof_info));
memset(&stats,0,sizeof(prof_stats));
CONTEXT cntx;
while(RunProfiler)
{
// Reset max/avg stats
if(Reset_Stats)
{
memset(&stats,0,sizeof(prof_stats));
Reset_Stats = false;
}
//get emulation thread's pc
memset(&cntx,0,sizeof(cntx));
cntx.ContextFlags= CONTEXT_FULL;
{
BOOL test = GetThreadContext((HANDLE)param,&cntx);
verify(test);
}
//count ticks
info.total_tc++;
AnalyseTick(cntx.Eip,&info);
//Update Stats if needed
if (info.total_tc>MAX_TICK_COUNT)
{
char temp[1024];
memcpy(&profile_info,&info,sizeof(prof_info));
memset(&info,0,sizeof(prof_info));
profile_info.ToText(temp, &stats);
wprintf(_T("%s \n"),temp);
if ( yes_interrupts+no_interrupts)
{
double cd=profile_info.cd/(200*1000*1000.0);
dlog("Interrupts : %.0f yes, %.0f no, %.2f ratio\n",yes_interrupts/cd,no_interrupts/cd,100*yes_interrupts/(float)(yes_interrupts+no_interrupts)/cd);
yes_interrupts=no_interrupts=0;
}
init_ProfilerModules();
}
//Sleep , so we dont realy use the cpu much
Sleep(1);
}
//CloseHandle((HANDLE)param);
return 0;
}
int percent(int tick, int total)
{
if (total == 0) return 0.0f;
else return (tick*10000)/total; // (tick*100.0f)/(float)total;
}
int effsceas(int tick, int cycleDif)
{
if (tick == 0) return 0.0f;
else return (int)(cycleDif/(double)tick/1000.0/20.0); // (float)(cycleDif/(double)tick/1000.0/1000.0/20.0);
}