Added profiler per thread logging.
This commit is contained in:
parent
58b87387eb
commit
7573f1b7dc
|
@ -2580,6 +2580,7 @@ int FCEUD_AviGetFormatOpts( std::vector <std::string> &formatList )
|
||||||
AviRecordDiskThread_t::AviRecordDiskThread_t( QObject *parent )
|
AviRecordDiskThread_t::AviRecordDiskThread_t( QObject *parent )
|
||||||
: QThread(parent)
|
: QThread(parent)
|
||||||
{
|
{
|
||||||
|
setObjectName( QString("AviRecordDiskThread") );
|
||||||
}
|
}
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
AviRecordDiskThread_t::~AviRecordDiskThread_t(void)
|
AviRecordDiskThread_t::~AviRecordDiskThread_t(void)
|
||||||
|
|
|
@ -125,6 +125,13 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
||||||
|
|
||||||
printf("Running on Platform: %s\n", QGuiApplication::platformName().toStdString().c_str() );
|
printf("Running on Platform: %s\n", QGuiApplication::platformName().toStdString().c_str() );
|
||||||
|
|
||||||
|
QThread *thread = QThread::currentThread();
|
||||||
|
|
||||||
|
if (thread)
|
||||||
|
{
|
||||||
|
thread->setObjectName( QString("MainThread") );
|
||||||
|
}
|
||||||
|
|
||||||
QApplication::setStyle( new fceuStyle() );
|
QApplication::setStyle( new fceuStyle() );
|
||||||
|
|
||||||
initHotKeys();
|
initHotKeys();
|
||||||
|
@ -4604,6 +4611,9 @@ void consoleWin_t::updatePeriodic(void)
|
||||||
|
|
||||||
updateCounter++;
|
updateCounter++;
|
||||||
|
|
||||||
|
#ifdef __FCEU_PROFILER_ENABLE__
|
||||||
|
FCEU_profiler_log_thread_activity();
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4614,6 +4624,7 @@ emulatorThread_t::emulatorThread_t( QObject *parent )
|
||||||
pself = 0;
|
pself = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
setObjectName( QString("EmulationThread") );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
|
|
@ -2507,6 +2507,7 @@ void QTraceLogView::paintEvent(QPaintEvent *event)
|
||||||
TraceLogDiskThread_t::TraceLogDiskThread_t( QObject *parent )
|
TraceLogDiskThread_t::TraceLogDiskThread_t( QObject *parent )
|
||||||
: QThread(parent)
|
: QThread(parent)
|
||||||
{
|
{
|
||||||
|
setObjectName( QString("TraceLogDiskThread") );
|
||||||
}
|
}
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
TraceLogDiskThread_t::~TraceLogDiskThread_t(void)
|
TraceLogDiskThread_t::~TraceLogDiskThread_t(void)
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "../../cheat.h"
|
#include "../../cheat.h"
|
||||||
#include "../../movie.h"
|
#include "../../movie.h"
|
||||||
#include "../../state.h"
|
#include "../../state.h"
|
||||||
|
#include "../../profiler.h"
|
||||||
#include "../../version.h"
|
#include "../../version.h"
|
||||||
|
|
||||||
#ifdef _S9XLUA_H
|
#ifdef _S9XLUA_H
|
||||||
|
@ -1465,6 +1466,9 @@ int fceuWrapperUpdate( void )
|
||||||
|
|
||||||
emulatorHasMutex = 0;
|
emulatorHasMutex = 0;
|
||||||
|
|
||||||
|
#ifdef __FCEU_PROFILER_ENABLE__
|
||||||
|
FCEU_profiler_log_thread_activity();
|
||||||
|
#endif
|
||||||
while ( SpeedThrottle() )
|
while ( SpeedThrottle() )
|
||||||
{
|
{
|
||||||
// Input device processing is in main thread
|
// Input device processing is in main thread
|
||||||
|
@ -1478,6 +1482,9 @@ int fceuWrapperUpdate( void )
|
||||||
|
|
||||||
emulatorHasMutex = 0;
|
emulatorHasMutex = 0;
|
||||||
|
|
||||||
|
#ifdef __FCEU_PROFILER_ENABLE__
|
||||||
|
FCEU_profiler_log_thread_activity();
|
||||||
|
#endif
|
||||||
msleep( 100 );
|
msleep( 100 );
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
130
src/profiler.cpp
130
src/profiler.cpp
|
@ -23,6 +23,10 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __QT_DRIVER__
|
||||||
|
#include <QThread>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +41,7 @@
|
||||||
|
|
||||||
namespace FCEU
|
namespace FCEU
|
||||||
{
|
{
|
||||||
|
static thread_local profileExecVector execList;
|
||||||
static thread_local profilerFuncMap threadProfileMap;
|
static thread_local profilerFuncMap threadProfileMap;
|
||||||
|
|
||||||
FILE *profilerManager::pLog = nullptr;
|
FILE *profilerManager::pLog = nullptr;
|
||||||
|
@ -64,10 +69,8 @@ void timeStampRecord::readNew(void)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
|
||||||
clock_gettime( CLOCK_REALTIME, &ts );
|
clock_gettime( CLOCK_REALTIME, &ts );
|
||||||
#elif defined(WIN32)
|
|
||||||
QueryPerformanceCounter((LARGE_INTEGER*)&ts);
|
|
||||||
#else
|
#else
|
||||||
ts = 0;
|
QueryPerformanceCounter((LARGE_INTEGER*)&ts);
|
||||||
#endif
|
#endif
|
||||||
tsc = rdtsc();
|
tsc = rdtsc();
|
||||||
}
|
}
|
||||||
|
@ -121,16 +124,19 @@ funcProfileRecord::funcProfileRecord(const char *fileNameStringLiteral,
|
||||||
: fileLineNum(fileLineNumber), fileName(fileNameStringLiteral),
|
: fileLineNum(fileLineNumber), fileName(fileNameStringLiteral),
|
||||||
funcName(funcNameStringLiteral), comment(commentStringLiteral)
|
funcName(funcNameStringLiteral), comment(commentStringLiteral)
|
||||||
{
|
{
|
||||||
min.zero();
|
min.fromSeconds(9);
|
||||||
max.zero();
|
max.zero();
|
||||||
sum.zero();
|
sum.zero();
|
||||||
numCalls = 0;
|
numCalls = 0;
|
||||||
recursionCount = 0;
|
recursionCount = 0;
|
||||||
|
|
||||||
|
threadProfileMap.addRecord( fileNameStringLiteral, fileLineNumber,
|
||||||
|
funcNameStringLiteral, commentStringLiteral, this);
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
void funcProfileRecord::reset(void)
|
void funcProfileRecord::reset(void)
|
||||||
{
|
{
|
||||||
min.zero();
|
min.fromSeconds(9);
|
||||||
max.zero();
|
max.zero();
|
||||||
sum.zero();
|
sum.zero();
|
||||||
numCalls = 0;
|
numCalls = 0;
|
||||||
|
@ -149,20 +155,9 @@ double funcProfileRecord::average(void)
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//---- Profile Scoped Function Class
|
//---- Profile Scoped Function Class
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
profileFuncScoped::profileFuncScoped(const char *fileNameStringLiteral,
|
profileFuncScoped::profileFuncScoped( funcProfileRecord *recordIn )
|
||||||
const int fileLineNumber,
|
|
||||||
const char *funcNameStringLiteral,
|
|
||||||
const char *commentStringLiteral)
|
|
||||||
{
|
{
|
||||||
rec = nullptr;
|
rec = recordIn;
|
||||||
|
|
||||||
//if (threadProfileMap == nullptr)
|
|
||||||
//{
|
|
||||||
// threadProfileMap = new profilerFuncMap();
|
|
||||||
//}
|
|
||||||
|
|
||||||
rec = threadProfileMap.findRecord( fileNameStringLiteral, fileLineNumber,
|
|
||||||
funcNameStringLiteral, commentStringLiteral, true);
|
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
{
|
{
|
||||||
|
@ -181,17 +176,70 @@ profileFuncScoped::~profileFuncScoped(void)
|
||||||
ts.readNew();
|
ts.readNew();
|
||||||
dt = ts - start;
|
dt = ts - start;
|
||||||
|
|
||||||
|
rec->last = dt;
|
||||||
rec->sum += dt;
|
rec->sum += dt;
|
||||||
if (dt < rec->min) rec->min = dt;
|
if (dt < rec->min) rec->min = dt;
|
||||||
if (dt > rec->max) rec->max = dt;
|
if (dt > rec->max) rec->max = dt;
|
||||||
|
|
||||||
rec->recursionCount--;
|
rec->recursionCount--;
|
||||||
|
|
||||||
//printf("%s: %u %f %f %f %f\n", rec->funcName, rec->numCalls, dt.toSeconds(), rec->average(), rec->min.toSeconds(), rec->max.toSeconds());
|
execList._vec.push_back(*rec);
|
||||||
|
|
||||||
threadProfileMap.popStack(rec);
|
threadProfileMap.popStack(rec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
//---- Profile Execution Vector
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
profileExecVector::profileExecVector(void)
|
||||||
|
{
|
||||||
|
_vec.reserve( 10000 );
|
||||||
|
|
||||||
|
char threadName[128];
|
||||||
|
char fileName[256];
|
||||||
|
|
||||||
|
strcpy( threadName, "MainThread");
|
||||||
|
|
||||||
|
#ifdef __QT_DRIVER__
|
||||||
|
QThread *thread = QThread::currentThread();
|
||||||
|
|
||||||
|
if (thread)
|
||||||
|
{
|
||||||
|
//printf("Thread: %s\n", thread->objectName().toStdString().c_str());
|
||||||
|
strcpy( threadName, thread->objectName().toStdString().c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
sprintf( fileName, "fceux-profile-%s.log", threadName);
|
||||||
|
|
||||||
|
logFp = ::fopen(fileName, "w");
|
||||||
|
|
||||||
|
if (logFp == nullptr)
|
||||||
|
{
|
||||||
|
printf("Error: Failed to create profiler logfile: %s\n", fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
profileExecVector::~profileExecVector(void)
|
||||||
|
{
|
||||||
|
if (logFp)
|
||||||
|
{
|
||||||
|
::fclose(logFp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
void profileExecVector::update(void)
|
||||||
|
{
|
||||||
|
size_t n = _vec.size();
|
||||||
|
|
||||||
|
for (size_t i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
funcProfileRecord &rec = _vec[i];
|
||||||
|
|
||||||
|
fprintf( logFp, "%s: %u %f %f %f %f\n", rec.funcName, rec.numCalls, rec.last.toSeconds(), rec.average(), rec.min.toSeconds(), rec.max.toSeconds());
|
||||||
|
}
|
||||||
|
_vec.clear();
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
//---- Profile Function Record Map
|
//---- Profile Function Record Map
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
profilerFuncMap::profilerFuncMap(void)
|
profilerFuncMap::profilerFuncMap(void)
|
||||||
|
@ -207,15 +255,15 @@ profilerFuncMap::~profilerFuncMap(void)
|
||||||
//printf("profilerFuncMap Destructor: %p\n", this);
|
//printf("profilerFuncMap Destructor: %p\n", this);
|
||||||
pMgr.removeThreadProfiler(this);
|
pMgr.removeThreadProfiler(this);
|
||||||
|
|
||||||
{
|
//{
|
||||||
autoScopedLock aLock(_mapMtx);
|
// autoScopedLock aLock(_mapMtx);
|
||||||
|
|
||||||
for (auto it = _map.begin(); it != _map.end(); it++)
|
// for (auto it = _map.begin(); it != _map.end(); it++)
|
||||||
{
|
// {
|
||||||
delete it->second;
|
// delete it->second;
|
||||||
}
|
// }
|
||||||
_map.clear();
|
// _map.clear();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
void profilerFuncMap::pushStack(funcProfileRecord *rec)
|
void profilerFuncMap::pushStack(funcProfileRecord *rec)
|
||||||
|
@ -228,6 +276,26 @@ void profilerFuncMap::popStack(funcProfileRecord *rec)
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
int profilerFuncMap::addRecord(const char *fileNameStringLiteral,
|
||||||
|
const int fileLineNumber,
|
||||||
|
const char *funcNameStringLiteral,
|
||||||
|
const char *commentStringLiteral,
|
||||||
|
funcProfileRecord *rec )
|
||||||
|
{
|
||||||
|
autoScopedLock aLock(_mapMtx);
|
||||||
|
char lineString[64];
|
||||||
|
|
||||||
|
sprintf( lineString, ":%i", fileLineNumber);
|
||||||
|
|
||||||
|
std::string fname(fileNameStringLiteral);
|
||||||
|
|
||||||
|
fname.append( lineString );
|
||||||
|
|
||||||
|
_map[fname] = rec;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
funcProfileRecord *profilerFuncMap::findRecord(const char *fileNameStringLiteral,
|
funcProfileRecord *profilerFuncMap::findRecord(const char *fileNameStringLiteral,
|
||||||
const int fileLineNumber,
|
const int fileLineNumber,
|
||||||
const char *funcNameStringLiteral,
|
const char *funcNameStringLiteral,
|
||||||
|
@ -363,6 +431,12 @@ int profilerManager::removeThreadProfiler( profilerFuncMap *m, bool shouldDestro
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//
|
} // namespace FCEU
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
int FCEU_profiler_log_thread_activity(void)
|
||||||
|
{
|
||||||
|
FCEU::execList.update();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // __FCEU_PROFILER_ENABLE__
|
#endif // __FCEU_PROFILER_ENABLE__
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
*/
|
*/
|
||||||
#ifdef __FCEU_PROFILER_ENABLE__
|
#ifdef __FCEU_PROFILER_ENABLE__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -123,7 +124,7 @@ namespace FCEU
|
||||||
}
|
}
|
||||||
else if (ts.tv_sec > op.ts.tv_sec)
|
else if (ts.tv_sec > op.ts.tv_sec)
|
||||||
{
|
{
|
||||||
res = (ts.tv_sec > op.ts.tv_sec);
|
res = true;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -135,9 +136,9 @@ namespace FCEU
|
||||||
{
|
{
|
||||||
res = (ts.tv_nsec < op.ts.tv_nsec);
|
res = (ts.tv_nsec < op.ts.tv_nsec);
|
||||||
}
|
}
|
||||||
else if (ts.tv_sec > op.ts.tv_sec)
|
else if (ts.tv_sec < op.ts.tv_sec)
|
||||||
{
|
{
|
||||||
res = (ts.tv_sec < op.ts.tv_sec);
|
res = true;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -149,6 +150,13 @@ namespace FCEU
|
||||||
tsc = 0;
|
tsc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fromSeconds(unsigned int sec)
|
||||||
|
{
|
||||||
|
ts.tv_sec = sec;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
tsc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
double toSeconds(void)
|
double toSeconds(void)
|
||||||
{
|
{
|
||||||
double sec = static_cast<double>(ts.tv_sec) + ( static_cast<double>(ts.tv_nsec) * 1.0e-9 );
|
double sec = static_cast<double>(ts.tv_sec) + ( static_cast<double>(ts.tv_nsec) * 1.0e-9 );
|
||||||
|
@ -213,6 +221,12 @@ namespace FCEU
|
||||||
tsc = 0;
|
tsc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fromSeconds(unsigned int sec)
|
||||||
|
{
|
||||||
|
ts = sec * qpcFreq;
|
||||||
|
tsc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
double toSeconds(void)
|
double toSeconds(void)
|
||||||
{
|
{
|
||||||
double sec = static_cast<double>(ts) / static_cast<double>(qpcFreq);
|
double sec = static_cast<double>(ts) / static_cast<double>(qpcFreq);
|
||||||
|
@ -235,6 +249,7 @@ namespace FCEU
|
||||||
timeStampRecord min;
|
timeStampRecord min;
|
||||||
timeStampRecord max;
|
timeStampRecord max;
|
||||||
timeStampRecord sum;
|
timeStampRecord sum;
|
||||||
|
timeStampRecord last;
|
||||||
unsigned int numCalls;
|
unsigned int numCalls;
|
||||||
unsigned int recursionCount;
|
unsigned int recursionCount;
|
||||||
|
|
||||||
|
@ -253,20 +268,35 @@ namespace FCEU
|
||||||
funcProfileRecord *rec;
|
funcProfileRecord *rec;
|
||||||
timeStampRecord start;
|
timeStampRecord start;
|
||||||
|
|
||||||
profileFuncScoped(const char *fileNameStringLiteral,
|
profileFuncScoped( funcProfileRecord *recordIn );
|
||||||
const int fileLineNumber,
|
|
||||||
const char *funcNameStringLiteral,
|
|
||||||
const char *commentStringLiteral);
|
|
||||||
|
|
||||||
~profileFuncScoped(void);
|
~profileFuncScoped(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct profileExecVector
|
||||||
|
{
|
||||||
|
profileExecVector(void);
|
||||||
|
~profileExecVector(void);
|
||||||
|
|
||||||
|
void update(void);
|
||||||
|
|
||||||
|
std::vector <funcProfileRecord> _vec;
|
||||||
|
|
||||||
|
FILE *logFp;
|
||||||
|
};
|
||||||
|
|
||||||
class profilerFuncMap
|
class profilerFuncMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
profilerFuncMap();
|
profilerFuncMap();
|
||||||
~profilerFuncMap();
|
~profilerFuncMap();
|
||||||
|
|
||||||
|
int addRecord(const char *fileNameStringLiteral,
|
||||||
|
const int fileLineNumber,
|
||||||
|
const char *funcNameStringLiteral,
|
||||||
|
const char *commentStringLiteral,
|
||||||
|
funcProfileRecord *rec );
|
||||||
|
|
||||||
funcProfileRecord *findRecord(const char *fileNameStringLiteral,
|
funcProfileRecord *findRecord(const char *fileNameStringLiteral,
|
||||||
const int fileLineNumber,
|
const int fileLineNumber,
|
||||||
const char *funcNameStringLiteral,
|
const char *funcNameStringLiteral,
|
||||||
|
@ -312,7 +342,12 @@ namespace FCEU
|
||||||
#define __FCEU_PROFILE_FUNC_NAME__ __func__
|
#define __FCEU_PROFILE_FUNC_NAME__ __func__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FCEU_PROFILE_FUNC(id, comment) FCEU::profileFuncScoped id( __FILE__, __LINE__, __FCEU_PROFILE_FUNC_NAME__, comment )
|
#define FCEU_PROFILE_FUNC(id, comment) \
|
||||||
|
static thread_local FCEU::funcProfileRecord id( __FILE__, __LINE__, __FCEU_PROFILE_FUNC_NAME__, comment ); \
|
||||||
|
FCEU::profileFuncScoped id ## _unique_scope( &id )
|
||||||
|
|
||||||
|
|
||||||
|
int FCEU_profiler_log_thread_activity(void);
|
||||||
|
|
||||||
#else // __FCEU_PROFILER_ENABLE__ not defined
|
#else // __FCEU_PROFILER_ENABLE__ not defined
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue