Parcourir la source

Merge pull request #490 from open62541/monotonic_clock

types: add a monotonic cpu timer to measure delays, fix #480
Julius Pfrommer il y a 9 ans
Parent
commit
b8e278d39c
6 fichiers modifiés avec 49 ajouts et 41 suppressions
  1. 14 1
      include/ua_types.h
  2. 1 6
      src/server/ua_server.c
  3. 2 2
      src/server/ua_server_worker.c
  4. 26 30
      src/ua_types.c
  5. 5 1
      src/ua_util.h
  6. 1 1
      tools/travis_linux_script.sh

+ 14 - 1
include/ua_types.h

@@ -115,11 +115,24 @@ UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
 /*********************************/
 /* DateTime: An instance in time */
 /*********************************/
+
 /* A DateTime value is encoded as a 64-bit signed integer which represents the
    number of 100 nanosecond intervals since January 1, 1601 (UTC) */
 typedef UA_Int64 UA_DateTime;
 
-UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
+/* Multiply to convert units for time difference computations */
+#define UA_USEC_TO_DATETIME 10LL
+#define UA_MSEC_TO_DATETIME (UA_USEC_TO_DATETIME * 1000LL)
+#define UA_SEC_TO_DATETIME (UA_MSEC_TO_DATETIME * 1000LL)
+
+/* Datetime of 1 Jan 1970 00:00 UTC */
+#define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_SEC_TO_DATETIME)
+
+/* The current time */
+UA_DateTime UA_EXPORT UA_DateTime_now(void);
+
+/* CPU clock invariant to system time changes. Use only for time diffs, not current time */
+UA_DateTime UA_EXPORT UA_DateTime_nowMonotonic(void);
 
 typedef struct UA_DateTimeStruct {
     UA_UInt16 nanoSec;

+ 1 - 6
src/server/ua_server.c

@@ -574,12 +574,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
     ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
     ct.tm_isdst = -1; // information is not available.
-
-    //FIXME: next 3 lines are copy-pasted from ua_types.c
-#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
-#define HUNDRED_NANOSEC_PER_USEC 10LL
-#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
-    server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
+    server->buildDate = (mktime(&ct) * UA_SEC_TO_DATETIME) + UA_DATETIME_UNIX_EPOCH;
     
     /**************/
     /* References */

+ 2 - 2
src/server/ua_server_worker.c

@@ -229,7 +229,7 @@ static UA_StatusCode addRepeatedJob(UA_Server *server, struct AddRepeatedJob * U
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
     /* search for matching entry */
-    UA_DateTime firstTime = UA_DateTime_now() + arw->interval;
+    UA_DateTime firstTime = UA_DateTime_nowMonotonic() + arw->interval;
     tempTw = LIST_FIRST(&server->repeatedJobs);
     while(tempTw) {
         if(arw->interval == tempTw->interval) {
@@ -321,7 +321,7 @@ UA_StatusCode UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32
 
 /* Returns the timeout until the next repeated job in ms */
 static UA_UInt16 processRepeatedJobs(UA_Server *server) {
-    UA_DateTime current = UA_DateTime_now();
+    UA_DateTime current = UA_DateTime_nowMonotonic();
     struct RepeatedJobs *tw = NULL;
 
     while((tw = LIST_FIRST(&server->repeatedJobs)) != NULL) {

+ 26 - 30
src/ua_types.c

@@ -53,41 +53,37 @@ UA_Boolean UA_String_equal(const UA_String *string1, const UA_String *string2) {
 }
 
 /* DateTime */
-#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
-#define HUNDRED_NANOSEC_PER_USEC 10LL
-#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
-
-#if defined(__MINGW32__) && !defined(_TIMEZONE_DEFINED)
-# define _TIMEZONE_DEFINED
-struct timezone {
-  int tz_minuteswest;
-  int tz_dsttime;
-};
-#endif
-
+UA_DateTime UA_DateTime_now(void) {
 #ifdef _WIN32
-static const UA_UInt64 epoch = 116444736000000000;
-int gettimeofday(struct timeval *tp, struct timezone *tzp);
-int gettimeofday(struct timeval *tp, struct timezone *tzp) {
-    FILETIME       ft;
-    SYSTEMTIME     st;
-    ULARGE_INTEGER ul;
+    /* Windows filetime has the same definition as UA_DateTime */
+    FILETIME ft;
+    SYSTEMTIME st;
     GetSystemTime(&st);
     SystemTimeToFileTime(&st, &ft);
-    ul.LowPart  = ft.dwLowDateTime;
+    ULARGE_INTEGER ul;
+    ul.LowPart = ft.dwLowDateTime;
     ul.HighPart = ft.dwHighDateTime;
-    tp->tv_sec  = (long)((ul.QuadPart - epoch) / 10000000L);
-    tp->tv_usec = st.wMilliseconds * 1000;
-    return 0;
-}
-#endif
-
-UA_DateTime UA_DateTime_now(void) {
-    UA_DateTime dateTime;
+    return (UA_DateTime)ul.QuadPart;
+#else
     struct timeval tv;
     gettimeofday(&tv, NULL);
-    dateTime = (tv.tv_sec + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC + tv.tv_usec * HUNDRED_NANOSEC_PER_USEC;
-    return dateTime;
+    return (tv.tv_sec * UA_SEC_TO_DATETIME) + (tv.tv_usec * UA_USEC_TO_DATETIME) + UA_DATETIME_UNIX_EPOCH;
+#endif
+}
+
+UA_DateTime UA_DateTime_nowMonotonic(void) {
+#ifdef _WIN32
+    LARGE_INTEGER freq, ticks;
+    QueryPerformanceFrequency(&freq);
+    QueryPerformanceCounter(&ticks);
+    UA_Double ticks2dt = UA_SEC_TO_DATETIME;
+    ticks2dt /= freq.QuadPart;
+    return (UA_DateTime)(ticks.QuadPart * ticks2dt);
+#else
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+    return (ts.tv_sec * UA_SEC_TO_DATETIME) + (ts.tv_nsec / 100);
+#endif
 }
 
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
@@ -98,7 +94,7 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
     dateTimeStruct.milliSec = (UA_UInt16)((atime % 10000000) / 10000);
 
     /* Calculating the unix time with #include <time.h> */
-    time_t secSinceUnixEpoch = (atime/10000000) - UNIX_EPOCH_BIAS_SEC;
+    time_t secSinceUnixEpoch = (atime - UA_DATETIME_UNIX_EPOCH) / UA_SEC_TO_DATETIME;
     struct tm ts = *gmtime(&secSinceUnixEpoch);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     dateTimeStruct.min    = (UA_UInt16)ts.tm_min;

+ 5 - 1
src/ua_util.h

@@ -64,11 +64,15 @@
 /* System Libraries */
 /********************/
 
-#include <time.h>
 #ifdef _WIN32
 # include <winsock2.h> //needed for amalgation
 # include <windows.h>
 # undef SLIST_ENTRY
+#endif
+
+#include <time.h>
+#ifdef _WIN32
+int gettimeofday(struct timeval *tp, struct timezone *tzp);
 #else
 # include <sys/time.h>
 #endif

+ 1 - 1
tools/travis_linux_script.sh

@@ -56,7 +56,7 @@ echo "Building the C++ example"
 mkdir -p build && cd build
 cp ../../open62541.* .
 gcc -std=c99 -c open62541.c
-g++-4.8 ../examples/server.cpp -I./ open62541.o -o cpp-server
+g++-4.8 ../examples/server.cpp -I./ open62541.o -lrt -o cpp-server
 cd .. && rm build -rf 
 
 echo "Compile multithreaded version"