libCom/osi: fetch monotonic time
This commit is contained in:
@@ -119,6 +119,7 @@ Com_SRCS += osdMutex.c
|
||||
Com_SRCS += osdSpin.c
|
||||
Com_SRCS += osdEvent.c
|
||||
Com_SRCS += osdTime.cpp
|
||||
Com_SRCS += osdMonotonic.c
|
||||
Com_SRCS += osdProcess.c
|
||||
Com_SRCS += osdNetIntf.c
|
||||
Com_SRCS += osdMessageQueue.c
|
||||
|
||||
@@ -258,6 +258,17 @@ epicsShareFunc void epicsShareAPI epicsTimeShow (
|
||||
epicsShareFunc int epicsShareAPI epicsTime_localtime ( const time_t * clock, struct tm * result );
|
||||
epicsShareFunc int epicsShareAPI epicsTime_gmtime ( const time_t * clock, struct tm * result );
|
||||
|
||||
/* Advertised monotonic counter resolution (may not be accurate).
|
||||
* Minimum non-zero difference between two calls to epicsMonotonicGet()
|
||||
*/
|
||||
epicsShareFunc epicsUInt64 epicsMonotonicResolution(void);
|
||||
/* Fetch monotonic counter, return is nano-seconds since an unspecified time */
|
||||
epicsShareFunc epicsUInt64 epicsMonotonicGet(void);
|
||||
|
||||
#ifdef EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
epicsShareFunc void osdMonotonicInit(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
32
src/libCom/osi/os/Darwin/osdMonotonic.c
Normal file
32
src/libCom/osi/os/Darwin/osdMonotonic.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <kern/clock.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return 1; /* TODO, how to find ? */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
uint64_t val = mach_absolute_time(), ret;
|
||||
absolutetime_to_nanoseconds(val, &ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
@@ -45,6 +46,8 @@ static int timeRegister(void)
|
||||
|
||||
generalTimeCurrentTpRegister("MachTime", \
|
||||
LAST_RESORT_PRIORITY, osdTimeGetCurrent);
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <rtems/rtems_bsdnet_internal.h>
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "osdTime.h"
|
||||
#include "osiNTPTime.h"
|
||||
@@ -37,6 +38,8 @@ void osdTimeRegister(void)
|
||||
/* Init NTP first so it can be used to sync ClockTime */
|
||||
NTPTime_Init(100);
|
||||
ClockTime_Init(CLOCKTIME_SYNC);
|
||||
|
||||
osdMonotonicInit();
|
||||
}
|
||||
|
||||
int osdNTPGet(struct timespec *ts)
|
||||
|
||||
53
src/libCom/osi/os/WIN32/osdMonotonic.c
Normal file
53
src/libCom/osi/os/WIN32/osdMonotonic.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
static unsigned char osdUsePrefCounter;
|
||||
static epicsUInt64 osdMonotonicResolution;
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
LARGE_INTEGER freq, val;
|
||||
|
||||
if(!QueryPerformanceFrequency(&freq) ||
|
||||
!QueryPerformanceCounter(&val))
|
||||
{
|
||||
double period = 1.0/freq.QuadPart;
|
||||
osdMonotonicResolution = period*1e9;
|
||||
osdUsePrefCounter = 1;
|
||||
} else {
|
||||
osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */
|
||||
}
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return osdMonotonicResolution;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
LARGE_INTEGER val;
|
||||
if(osdUsePrefCounter) {
|
||||
if(!QueryPerformanceCounter(&val)) {
|
||||
errMessage(errlogMinor, "Warning: failed to fetch performance counter\n");
|
||||
return 0;
|
||||
} else
|
||||
return val.QuadPart;
|
||||
} else {
|
||||
epicsUInt64 ret = GetTickCount();
|
||||
ret *= 1000000;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
// EPICS
|
||||
//
|
||||
#define epicsExportSharedSymbols
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
#include "epicsTimer.h"
|
||||
@@ -106,6 +107,8 @@ static int timeRegister(void)
|
||||
generalTimeCurrentTpRegister("PerfCounter", 150, osdTimeGetCurrent);
|
||||
|
||||
pCurrentTime->startPLL ();
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
31
src/libCom/osi/os/iOS/osdMonotonic.c
Normal file
31
src/libCom/osi/os/iOS/osdMonotonic.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#import <mach/mach_time.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return 1; /* TODO, how to find ? */
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
uint64_t val = mach_absolute_time(), ret;
|
||||
absolutetime_to_nanoseconds(val, &ret);
|
||||
return ret;
|
||||
}
|
||||
75
src/libCom/osi/os/posix/osdMonotonic.c
Normal file
75
src/libCom/osi/os/posix/osdMonotonic.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
static clockid_t osdMonotonicID;
|
||||
static epicsUInt64 osdMonotonicResolution;
|
||||
|
||||
void osdMonotonicInit(void)
|
||||
{
|
||||
unsigned i;
|
||||
clockid_t ids[] = {
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
CLOCK_MONOTONIC_RAW, /* Linux specific */
|
||||
#endif
|
||||
#ifdef CLOCK_HIGHRES
|
||||
CLOCK_HIGHRES, /* solaris specific */
|
||||
#endif
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
CLOCK_MONOTONIC, /* Linux, RTEMS, and probably others */
|
||||
#endif
|
||||
/* fallback and vxWorks, not actually monotonic, but always available */
|
||||
CLOCK_REALTIME
|
||||
};
|
||||
|
||||
for(i=0; i<NELEMENTS(ids); i++) {
|
||||
epicsUInt64 res;
|
||||
struct timespec ts;
|
||||
int ret = clock_getres(ids[i], &ts);
|
||||
if(ret) continue;
|
||||
|
||||
res = ts.tv_sec;
|
||||
res *= 1000000000;
|
||||
res += ts.tv_nsec;
|
||||
|
||||
/* fetch the time once to see that it actually succeeds */
|
||||
ret = clock_gettime(ids[i], &ts);
|
||||
if(ret) continue;
|
||||
|
||||
osdMonotonicID = ids[i];
|
||||
osdMonotonicResolution = res;
|
||||
return;
|
||||
}
|
||||
|
||||
errMessage(errlogMinor, "Warning: failed to setup monotonic time source\n");
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicResolution(void)
|
||||
{
|
||||
return osdMonotonicResolution;
|
||||
}
|
||||
|
||||
epicsUInt64 epicsMonotonicGet(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
int ret = clock_gettime(osdMonotonicID, &ts);
|
||||
if(ret) {
|
||||
errlogPrintf("Warning: failed to fetch monotonic time %d %d\n",
|
||||
(int)osdMonotonicID, ret);
|
||||
return 0;
|
||||
} else {
|
||||
epicsUInt64 ret = ts.tv_sec;
|
||||
ret *= 1000000000;
|
||||
ret += ts.tv_nsec;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
@@ -56,6 +57,8 @@ int clock_settime(clockid_t clock, const timespec *tp)
|
||||
static int timeRegister(void)
|
||||
{
|
||||
TIME_INIT;
|
||||
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
|
||||
#include "epicsTime.h"
|
||||
#include "osiNTPTime.h"
|
||||
#include "osiClockTime.h"
|
||||
@@ -63,6 +64,7 @@ static int timeRegister(void)
|
||||
} else {
|
||||
ClockTime_Init(CLOCKTIME_NOSYNC);
|
||||
}
|
||||
osdMonotonicInit();
|
||||
return 1;
|
||||
}
|
||||
static int done = timeRegister();
|
||||
|
||||
@@ -38,12 +38,53 @@ static const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
static const unsigned nSecPerSec = 1000u * uSecPerSec;
|
||||
static const double precisionEPICS = 1.0 / nSecPerSec;
|
||||
|
||||
static void crossCheck(double delay)
|
||||
{
|
||||
double mindelta = 2*epicsMonotonicResolution()*1e-9,
|
||||
tres = epicsThreadSleepQuantum();
|
||||
epicsUInt64 A = epicsMonotonicGet();
|
||||
epicsThreadSleep(delay);
|
||||
epicsUInt64 B = epicsMonotonicGet();
|
||||
|
||||
double actual = (B-A)*1e-9, percent;
|
||||
|
||||
if(mindelta<tres*2)
|
||||
mindelta = tres*2;
|
||||
if(delay<mindelta)
|
||||
delay = mindelta;
|
||||
|
||||
percent = (delay-actual)/delay*100.0;
|
||||
|
||||
testOk(fabs(percent)<1000.0, "crossCheck(%f) actual %f (%f %%)",
|
||||
delay, actual, percent);
|
||||
}
|
||||
|
||||
static void testMonotonic()
|
||||
{
|
||||
crossCheck(2.1); /* greater than 2 so that seconds value is different */
|
||||
crossCheck(0.1);
|
||||
crossCheck(0.01);
|
||||
crossCheck(0.001);
|
||||
crossCheck(epicsThreadSleepQuantum());
|
||||
|
||||
testDiag("Resolution %u ns", (unsigned)epicsMonotonicResolution());
|
||||
|
||||
epicsUInt64 A = epicsMonotonicGet();
|
||||
epicsThreadSleep(0.0);
|
||||
epicsUInt64 B = epicsMonotonicGet();
|
||||
testDiag("epicsThreadSleep(0.0) Delta %u ns", (unsigned)(B-A));
|
||||
|
||||
A = epicsMonotonicGet();
|
||||
B = epicsMonotonicGet();
|
||||
testDiag("Small Delta %u ns", (unsigned)(B-A));
|
||||
}
|
||||
|
||||
MAIN(epicsTimeTest)
|
||||
{
|
||||
const int wasteTime = 100000;
|
||||
const int nTimes = 10;
|
||||
|
||||
testPlan(17 + nTimes * 19);
|
||||
testPlan(22 + nTimes * 19);
|
||||
|
||||
try {
|
||||
const epicsTimeStamp epochTS = {0, 0};
|
||||
@@ -241,5 +282,7 @@ MAIN(epicsTimeTest)
|
||||
testFail("OS time_t conversion exception for value 10 years hence");
|
||||
}
|
||||
|
||||
testMonotonic();
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user