mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-23 15:46:18 +00:00
Added: Implementation of timer tests for linux
This commit is contained in:
parent
ebabe8ed73
commit
d14bbaf331
2 changed files with 169 additions and 66 deletions
|
@ -34,16 +34,16 @@ struct CPMainThread : public CPThread
|
||||||
{
|
{
|
||||||
CPMainThread() : CPThread(NULL, 0)
|
CPMainThread() : CPThread(NULL, 0)
|
||||||
{
|
{
|
||||||
if(pthread_key_create(&threadSpecificKey, NULL) != 0)
|
if(pthread_key_create(&threadSpecificKey, NULL) != 0)
|
||||||
throw EThread("cannot create thread specific storage key.");
|
throw EThread("cannot create thread specific storage key.");
|
||||||
|
|
||||||
if(pthread_setspecific(threadSpecificKey, this) != 0)
|
if(pthread_setspecific(threadSpecificKey, this) != 0)
|
||||||
throw EThread("cannot set main thread ptr in thread specific storage.");
|
throw EThread("cannot set main thread ptr in thread specific storage.");
|
||||||
}
|
}
|
||||||
|
|
||||||
~CPMainThread()
|
~CPMainThread()
|
||||||
{
|
{
|
||||||
if(pthread_key_delete(threadSpecificKey) != 0)
|
if(pthread_key_delete(threadSpecificKey) != 0)
|
||||||
throw EThread("cannot delete thread specific storage key.");
|
throw EThread("cannot delete thread specific storage key.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -139,7 +139,7 @@ void CPThread::start()
|
||||||
/* setting the size of the stack also */
|
/* setting the size of the stack also */
|
||||||
ret = pthread_attr_setstacksize(&tattr, _StackSize);
|
ret = pthread_attr_setstacksize(&tattr, _StackSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool detach_old_thread = false;
|
bool detach_old_thread = false;
|
||||||
pthread_t old_thread_handle;
|
pthread_t old_thread_handle;
|
||||||
if (_State != ThreadStateNone)
|
if (_State != ThreadStateNone)
|
||||||
|
@ -221,6 +221,9 @@ void CPThread::wait ()
|
||||||
bool CPThread::setCPUMask(uint64 cpuMask)
|
bool CPThread::setCPUMask(uint64 cpuMask)
|
||||||
{
|
{
|
||||||
#ifdef __USE_GNU
|
#ifdef __USE_GNU
|
||||||
|
|
||||||
|
nlwarning("This code does not work. May cause a segmentation fault...");
|
||||||
|
|
||||||
sint res = pthread_setaffinity_np(_ThreadHandle, sizeof(uint64), (const cpu_set_t*)&cpuMask);
|
sint res = pthread_setaffinity_np(_ThreadHandle, sizeof(uint64), (const cpu_set_t*)&cpuMask);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -228,9 +231,14 @@ bool CPThread::setCPUMask(uint64 cpuMask)
|
||||||
nlwarning("pthread_setaffinity_np() returned %d", res);
|
nlwarning("pthread_setaffinity_np() returned %d", res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif // __USE_GNU
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
#else // __USE_GNU
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#endif // __USE_GNU
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -238,9 +246,12 @@ bool CPThread::setCPUMask(uint64 cpuMask)
|
||||||
*/
|
*/
|
||||||
uint64 CPThread::getCPUMask()
|
uint64 CPThread::getCPUMask()
|
||||||
{
|
{
|
||||||
uint64 cpuMask = 1;
|
|
||||||
|
|
||||||
#ifdef __USE_GNU
|
#ifdef __USE_GNU
|
||||||
|
|
||||||
|
nlwarning("This code does not work. May cause a segmentation fault...");
|
||||||
|
|
||||||
|
uint64 cpuMask = 0;
|
||||||
|
|
||||||
sint res = pthread_getaffinity_np(_ThreadHandle, sizeof(uint64), (cpu_set_t*)&cpuMask);
|
sint res = pthread_getaffinity_np(_ThreadHandle, sizeof(uint64), (cpu_set_t*)&cpuMask);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -248,9 +259,14 @@ uint64 CPThread::getCPUMask()
|
||||||
nlwarning("pthread_getaffinity_np() returned %d", res);
|
nlwarning("pthread_getaffinity_np() returned %d", res);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // __USE_GNU
|
|
||||||
|
|
||||||
return cpuMask;
|
return cpuMask;
|
||||||
|
|
||||||
|
#else // __USE_GNU
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif // __USE_GNU
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPThread::setPriority(TThreadPriority priority)
|
void CPThread::setPriority(TThreadPriority priority)
|
||||||
|
@ -311,9 +327,9 @@ IProcess *IProcess::getCurrentProcess ()
|
||||||
*/
|
*/
|
||||||
uint64 CPProcess::getCPUMask()
|
uint64 CPProcess::getCPUMask()
|
||||||
{
|
{
|
||||||
uint64 cpuMask = 1;
|
|
||||||
|
|
||||||
#ifdef __USE_GNU
|
#ifdef __USE_GNU
|
||||||
|
|
||||||
|
uint64 cpuMask = 0;
|
||||||
sint res = sched_getaffinity(getpid(), sizeof(uint64), (cpu_set_t*)&cpuMask);
|
sint res = sched_getaffinity(getpid(), sizeof(uint64), (cpu_set_t*)&cpuMask);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -321,15 +337,21 @@ uint64 CPProcess::getCPUMask()
|
||||||
nlwarning("sched_getaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
|
nlwarning("sched_getaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // __USE_GNU
|
|
||||||
|
|
||||||
return cpuMask;
|
return cpuMask;
|
||||||
|
|
||||||
|
#else // __USE_GNU
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif // __USE_GNU
|
||||||
}
|
}
|
||||||
|
|
||||||
/// set the CPU mask
|
/// set the CPU mask
|
||||||
bool CPProcess::setCPUMask(uint64 cpuMask)
|
bool CPProcess::setCPUMask(uint64 cpuMask)
|
||||||
{
|
{
|
||||||
#ifdef __USE_GNU
|
#ifdef __USE_GNU
|
||||||
|
|
||||||
sint res = sched_setaffinity(getpid(), sizeof(uint64), (const cpu_set_t*)&cpuMask);
|
sint res = sched_setaffinity(getpid(), sizeof(uint64), (const cpu_set_t*)&cpuMask);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -337,9 +359,14 @@ bool CPProcess::setCPUMask(uint64 cpuMask)
|
||||||
nlwarning("sched_setaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
|
nlwarning("sched_setaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif // __USE_GNU
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
#else // __USE_GNU
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#endif // __USE_GNU
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,63 @@ namespace {
|
||||||
bool a_HaveQueryPerformance = false;
|
bool a_HaveQueryPerformance = false;
|
||||||
LARGE_INTEGER a_QueryPerformanceFrequency;
|
LARGE_INTEGER a_QueryPerformanceFrequency;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NL_OS_UNIX
|
||||||
|
# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
||||||
|
# if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
|
||||||
|
# define NL_MONOTONIC_CLOCK
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# ifdef NL_MONOTONIC_CLOCK
|
||||||
|
bool a_CheckedMonotonicClock = false;
|
||||||
|
bool a_HasMonotonicClock = false;
|
||||||
|
uint64 a_MonotonicClockFrequency = 0;
|
||||||
|
uint64 a_MonotonicClockResolutionNs = 0;
|
||||||
|
bool hasMonotonicClock()
|
||||||
|
{
|
||||||
|
if (!a_CheckedMonotonicClock)
|
||||||
|
{
|
||||||
|
/* Initialize the local time engine.
|
||||||
|
* On Unix, this method will find out if the Monotonic Clock is supported
|
||||||
|
* (seems supported by kernel 2.6, not by kernel 2.4). See getLocalTime().
|
||||||
|
*/
|
||||||
|
struct timespec tv;
|
||||||
|
if ((clock_gettime( CLOCK_MONOTONIC, &tv ) == 0) &&
|
||||||
|
(clock_getres( CLOCK_MONOTONIC, &tv ) == 0))
|
||||||
|
{
|
||||||
|
// nldebug( "Monotonic local time supported (resolution %.6f ms)", ((float)tv.tv_sec)*1000.0f + ((float)tv.tv_nsec)/1000000.0f );
|
||||||
|
|
||||||
|
if (tv.tv_sec > 0)
|
||||||
|
{
|
||||||
|
nlwarning("Monotonic clock not ok, resolution > 1s");
|
||||||
|
a_HasMonotonicClock = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64 nsPerTick = tv.tv_nsec;
|
||||||
|
uint64 nsPerSec = 1000000000L;
|
||||||
|
uint64 tickPerSec = nsPerSec / nsPerTick;
|
||||||
|
a_MonotonicClockFrequency = tickPerSec;
|
||||||
|
a_MonotonicClockResolutionNs = nsPerTick;
|
||||||
|
a_HasMonotonicClock = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_HasMonotonicClock = false;
|
||||||
|
}
|
||||||
|
a_CheckedMonotonicClock = true;
|
||||||
|
}
|
||||||
|
return a_HasMonotonicClock;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTime::probeTimerInfo(CTime::CTimerInfo &result)
|
void CTime::probeTimerInfo(CTime::CTimerInfo &result)
|
||||||
{
|
{
|
||||||
breakable
|
breakable
|
||||||
{
|
{
|
||||||
#ifdef NL_OS_WINDOWS
|
#ifdef NL_OS_WINDOWS
|
||||||
LARGE_INTEGER winPerfFreq;
|
LARGE_INTEGER winPerfFreq;
|
||||||
LARGE_INTEGER winPerfCount;
|
LARGE_INTEGER winPerfCount;
|
||||||
DWORD lowResTime;
|
DWORD lowResTime;
|
||||||
|
@ -78,21 +128,34 @@ void CTime::probeTimerInfo(CTime::CTimerInfo &result)
|
||||||
{
|
{
|
||||||
lowResTime = timeGetTime();
|
lowResTime = timeGetTime();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// nldebug("Probe of timer info not implemented");
|
|
||||||
result.IsHighPrecisionAvailable = false;
|
// Other platforms are awesome. Generic implementation for now.
|
||||||
result.RequiresSingleCore = true;
|
TTime localTime = getLocalTime();
|
||||||
break;
|
result.IsHighPrecisionAvailable = true;
|
||||||
#endif
|
result.HighPrecisionResolution = 0;
|
||||||
|
|
||||||
|
# ifdef NL_MONOTONIC_CLOCK
|
||||||
|
timespec monoClock;
|
||||||
|
if (hasMonotonicClock())
|
||||||
|
{
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &monoClock);
|
||||||
|
result.HighPrecisionResolution = a_MonotonicClockFrequency;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nldebug("Monotonic clock not available");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
uint64 cpuMask = IProcess::getCurrentProcess()->getCPUMask();
|
uint64 cpuMask = IProcess::getCurrentProcess()->getCPUMask();
|
||||||
uint64 threadMask = IThread::getCurrentThread()->getCPUMask();
|
#ifdef NL_OS_WINDOWS
|
||||||
|
uint64 threadMask = IThread::getCurrentThread()->getCPUMask(); // broken on linux, don't expect it to work anywhere
|
||||||
#ifdef NL_OS_WINDOWS
|
#else
|
||||||
|
uint64 threadMask = cpuMask;
|
||||||
#else
|
#endif
|
||||||
TTicks timerFrequency = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint identical = 0; // Identical stamps may indicate the os handling backwards glitches.
|
uint identical = 0; // Identical stamps may indicate the os handling backwards glitches.
|
||||||
uint backwards = 0; // Happens when the timers are not always in sync and the implementation is faulty.
|
uint backwards = 0; // Happens when the timers are not always in sync and the implementation is faulty.
|
||||||
|
@ -109,7 +172,12 @@ void CTime::probeTimerInfo(CTime::CTimerInfo &result)
|
||||||
{
|
{
|
||||||
if (cpuMask & currentBit)
|
if (cpuMask & currentBit)
|
||||||
{
|
{
|
||||||
IThread::getCurrentThread()->setCPUMask(currentBit);
|
#ifdef NL_OS_WINDOWS
|
||||||
|
if (!IThread::getCurrentThread()->setCPUMask(currentBit))
|
||||||
|
#else
|
||||||
|
if (!IProcess::getCurrentProcess()->setCPUMask(currentBit))
|
||||||
|
#endif
|
||||||
|
break; // Thread was set to last cpu.
|
||||||
#ifdef NL_OS_WINDOWS
|
#ifdef NL_OS_WINDOWS
|
||||||
// Make sure the thread is rescheduled.
|
// Make sure the thread is rescheduled.
|
||||||
SwitchToThread();
|
SwitchToThread();
|
||||||
|
@ -152,13 +220,53 @@ void CTime::probeTimerInfo(CTime::CTimerInfo &result)
|
||||||
++regular;
|
++regular;
|
||||||
lowResTime = lowResTimeN;
|
lowResTime = lowResTimeN;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#ifdef NL_OS_UNIX
|
||||||
|
sched_yield();
|
||||||
|
#else
|
||||||
|
nlSleep(0);
|
||||||
|
#endif
|
||||||
|
# ifdef NL_MONOTONIC_CLOCK
|
||||||
|
if (hasMonotonicClock())
|
||||||
|
{
|
||||||
|
timespec monoClockN;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &monoClockN);
|
||||||
|
if (monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec == monoClockN.tv_nsec)
|
||||||
|
++identical;
|
||||||
|
if (monoClockN.tv_sec < monoClock.tv_sec || (monoClock.tv_sec == monoClockN.tv_sec && monoClockN.tv_nsec < monoClock.tv_nsec))
|
||||||
|
++backwards;
|
||||||
|
if (monoClock.tv_sec == monoClockN.tv_sec && (monoClockN.tv_nsec - monoClock.tv_nsec > 50000000L))
|
||||||
|
++skipping;
|
||||||
|
else if ((monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec < monoClockN.tv_nsec) || monoClock.tv_sec < monoClockN.tv_sec)
|
||||||
|
++regular;
|
||||||
|
monoClock.tv_sec = monoClockN.tv_sec;
|
||||||
|
monoClock.tv_nsec = monoClockN.tv_nsec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
TTime localTimeN = getLocalTime();
|
||||||
|
if (localTimeN == localTime)
|
||||||
|
++identical;
|
||||||
|
if (localTimeN < localTime || localTimeN - localTime < 0)
|
||||||
|
++backwards;
|
||||||
|
if (localTimeN - localTime > 50)
|
||||||
|
++skipping;
|
||||||
|
else if (localTimeN > localTime)
|
||||||
|
++regular;
|
||||||
|
localTime = localTimeN;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
currentBit <<= 1;
|
currentBit <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NL_OS_WINDOWS
|
||||||
IThread::getCurrentThread()->setCPUMask(threadMask);
|
IThread::getCurrentThread()->setCPUMask(threadMask);
|
||||||
|
#else
|
||||||
|
IProcess::getCurrentProcess()->setCPUMask(threadMask);
|
||||||
|
#endif
|
||||||
|
|
||||||
nldebug("Timer resolution: %i Hz", (int)(result.HighPrecisionResolution));
|
nldebug("Timer resolution: %i Hz", (int)(result.HighPrecisionResolution));
|
||||||
nldebug("Time identical: %i, backwards: %i, regular: %i, skipping: %i, frequency bug: %i", identical, backwards, regular, skipping, frequencybug);
|
nldebug("Time identical: %i, backwards: %i, regular: %i, skipping: %i, frequency bug: %i", identical, backwards, regular, skipping, frequencybug);
|
||||||
|
@ -245,10 +353,10 @@ TTime CTime::getLocalTime ()
|
||||||
// return timeGetTime(); // Only this was left active before it was commented.
|
// return timeGetTime(); // Only this was left active before it was commented.
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The above is no longer relevant.
|
* The above is no longer relevant.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (a_HaveQueryPerformance)
|
if (a_HaveQueryPerformance)
|
||||||
{
|
{
|
||||||
// On a (fast) 15MHz timer this rolls over after 7000 days.
|
// On a (fast) 15MHz timer this rolls over after 7000 days.
|
||||||
|
@ -266,49 +374,17 @@ TTime CTime::getLocalTime ()
|
||||||
|
|
||||||
#elif defined (NL_OS_UNIX)
|
#elif defined (NL_OS_UNIX)
|
||||||
|
|
||||||
static bool initdone = false;
|
#ifdef NL_MONOTONIC_CLOCK
|
||||||
static bool isMonotonicClockSupported = false;
|
|
||||||
if ( ! initdone )
|
if (hasMonotonicClock())
|
||||||
{
|
{
|
||||||
|
timespec tv;
|
||||||
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
|
||||||
#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
|
|
||||||
|
|
||||||
/* Initialize the local time engine.
|
|
||||||
* On Unix, this method will find out if the Monotonic Clock is supported
|
|
||||||
* (seems supported by kernel 2.6, not by kernel 2.4). See getLocalTime().
|
|
||||||
*/
|
|
||||||
struct timespec tv;
|
|
||||||
if ( (clock_gettime( CLOCK_MONOTONIC, &tv ) == 0) &&
|
|
||||||
(clock_getres( CLOCK_MONOTONIC, &tv ) == 0) )
|
|
||||||
{
|
|
||||||
// nldebug( "Monotonic local time supported (resolution %.6f ms)", ((float)tv.tv_sec)*1000.0f + ((float)tv.tv_nsec)/1000000.0f );
|
|
||||||
isMonotonicClockSupported = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// nlwarning( "Monotonic local time not supported, caution with time sync" );
|
|
||||||
}
|
|
||||||
|
|
||||||
initdone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
|
||||||
#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
|
|
||||||
|
|
||||||
if ( isMonotonicClockSupported )
|
|
||||||
{
|
|
||||||
struct timespec tv;
|
|
||||||
// This is not affected by system time changes.
|
// This is not affected by system time changes.
|
||||||
if ( clock_gettime( CLOCK_MONOTONIC, &tv ) != 0 )
|
if ( clock_gettime( CLOCK_MONOTONIC, &tv ) != 0 )
|
||||||
nlerror ("Can't get clock time again");
|
nlerror ("Can't get clock time again");
|
||||||
return (TTime)tv.tv_sec * (TTime)1000 + (TTime)((tv.tv_nsec/*+500*/) / 1000000);
|
return (TTime)tv.tv_sec * (TTime)1000 + (TTime)((tv.tv_nsec/*+500*/) / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is affected by system time changes.
|
// This is affected by system time changes.
|
||||||
|
@ -346,7 +422,7 @@ TTicks CTime::getPerformanceTime ()
|
||||||
return (hi << 32) | (lo & 0xffffffff);
|
return (hi << 32) | (lo & 0xffffffff);
|
||||||
#elif defined(HAVE_X86) and !defined(NL_OS_MAC)
|
#elif defined(HAVE_X86) and !defined(NL_OS_MAC)
|
||||||
uint64 x;
|
uint64 x;
|
||||||
// RDTSC - Read time-stamp counter into EDX:EAX.
|
// RDTSC - Read time-stamp counter into EDX:EAX.
|
||||||
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
||||||
return x;
|
return x;
|
||||||
#else // HAVE_X86
|
#else // HAVE_X86
|
||||||
|
|
Loading…
Reference in a new issue