From 6aec8d9bcb4ee7f0c68aed5abddcc034fbbe45f4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 25 Aug 2015 18:09:35 -0400 Subject: [PATCH] libCom/osi: fetch monotonic time --- src/libCom/osi/Makefile | 1 + src/libCom/osi/epicsTime.h | 11 ++++ src/libCom/osi/os/Darwin/osdMonotonic.c | 32 +++++++++++ src/libCom/osi/os/Darwin/osdTime.cpp | 3 + src/libCom/osi/os/RTEMS/osdTime.cpp | 3 + src/libCom/osi/os/WIN32/osdMonotonic.c | 53 +++++++++++++++++ src/libCom/osi/os/WIN32/osdTime.cpp | 3 + src/libCom/osi/os/iOS/osdMonotonic.c | 31 ++++++++++ src/libCom/osi/os/posix/osdMonotonic.c | 75 +++++++++++++++++++++++++ src/libCom/osi/os/posix/osdTime.cpp | 3 + src/libCom/osi/os/vxWorks/osdTime.cpp | 2 + src/libCom/test/epicsTimeTest.cpp | 45 ++++++++++++++- 12 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 src/libCom/osi/os/Darwin/osdMonotonic.c create mode 100644 src/libCom/osi/os/WIN32/osdMonotonic.c create mode 100644 src/libCom/osi/os/iOS/osdMonotonic.c create mode 100644 src/libCom/osi/os/posix/osdMonotonic.c diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index c06a862ed..ecbf4c23b 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -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 diff --git a/src/libCom/osi/epicsTime.h b/src/libCom/osi/epicsTime.h index 149f6f2d3..862bc22d2 100644 --- a/src/libCom/osi/epicsTime.h +++ b/src/libCom/osi/epicsTime.h @@ -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 */ diff --git a/src/libCom/osi/os/Darwin/osdMonotonic.c b/src/libCom/osi/os/Darwin/osdMonotonic.c new file mode 100644 index 000000000..50ca82ef6 --- /dev/null +++ b/src/libCom/osi/os/Darwin/osdMonotonic.c @@ -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 +#include + +#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; +} diff --git a/src/libCom/osi/os/Darwin/osdTime.cpp b/src/libCom/osi/os/Darwin/osdTime.cpp index 72b3dc874..7bddc7da2 100644 --- a/src/libCom/osi/os/Darwin/osdTime.cpp +++ b/src/libCom/osi/os/Darwin/osdTime.cpp @@ -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(); diff --git a/src/libCom/osi/os/RTEMS/osdTime.cpp b/src/libCom/osi/os/RTEMS/osdTime.cpp index 4947c568e..a9d5c2ea6 100644 --- a/src/libCom/osi/os/RTEMS/osdTime.cpp +++ b/src/libCom/osi/os/RTEMS/osdTime.cpp @@ -20,6 +20,7 @@ #include #include #include +#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) diff --git a/src/libCom/osi/os/WIN32/osdMonotonic.c b/src/libCom/osi/os/WIN32/osdMonotonic.c new file mode 100644 index 000000000..342ee7d60 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdMonotonic.c @@ -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 + +#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; + } +} diff --git a/src/libCom/osi/os/WIN32/osdTime.cpp b/src/libCom/osi/os/WIN32/osdTime.cpp index 2ee0d3066..348fe7c2f 100644 --- a/src/libCom/osi/os/WIN32/osdTime.cpp +++ b/src/libCom/osi/os/WIN32/osdTime.cpp @@ -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(); diff --git a/src/libCom/osi/os/iOS/osdMonotonic.c b/src/libCom/osi/os/iOS/osdMonotonic.c new file mode 100644 index 000000000..0c2c7718f --- /dev/null +++ b/src/libCom/osi/os/iOS/osdMonotonic.c @@ -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 + +#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; +} diff --git a/src/libCom/osi/os/posix/osdMonotonic.c b/src/libCom/osi/os/posix/osdMonotonic.c new file mode 100644 index 000000000..203702dd5 --- /dev/null +++ b/src/libCom/osi/os/posix/osdMonotonic.c @@ -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 #include +#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(); diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp index 55ad43cdd..8eb8de6d4 100644 --- a/src/libCom/test/epicsTimeTest.cpp +++ b/src/libCom/test/epicsTimeTest.cpp @@ -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