Implement JitIL profiling on linux. I also tried implementing __rdtsc using assembly and didn't really see a speed improvement so went with clock_gettime.
Also changed other gettimeofday calls to clock_gettime, which is supposedly more accurate. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6447 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
d1264b3258
commit
ef55177ed6
|
@ -492,15 +492,11 @@ namespace Common
|
|||
|
||||
if (timeout != INFINITE)
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
|
||||
|
||||
memset(&wait, 0, sizeof(wait));
|
||||
//TODO: timespec also has nanoseconds, but do we need them?
|
||||
//as consequence, waiting is limited to seconds for now.
|
||||
//the following just looks ridiculous, and probably fails for
|
||||
//values 429 < ms <= 999 since it overflows the long.
|
||||
//wait.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000);
|
||||
wait.tv_nsec = now.tv_nsec + (timeout % 1000) * 1000000;
|
||||
wait.tv_sec = now.tv_sec + (timeout / 1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,8 +60,7 @@
|
|||
#define INFINITE 0xffffffff
|
||||
#endif
|
||||
|
||||
//for gettimeofday and struct time(val|spec)
|
||||
#include <sys/time.h>
|
||||
//for clock_gettime and struct timespec
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <Windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <sys/timeb.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
|
@ -37,9 +35,9 @@ u32 Timer::GetTimeMs()
|
|||
#ifdef _WIN32
|
||||
return timeGetTime();
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
return((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
|
||||
struct timespec t;
|
||||
(void)clock_gettime(CLOCK_MONOTONIC_RAW, &t);
|
||||
return ((u32)(t.tv_sec * 1000 + t.tv_nsec / 1000000));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -157,13 +155,6 @@ void Timer::RestoreResolution()
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
void _time64(u64* t)
|
||||
{
|
||||
*t = 0; //TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the number of seconds since January 1 1970
|
||||
u64 Timer::GetTimeSinceJan1970()
|
||||
{
|
||||
|
@ -213,9 +204,9 @@ std::string Timer::GetTimeFormatted()
|
|||
(void)::ftime(&tp);
|
||||
sprintf(formattedTime, "%s:%03i", tmp, tp.millitm);
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000));
|
||||
struct timespec t;
|
||||
(void)clock_gettime(CLOCK_REALTIME, &t);
|
||||
sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_nsec / 1000000));
|
||||
#endif
|
||||
|
||||
return std::string(formattedTime);
|
||||
|
@ -229,8 +220,8 @@ double Timer::GetDoubleTime()
|
|||
struct timeb tp;
|
||||
(void)::ftime(&tp);
|
||||
#else
|
||||
struct timeval t;
|
||||
(void)gettimeofday(&t, NULL);
|
||||
struct timespec t;
|
||||
(void)clock_gettime(CLOCK_REALTIME, &t);
|
||||
#endif
|
||||
// Get continuous timestamp
|
||||
u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
|
||||
|
@ -246,7 +237,7 @@ double Timer::GetDoubleTime()
|
|||
#ifdef _WIN32
|
||||
double ms = tp.millitm / 1000.0 / 1000.0;
|
||||
#else
|
||||
double ms = t.tv_usec / 1000.0 / 1000.0;
|
||||
double ms = t.tv_nsec / 1000000000.0;
|
||||
#endif
|
||||
double TmpTime = Seconds + ms;
|
||||
|
||||
|
|
|
@ -153,24 +153,39 @@ ps_adds1
|
|||
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// For profiling
|
||||
// FIXME: This is currently for windows only.
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include <time.h>
|
||||
namespace JitILProfiler {
|
||||
struct Block {
|
||||
#else
|
||||
#include <memory>
|
||||
static inline u64 __rdtsc()
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
|
||||
return (ts.tv_sec * 100000000 + ts.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace JitILProfiler
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
u32 index;
|
||||
u64 codeHash;
|
||||
u64 toalElapsed;
|
||||
u64 totalElapsed;
|
||||
u64 numberOfCalls;
|
||||
Block() : index(0), codeHash(0), toalElapsed(0), numberOfCalls(0) { }
|
||||
Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0) { }
|
||||
};
|
||||
static std::vector<Block> blocks;
|
||||
static u32 blockIndex;
|
||||
static u64 beginTime;
|
||||
static Block& Add(u64 codeHash) {
|
||||
static Block& Add(u64 codeHash)
|
||||
{
|
||||
const u32 blockIndex = blocks.size();
|
||||
blocks.push_back(Block());
|
||||
Block& block = blocks.back();
|
||||
|
@ -178,29 +193,34 @@ namespace JitILProfiler {
|
|||
block.codeHash = codeHash;
|
||||
return block;
|
||||
}
|
||||
// These functions need to be static function
|
||||
// because they are called with ABI_CallFunction().
|
||||
static void Begin(u32 index) {
|
||||
// These functions need to be static because they are called with
|
||||
// ABI_CallFunction().
|
||||
static void Begin(u32 index)
|
||||
{
|
||||
blockIndex = index;
|
||||
beginTime = __rdtsc();
|
||||
}
|
||||
static void End() {
|
||||
static void End()
|
||||
{
|
||||
const u64 endTime = __rdtsc();
|
||||
const u64 duration = endTime - beginTime;
|
||||
Block& block = blocks[blockIndex];
|
||||
block.toalElapsed += duration;
|
||||
block.totalElapsed += duration;
|
||||
++block.numberOfCalls;
|
||||
}
|
||||
struct JitILProfilerFinalizer {
|
||||
virtual ~JitILProfilerFinalizer() {
|
||||
struct JitILProfilerFinalizer
|
||||
{
|
||||
virtual ~JitILProfilerFinalizer()
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf(buffer, "JitIL_profiling_%d.csv", time(NULL));
|
||||
sprintf(buffer, "JitIL_profiling_%d.csv", (int)time(NULL));
|
||||
FILE* file = fopen(buffer, "w");
|
||||
setvbuf(file, NULL, _IOFBF, 1024 * 1024);
|
||||
fprintf(file, "code hash,total elapsed,number of calls,elapsed per call\n");
|
||||
for (std::vector<Block>::iterator it = blocks.begin(), itEnd = blocks.end(); it != itEnd; ++it) {
|
||||
for (std::vector<Block>::iterator it = blocks.begin(), itEnd = blocks.end(); it != itEnd; ++it)
|
||||
{
|
||||
const u64 codeHash = it->codeHash;
|
||||
const u64 totalElapsed = it->toalElapsed;
|
||||
const u64 totalElapsed = it->totalElapsed;
|
||||
const u64 numberOfCalls = it->numberOfCalls;
|
||||
const double elapsedPerCall = totalElapsed / (double)numberOfCalls;
|
||||
fprintf(file, "%016llx,%lld,%lld,%f\n", codeHash, totalElapsed, numberOfCalls, elapsedPerCall);
|
||||
|
@ -210,31 +230,15 @@ namespace JitILProfiler {
|
|||
}
|
||||
};
|
||||
std::auto_ptr<JitILProfilerFinalizer> finalizer;
|
||||
static void Init() {
|
||||
static void Init()
|
||||
{
|
||||
finalizer = std::auto_ptr<JitILProfilerFinalizer>(new JitILProfilerFinalizer);
|
||||
}
|
||||
static void Shutdown() {
|
||||
static void Shutdown()
|
||||
{
|
||||
finalizer.reset();
|
||||
}
|
||||
};
|
||||
#else
|
||||
namespace JitILProfiler {
|
||||
// FIXME: Dummy functions for linux. Please implement them.
|
||||
struct Block {
|
||||
u32 index;
|
||||
u64 codeHash;
|
||||
u64 toalElapsed;
|
||||
u64 numberOfCalls;
|
||||
Block() : index(0), codeHash(0), toalElapsed(0), numberOfCalls(0) { }
|
||||
};
|
||||
static Block dummyBlock;
|
||||
static Block& Add(u64 codeHash) { return dummyBlock; }
|
||||
static void Begin(u32 index) { }
|
||||
static void End() { }
|
||||
static void Init() { }
|
||||
static void Shutdown() { }
|
||||
};
|
||||
#endif
|
||||
|
||||
static int CODE_SIZE = 1024*1024*32;
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ elseif(NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
|||
set(LIBS ${LIBS} clrun)
|
||||
endif()
|
||||
|
||||
add_library(Plugin_VideoSoftware SHARED ${SRCS})
|
||||
add_library(Plugin_VideoSoftware MODULE ${SRCS})
|
||||
target_link_libraries(Plugin_VideoSoftware ${LIBS})
|
||||
install(TARGETS Plugin_VideoSoftware
|
||||
LIBRARY DESTINATION ${plugindir}
|
||||
|
|
Loading…
Reference in New Issue