1 |
|
2 |
#include "PrecompiledHeader.h" |
3 |
#include "Utilities/RedtapeWindows.h" |
4 |
|
5 |
#include "SamplProf.h" |
6 |
#include <map> |
7 |
#include <algorithm> |
8 |
|
9 |
using namespace std; |
10 |
|
11 |
DWORD GetModuleFromPtr(IN void* ptr,OUT LPWSTR lpFilename,IN DWORD nSize) |
12 |
{ |
13 |
MEMORY_BASIC_INFORMATION mbi; |
14 |
VirtualQuery(ptr,&mbi,sizeof(mbi)); |
15 |
return GetModuleFileName((HMODULE)mbi.AllocationBase,lpFilename,nSize); |
16 |
} |
17 |
|
18 |
struct Module |
19 |
{ |
20 |
uptr base; |
21 |
uptr end; |
22 |
uptr len; |
23 |
wxString name; |
24 |
u32 ticks; |
25 |
|
26 |
Module(const wxChar* name, const void* ptr) |
27 |
{ |
28 |
if (name!=0) |
29 |
this->name=name; |
30 |
FromAddress(ptr,name==0); |
31 |
ticks=0; |
32 |
} |
33 |
Module(const wxChar* name, const void* b, u32 s) |
34 |
{ |
35 |
this->name=name; |
36 |
FromValues(b,s); |
37 |
ticks=0; |
38 |
} |
39 |
bool operator<(const Module &other) const |
40 |
{ |
41 |
return ticks>other.ticks; |
42 |
} |
43 |
wxString ToString(u32 total_ticks) |
44 |
{ |
45 |
return wxsFormat( L"| %s: %2.2f%% |", name.c_str(), (float)(((double)ticks*100.0) / (double)total_ticks) ); |
46 |
} |
47 |
bool Inside(uptr val) { return val>=base && val<=end; } |
48 |
void FromAddress(const void* ptr,bool getname) |
49 |
{ |
50 |
wxChar filename[512]; |
51 |
wxChar filename2[512]; |
52 |
static const void* ptr_old=0; |
53 |
|
54 |
if (ptr_old==ptr) |
55 |
return; |
56 |
ptr_old=ptr; |
57 |
|
58 |
MEMORY_BASIC_INFORMATION mbi; |
59 |
VirtualQuery(ptr,&mbi,sizeof(mbi)); |
60 |
base=(u32)mbi.AllocationBase; |
61 |
GetModuleFileName((HMODULE)mbi.AllocationBase,filename,512); |
62 |
len=(u8*)mbi.BaseAddress-(u8*)mbi.AllocationBase+mbi.RegionSize; |
63 |
|
64 |
if (getname) |
65 |
{ |
66 |
name=filename; |
67 |
size_t last=name.find_last_of('\\'); |
68 |
last=last==name.npos?0:last+1; |
69 |
name=name.substr(last); |
70 |
} |
71 |
|
72 |
for(;;) |
73 |
{ |
74 |
VirtualQuery(((u8*)base)+len,&mbi,sizeof(mbi)); |
75 |
if (!(mbi.Type&MEM_IMAGE)) |
76 |
break; |
77 |
|
78 |
if (!GetModuleFileName((HMODULE)mbi.AllocationBase,filename2,512)) |
79 |
break; |
80 |
|
81 |
if (wxStrcmp(filename,filename2)!=0) |
82 |
break; |
83 |
len+=mbi.RegionSize; |
84 |
} |
85 |
|
86 |
|
87 |
end=base+len-1; |
88 |
} |
89 |
void FromValues(const void* b,u32 s) |
90 |
{ |
91 |
base= (uptr)b; |
92 |
len=s; |
93 |
end=base+len-1; |
94 |
} |
95 |
}; |
96 |
|
97 |
typedef map<wxString,Module> MapType; |
98 |
|
99 |
static vector<Module> ProfModules; |
100 |
static MapType ProfUnknownHash; |
101 |
|
102 |
static HANDLE hEmuThread = NULL; |
103 |
static HANDLE hMtgsThread = NULL; |
104 |
static HANDLE hProfThread = NULL; |
105 |
|
106 |
static CRITICAL_SECTION ProfModulesLock; |
107 |
|
108 |
static volatile bool ProfRunning=false; |
109 |
|
110 |
static bool _registeredName( const wxString& name ) |
111 |
{ |
112 |
for( vector<Module>::const_iterator |
113 |
iter = ProfModules.begin(), |
114 |
end = ProfModules.end(); iter<end; ++iter ) |
115 |
{ |
116 |
if( iter->name.compare( name ) == 0 ) |
117 |
return true; |
118 |
} |
119 |
return false; |
120 |
} |
121 |
|
122 |
void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) |
123 |
{ |
124 |
if( ProfRunning ) |
125 |
EnterCriticalSection( &ProfModulesLock ); |
126 |
|
127 |
wxString strName( fromUTF8(Name) ); |
128 |
if( !_registeredName( strName ) ) |
129 |
ProfModules.push_back( Module( strName, buff, sz ) ); |
130 |
|
131 |
if( ProfRunning ) |
132 |
LeaveCriticalSection( &ProfModulesLock ); |
133 |
} |
134 |
|
135 |
void ProfilerRegisterSource(const char* Name, const void* function) |
136 |
{ |
137 |
if( ProfRunning ) |
138 |
EnterCriticalSection( &ProfModulesLock ); |
139 |
|
140 |
wxString strName( fromUTF8(Name) ); |
141 |
if( !_registeredName( strName ) ) |
142 |
ProfModules.push_back( Module(strName,function) ); |
143 |
|
144 |
if( ProfRunning ) |
145 |
LeaveCriticalSection( &ProfModulesLock ); |
146 |
} |
147 |
|
148 |
void ProfilerTerminateSource( const char* Name ) |
149 |
{ |
150 |
wxString strName( fromUTF8(Name) ); |
151 |
for( vector<Module>::const_iterator |
152 |
iter = ProfModules.begin(), |
153 |
end = ProfModules.end(); iter<end; ++iter ) |
154 |
{ |
155 |
if( iter->name.compare( strName ) == 0 ) |
156 |
{ |
157 |
ProfModules.erase( iter ); |
158 |
break; |
159 |
} |
160 |
} |
161 |
} |
162 |
|
163 |
static bool DispatchKnownModules( uint Eip ) |
164 |
{ |
165 |
bool retval = false; |
166 |
EnterCriticalSection( &ProfModulesLock ); |
167 |
|
168 |
size_t i; |
169 |
for(i=0;i<ProfModules.size();i++) |
170 |
if (ProfModules[i].Inside(Eip)) break; |
171 |
|
172 |
if( i < ProfModules.size() ) |
173 |
{ |
174 |
ProfModules[i].ticks++; |
175 |
retval = true; |
176 |
} |
177 |
|
178 |
LeaveCriticalSection( &ProfModulesLock ); |
179 |
return retval; |
180 |
} |
181 |
|
182 |
static void MapUnknownSource( uint Eip ) |
183 |
{ |
184 |
wxChar modulename[512]; |
185 |
DWORD sz=GetModuleFromPtr((void*)Eip,modulename,512); |
186 |
wxString modulenam( (sz==0) ? L"[Unknown]" : modulename ); |
187 |
|
188 |
map<wxString,Module>::iterator iter = ProfUnknownHash.find(modulenam); |
189 |
if (iter!=ProfUnknownHash.end()) |
190 |
{ |
191 |
iter->second.ticks++; |
192 |
return; |
193 |
} |
194 |
|
195 |
Module tmp((sz==0) ? modulenam.c_str() : NULL, (void*)Eip); |
196 |
tmp.ticks++; |
197 |
|
198 |
ProfUnknownHash.insert(MapType::value_type(modulenam, tmp)); |
199 |
} |
200 |
|
201 |
int __stdcall ProfilerThread(void* nada) |
202 |
{ |
203 |
ProfUnknownHash.clear(); |
204 |
u32 tick_count=0; |
205 |
|
206 |
while(ProfRunning) |
207 |
{ |
208 |
Sleep(5); |
209 |
|
210 |
if (tick_count>500) |
211 |
{ |
212 |
wxString rT = L""; |
213 |
wxString rv = L""; |
214 |
u32 subtotal=0; |
215 |
for (size_t i=0;i<ProfModules.size();i++) |
216 |
{ |
217 |
wxString t = ProfModules[i].ToString(tick_count); |
218 |
bool b0 = EmuConfig.Cpu.Recompiler.UseMicroVU0; |
219 |
bool b1 = EmuConfig.Cpu.Recompiler.UseMicroVU1; |
220 |
if ( b0 && b1) { if (t.Find(L"sVU") == -1) rT+=t;} |
221 |
else if (!b0 && !b1) { if (t.Find(L"mVU") == -1) rT+=t;} |
222 |
else if (!b0) { if (t.Find(L"mVU0") == -1) rT+=t;} |
223 |
else if (!b1) { if (t.Find(L"mVU1") == -1) rT+=t;} |
224 |
else rT+=t; |
225 |
|
226 |
subtotal+=ProfModules[i].ticks; |
227 |
ProfModules[i].ticks=0; |
228 |
} |
229 |
|
230 |
rT += wxsFormat( L"| Recs Total: %2.2f%% |", (float)(((double)subtotal*100.0) / (double)tick_count)); |
231 |
vector<MapType::mapped_type> lst; |
232 |
for (MapType::iterator i=ProfUnknownHash.begin();i!=ProfUnknownHash.end();i++) |
233 |
{ |
234 |
lst.push_back(i->second); |
235 |
} |
236 |
|
237 |
sort(lst.begin(),lst.end()); |
238 |
for (size_t i=0;i<lst.size();i++) |
239 |
{ |
240 |
rv += lst[i].ToString(tick_count); |
241 |
} |
242 |
|
243 |
Console.WriteLn( L"Sampling Profiler Results:\n%s\n%s\n", rT.c_str(), rv.c_str() ); |
244 |
Console.SetTitle(rT); |
245 |
|
246 |
tick_count=0; |
247 |
|
248 |
ProfUnknownHash.clear(); |
249 |
} |
250 |
|
251 |
tick_count++; |
252 |
|
253 |
CONTEXT ctx; |
254 |
ctx.ContextFlags = CONTEXT_FULL; |
255 |
GetThreadContext(hEmuThread,&ctx); |
256 |
|
257 |
if( !DispatchKnownModules( ctx.Eip ) ) |
258 |
{ |
259 |
MapUnknownSource( ctx.Eip ); |
260 |
} |
261 |
|
262 |
if( hMtgsThread != NULL ) |
263 |
{ |
264 |
GetThreadContext(hMtgsThread,&ctx); |
265 |
if( DispatchKnownModules( ctx.Eip ) ) |
266 |
continue; |
267 |
} |
268 |
} |
269 |
|
270 |
return -1; |
271 |
} |
272 |
|
273 |
void ProfilerInit() |
274 |
{ |
275 |
if (ProfRunning) |
276 |
return; |
277 |
|
278 |
Console.WriteLn( "Profiler Thread Initializing..." ); |
279 |
ProfRunning=true; |
280 |
DuplicateHandle(GetCurrentProcess(), |
281 |
GetCurrentThread(), |
282 |
GetCurrentProcess(), |
283 |
&(HANDLE)hEmuThread, |
284 |
0, |
285 |
FALSE, |
286 |
DUPLICATE_SAME_ACCESS); |
287 |
|
288 |
InitializeCriticalSection( &ProfModulesLock ); |
289 |
|
290 |
hProfThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ProfilerThread,0,0,0); |
291 |
SetThreadPriority(hProfThread,THREAD_PRIORITY_HIGHEST); |
292 |
Console.WriteLn( "Profiler Thread Started!" ); |
293 |
} |
294 |
|
295 |
void ProfilerTerm() |
296 |
{ |
297 |
Console.WriteLn( "Profiler Terminating..." ); |
298 |
if (!ProfRunning) |
299 |
return; |
300 |
|
301 |
ProfRunning=false; |
302 |
|
303 |
if( hProfThread != NULL ) |
304 |
{ |
305 |
ResumeThread(hProfThread); |
306 |
WaitForSingleObject(hProfThread,INFINITE); |
307 |
CloseHandle(hProfThread); |
308 |
} |
309 |
|
310 |
if( hEmuThread != NULL ) |
311 |
CloseHandle( hEmuThread ); |
312 |
|
313 |
if( hMtgsThread != NULL ) |
314 |
CloseHandle( hMtgsThread ); |
315 |
|
316 |
DeleteCriticalSection( &ProfModulesLock ); |
317 |
Console.WriteLn( "Profiler Termination Done!" ); |
318 |
} |
319 |
|
320 |
void ProfilerSetEnabled(bool Enabled) |
321 |
{ |
322 |
if (!ProfRunning) |
323 |
{ |
324 |
if( !Enabled ) return; |
325 |
ProfilerInit(); |
326 |
} |
327 |
|
328 |
if (Enabled) |
329 |
ResumeThread(hProfThread); |
330 |
else |
331 |
SuspendThread(hProfThread); |
332 |
} |