commit ba86a79ba534c1b802121737718d5640486da028
parent 5deb09eaf8f1d91b87d7458a9f810a9cbace8c82
Author: vaplv <vaplv@free.fr>
Date: Fri, 29 Nov 2013 11:38:32 +0100
Use more accurate timing functions on Unix platforms
Diffstat:
4 files changed, 89 insertions(+), 18 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -44,7 +44,7 @@ set(RSYS_FILES_INC
rsys.h)
add_library(rsys SHARED ${RSYS_FILES_SRC} ${RSYS_FILES_INC})
-target_link_libraries(rsys dl)
+target_link_libraries(rsys dl rt)
set_target_properties(rsys PROPERTIES DEFINE_SYMBOL RSYS_SHARED_BUILD)
################################################################################
@@ -76,7 +76,6 @@ add_test(test_atomic test_atomic)
add_executable(test_ref test_ref.c)
add_test(test_ref test_ref)
-
if(NOT OPENMP_FOUND)
message(STATUS "No OpenMP support: multi-threaded tests cannot be generated")
else()
diff --git a/src/clock_time.c b/src/clock_time.c
@@ -3,7 +3,7 @@
#include <string.h>
#define TIME_TO_NSEC(Time) \
- (((Time)->tv_usec + (Time)->tv_sec * 1000000L) * 1000L)
+ ((Time)->tv_nsec + (Time)->tv_sec * 1000000000L)
#define NSEC_PER_USEC 1000L
#define NSEC_PER_MSEC (1000L * NSEC_PER_USEC)
@@ -12,6 +12,46 @@
#define NSEC_PER_HOUR (60L * NSEC_PER_MIN)
#define NSEC_PER_DAY (24L * NSEC_PER_HOUR)
+void
+time_val_set(time_T* time, const int64_t val, const enum time_unit unit)
+{
+ int64_t ns = 0;
+ int64_t s = 0;
+
+ if(unit & (TIME_NSEC | TIME_USEC | TIME_MSEC)) {
+ switch(unit) {
+ case TIME_NSEC:
+ s = val / 1000000000L;
+ ns = val - s * 1000000000L;
+ break;
+ case TIME_USEC:
+ s = val / 1000000L;
+ ns = (val - s * 1000000L) * 1000L;
+ break;
+ case TIME_MSEC:
+ s = val / 1000L;
+ ns = (val - s * 1000L) * 1000000L;
+ break;
+ default:
+ ASSERT(0 && "Unreachable code");
+ break;
+ }
+ } else {
+ int64_t factor = 0;
+ switch(unit) {
+ case TIME_SEC: factor = 0L; break;
+ case TIME_MIN: factor = 60L; break;
+ case TIME_HOUR: factor = 3600L; break;
+ case TIME_DAY: factor = 86400L; break;
+ default: ASSERT(0 && "Unreachable code"); break;
+ }
+ s = val * factor;
+ ns = 0;
+ }
+ time->tv_sec = s;
+ time->tv_nsec = ns;
+}
+
int64_t
time_val(const time_T* time, enum time_unit unit)
{
diff --git a/src/clock_time.h b/src/clock_time.h
@@ -2,13 +2,22 @@
#define TIME_H
#include "rsys.h"
-#ifndef PLATFORM_UNIX
+#if !defined(PLATFORM_UNIX) \
+ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L)
#error "Unsupported platform"
#endif
-#include <sys/time.h>
+
+#ifdef _POSIX_C_SOURCE
+ #include <time.h>
+#else
+ #define _POSIX_C_SOURCE 200112L
+ #include <time.h>
+ #undef _POSIX_C_SOURCE
+#endif
+
#include <stddef.h>
-typedef struct timeval time_T;
+typedef struct timespec time_T;
enum time_unit {
TIME_NSEC = BIT(0),
@@ -25,20 +34,26 @@ time_current(time_T* time)
{
int err = 0; (void) err;
ASSERT(time);
- err = gettimeofday(time, NULL);
+ err = clock_gettime(CLOCK_REALTIME, time);
ASSERT(err == 0);
}
static FINLINE void
+time_sleep(const time_T* time)
+{
+ clock_nanosleep(CLOCK_REALTIME, 0, time, NULL);
+}
+
+static FINLINE void
time_sub(time_T* res, const time_T* a, const time_T* b)
{
ASSERT(res && a && b);
res->tv_sec = a->tv_sec - b->tv_sec;
- res->tv_usec = a->tv_usec - b->tv_usec;
- if(res->tv_usec < 0) {
+ res->tv_nsec = a->tv_nsec - b->tv_nsec;
+ if(res->tv_nsec < 0) {
--res->tv_sec;
- res->tv_usec += 1000000L;
+ res->tv_nsec += 1000000000L;
}
}
@@ -48,10 +63,10 @@ time_add(time_T* res, const time_T* a, const time_T* b)
ASSERT(res && a && b);
res->tv_sec = a->tv_sec + b->tv_sec;
- res->tv_usec = a->tv_usec + b->tv_usec;
- if(res->tv_usec >= 1000000L) {
+ res->tv_nsec = a->tv_nsec + b->tv_nsec;
+ if(res->tv_nsec >= 1000000000L) {
++res->tv_sec;
- res->tv_usec -= 1000000L;
+ res->tv_nsec -= 1000000000L;
}
}
@@ -59,6 +74,12 @@ time_add(time_T* res, const time_T* a, const time_T* b)
extern "C" {
#endif
+RSYS_API void
+time_val_set
+ (time_T* time,
+ const int64_t val,
+ const enum time_unit unit);
+
RSYS_API int64_t
time_val
(const time_T* time,
diff --git a/src/test_time.c b/src/test_time.c
@@ -10,19 +10,30 @@ main(int argc, char** argv)
int64_t time = 0;
(void)argc, (void)argv;
+ time_val_set(&res, 1250, TIME_MSEC);
time_current(&start);
- sleep(2);
+ time_sleep(&res);
time_current(&end);
time_sub(&res, &end, &start);
time = time_val(&res, TIME_NSEC);
- CHECK(llabs((long long)(time - 2000000000)) <= 1000000 , 1);
+ CHECK(llabs((long long)(time - 1250000000)) <= 1000000 , 1);
time = time_val(&res, TIME_USEC);
- CHECK(llabs((long long)(time - 2000000)) <= 1000 , 1);
+ CHECK(llabs((long long)(time - 1250000)) <= 1000 , 1);
time = time_val(&res, TIME_MSEC);
- CHECK(llabs((long long)(time - 2000)) <= 1 , 1);
+ CHECK(llabs((long long)(time - 1250)) <= 1 , 1);
time = time_val(&res, TIME_SEC);
- CHECK(llabs((long long)(time - 2)) <= 0 , 1);
+ CHECK(time, 1);
+ CHECK(time_val(&res, TIME_NSEC) >= time_val(&res, TIME_USEC) * 1000, 1);
+ CHECK(time_val(&res, TIME_USEC) >= time_val(&res, TIME_MSEC) * 1000, 1);
+ CHECK(time_val(&res, TIME_MSEC) >= time_val(&res, TIME_SEC) * 1000, 1);
+ time_val_set(&res, 1234, TIME_USEC);
+ time_current(&start);
+ time_sleep(&res);
+ time_current(&end);
+ time_sub(&res, &end, &start);
+ time = time_val(&res, TIME_NSEC);
+ CHECK(llabs((long long)(time - 1234000)) <= 1000000 , 1);
return 0;
}