From 29660bd13b283860b273f7c3d310cd6e696efe1d Mon Sep 17 00:00:00 2001 From: telleriam Date: Wed, 12 Mar 2008 12:35:07 +0000 Subject: [PATCH] Additions to fosa time to be used with FRSH git-svn-id: http://www.frescor.org/private/svn/frescor/fosa/trunk@1042 35b4ef3e-fd22-0410-ab77-dab3279adceb --- include/fosa_opaque_types_time.h | 9 +- include/fosa_time_numeric.h | 157 ++++++++- include/fosa_time_timespec.h | 384 ++++++++++++++++++++- src_marte/tests/test_time/fosa_test_time.c | 41 +++ 4 files changed, 578 insertions(+), 13 deletions(-) diff --git a/include/fosa_opaque_types_time.h b/include/fosa_opaque_types_time.h index 5d2b146..d1f6ab0 100644 --- a/include/fosa_opaque_types_time.h +++ b/include/fosa_opaque_types_time.h @@ -79,16 +79,14 @@ - numeric type (long, .long long, short) **/ - #define FOSA_TIME_TIMESPEC typedef struct timespec FOSA_REL_TIME_T_OPAQUE; typedef struct timespec FOSA_ABS_TIME_T_OPAQUE; - - /* + #define FOSA_TIME_NUMERIC #define FOSA_TIME_BASE 9 // 9 for nanosecods // 6 for microseconds @@ -120,14 +118,16 @@ typedef unsigned long long FOSA_ABS_TIME_T_OPAQUE; - struct timespec - numeric type (long, .long long, short) **/ - +/* #define FOSA_TIME_TIMESPEC typedef struct timespec FOSA_REL_TIME_T_OPAQUE; typedef struct timespec FOSA_ABS_TIME_T_OPAQUE; +*/ /* + #define FOSA_TIME_NUMERIC #define FOSA_TIME_BASE 9 // 9 for nanosecods // 6 for microseconds @@ -137,6 +137,7 @@ typedef long long FOSA_REL_TIME_T_OPAQUE; typedef unsigned long long FOSA_ABS_TIME_T_OPAQUE; */ + /** Possible additions: FOSA_ABS_TIME_MAX, FOSA_ABS_TIME_MIN, FOSA_REL_TIME_MAX, FOSA_REL_TIME_MIN to protect diff --git a/include/fosa_time_numeric.h b/include/fosa_time_numeric.h index d78f7b9..360f5d4 100644 --- a/include/fosa_time_numeric.h +++ b/include/fosa_time_numeric.h @@ -77,6 +77,9 @@ #define msec_to_fosa_time(msec) (msec) * 1000000 #define fosa_time_to_usec(time) (time) / 1000 #define usec_to_fosa_time(usec) (usec) * 1000 +#define fosa_time_to_nsec(time) (time) +#define nsec_to_fosa_time(nsec) (nsec) + #define timespec_to_fosa_time(time_type, tspec) ((time_type) (tspec).tv_sec) * 1000000000 + (time_type) (tspec).tv_nsec @@ -86,7 +89,8 @@ do { \ (tspec).tv_nsec = (time) % 1000000000; \ } while(0) - +#define fosa_time_to_double(time) (double) (time) * 1e-9; +#define fosa_double_to_time(time_type, time) (time_type) (time * 1e9) #endif @@ -96,6 +100,8 @@ do { \ #define msec_to_fosa_time(msec) (msec) * 1000 #define fosa_time_to_usec(time) (time) #define usec_to_fosa_time(usec) (usec) +#define fosa_time_to_nsec(time) (time) * 1000 +#define nsec_to_fosa_time(nsec) (nsec) / 1000 #define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000000 + (time_type) (tspec).tv_nsec/1000 @@ -105,6 +111,8 @@ do { \ (tspec).tv_nsec = ( (time) % 1000000) * 1000; \ } while(0) +#define fosa_time_to_double(time) (double) (time) * 1e-6; +#define fosa_double_to_time(time_type, time) (time_type) (time * 1e6) #endif @@ -114,6 +122,8 @@ do { \ #define msec_to_fosa_time(msec) (msec) #define fosa_time_to_usec(time) (time) * 1000 #define usec_to_fosa_time(usec) (usec) / 1000 +#define fosa_time_to_nsec(time) (time) * 1000000 +#define nsec_to_fosa_time(nsec) (nsec) / 1000000 #define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000 + (time_type) (tspec).tv_nsec/1000000 @@ -123,6 +133,9 @@ do { \ (tspec).tv_nsec = ( (time) % 1000) * 1000000; \ } while(0) +#define fosa_time_to_double(time) (double) (time) * 1e-3; +#define fosa_double_to_time(time_type, time) (time_type) (time) * 1e3 + #endif @@ -189,6 +202,29 @@ static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel return result; } +// --------------------------------------------------------- + + +static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier) +{ + fosa_rel_time_t result; + + result = time * multiplier; + + return result; +} + + +// --------------------------------------------------------- + +static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider) +{ + return time / divider; +} + + + + /* Comparison */ /**************/ @@ -237,6 +273,54 @@ static inline bool fosa_rel_time_smaller_or_equal(fosa_rel_time_t relt1, fosa_re } +// ----------------------------------------------------------- + +static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2) +{ + bool result; + + result = relt1 == relt2; + + return result; +} + + +// ----------------------------------------------------------- + +static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2) +{ + bool result; + + result = abst1 == abst2; + + return result; +} + +// ----------------------------------------------------------- + +static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt) +{ + bool result; + + result = relt == 0; + + return result; +} + + +// ----------------------------------------------------------- + +static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst) +{ + bool result; + + result = abst == 0; + + return result; +} + + + /* Conversion */ /**************/ static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec) @@ -330,6 +414,52 @@ static inline long fosa_abs_time_to_usec(fosa_abs_time_t abst) } + +// -------------------------------------------------- + +static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec) +{ + fosa_rel_time_t result; + + result = nsec_to_fosa_time((fosa_rel_time_t ) nsec); + + return result; +} + +// -------------------------------------------------- + +static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt) +{ + long result; + + result = fosa_time_to_nsec(relt); + + return result; +} + + +// -------------------------------------------------- + +static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec) +{ + fosa_abs_time_t result; + + result = nsec_to_fosa_time( (fosa_abs_time_t) nsec); + + return result; +} + +// -------------------------------------------------- + +static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst) +{ + long result; + + result = fosa_time_to_nsec(abst); + + return result; +} + // -------------------------------------------------- static inline fosa_rel_time_t fosa_timespec_to_rel_time(struct timespec time_tspec) @@ -375,4 +505,29 @@ static inline struct timespec fosa_abs_time_to_timespec(fosa_abs_time_t abst) } + +// -------------------------------------------------- + +static inline double fosa_rel_time_to_double(fosa_rel_time_t relt) +{ + double result; + + result = fosa_time_to_double(relt); + return result; +} + + +// -------------------------------------------------- + +static inline double fosa_double_to_rel_time(double time) +{ + fosa_rel_time_t result; + + result = fosa_double_to_time(fosa_rel_time_t, time); + return result; +} + + + + #endif /* !FOSA_TIME_H_ */ diff --git a/include/fosa_time_timespec.h b/include/fosa_time_timespec.h index 4d5f2b5..942d9e5 100644 --- a/include/fosa_time_timespec.h +++ b/include/fosa_time_timespec.h @@ -65,23 +65,33 @@ #ifndef FOSA_TIME_TIMESPEC_H_ #define FOSA_TIME_TIMESPEC_H_ +#include +#include /**********************************/ /* T I M E S P E C M A C R O S */ /**********************************/ +#define normalize_timespec(t1) \ +do \ +{ \ + if ((t1).tv_nsec >= 1000000000) \ + { \ + (t1).tv_sec++; \ + (t1).tv_nsec -= 1000000000; \ + } \ +} while(0) + + #define add_timespec(sum, t1, t2) \ do { \ (sum).tv_sec = (t1).tv_sec + (t2).tv_sec; \ (sum).tv_nsec = (t1).tv_nsec + (t2).tv_nsec; \ - if ((sum).tv_nsec >= 1000000000) \ - { \ - (sum).tv_sec++; \ - (sum).tv_nsec -= 1000000000; \ - } \ + normalize_timespec(sum); \ } while(0) + // ------------------------------------------------------------------- /* TODO: Test that for past > future we obtain a correct negative @@ -149,7 +159,34 @@ do { \ ( ((t1).tv_sec % 2148) * 1000000 + (t1).tv_nsec/1000 ) +// --------------------------------------------------------- + +#define nsec_to_timespec(tspec, nsec) \ +do { \ + if ((nsec) >= 1000000000) { \ + (tspec).tv_sec = (nsec)/1000000000; \ + (tspec).tv_nsec = (nsec) % 1000000000; \ + } else { \ + (tspec).tv_sec = 0; \ + (tspec).tv_nsec = (nsec); \ + } \ +} while(0) + +// --------------------------------------------------------- + +#define timespec_to_nsec(t1) \ + ( ((t1).tv_sec % 2) * 1000000000 + (t1).tv_nsec ) + + + +// --------------------------------------------------------- + +#define timespec_equal(t1, t2) ( (t1).tv_sec == (t2).tv_sec ) && ( (t1).tv_nsec == (t2).tv_nsec ) + +#define timespec_is_null(t1) ( (t1).tv_sec == 0 ) && ( (t1).tv_nsec == 0 ) + + /***************************************/ /* T I M E S P E C F U N C T I O N S */ /***************************************/ @@ -171,8 +208,6 @@ static inline fosa_abs_time_t fosa_abs_time_decr(fosa_abs_time_t base, fosa_rel_ { fosa_abs_time_t result; - - substract_timespec(result, base, interval); return result; @@ -204,7 +239,6 @@ static inline fosa_rel_time_t fosa_rel_time_add(fosa_rel_time_t relt1, fosa_rel_ } - // --------------------------------------------------------- static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel_time_t part) @@ -216,6 +250,224 @@ static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel return result; } +// --------------------------------------------------------- + +/** + * exact_long_multiply_smaller_10e5() + * + * Same as below but with operands smaller than 10000 which allows + * to perform all component multiplications without an overflow risk. + **/ +static inline struct timespec exact_long_multiply_smaller_10e5(long t, long k) +{ + /* Since operands are smaller than 10e5 we can use 1000 */ + /* the base without risking to cause overflows in the */ + /* operations. */ + /********************************************************/ + assert(t < 10000); + assert(k < 10000); + + struct timespec result; + + long base = 1000; + + long t_high = t / base; + long t_low = t % base; + long k_high = k / base; + long k_low = k % base; + + long thkh = t_high * k_high; + long thkl = t_high * k_low; + long tlkh = t_low * k_high; + long tlkl = t_low * k_low; + + long thkl_high = thkl / base; + long tlkh_high = tlkh / base; + long thkl_low = thkl % base; + long tlkh_low = tlkh % base; + + long c2 = thkh + thkl_high + tlkh_high; // Normalized at 10^6 + long c1 = thkl_low + tlkh_low; // Normalized at 10^3 + long c0 = tlkl; + + result.tv_sec = c2/1000 + c1/1000000; + result.tv_nsec = (c2 % 1000) * 1000000 + (c1 % 1000000) * 1000 + c0; + + result.tv_sec += (result.tv_nsec / 1000000000); + result.tv_nsec %= 1000000000; + + return result; +} + + +// ------------------------------------------------------------- + + + +/** + * exact_long_multiply() + * + * This function performs an exact long * long operations on operands + * lower than 1e9 without using more than 32bit (1e9) arithmetic. + * + * To achieve this we decompose the operands in high and low: + * + * num = (num/base) * base + (num % base) + * ^^^^^^^^ ^^^^^^^^^^^^ + * high component low component + * + * t * k = (th*kh + th*kl/base + tl*kh/base )*base^2 + * + (th*kl % base)*base + (tl*kh % base) * base + tl*kl + * + * The problem is that we cannot use an exact base because sqrt(1e9) + * is not a multiple of 1e9 (in fact it is not even integer). + * + * So we use as a base 100000 which means that the last term tl*kl may + * need another exact calculation with a lower base (100) + **/ +static inline struct timespec exact_long_multiply(long t, long k) +{ + struct timespec result; + + long t_high; + long t_low; + long k_high; + long k_low; + + long base = 100000; /* Power of 10 closest to sqrt(1e9) from + * above */ + + t_high = t / base; + t_low = t % base; // Between 0 99999 + k_high = k / base; + k_low = k % base; // Between 0 99999 + + /* These numbers are always lower than 1e9 */ + long thkh = t_high * k_high; + long thkl = t_high * k_low; + long tlkh = t_low * k_high; + + long thkl_high = thkl / base; + long thkl_low = thkl % base; + long tlkh_high = tlkh / base; + long tlkh_low = tlkh % base; + + /* We can calculate the base^2 term (note however that this is 10 + * times the tv_sec component because it is multiplied by 10^10 */ + long c2 = thkh + thkl_high + tlkh_high; // scaled to 10^10 + long c1 = thkl_low + tlkh_low; // scaled to 10^5 + + struct timespec c0; + + /* Now we can write the initial values of result */ + result.tv_sec = c2*10 + c1/10000; + result.tv_nsec = (c1 % 10000) * 100000; + + normalize_timespec(result); + + /* To calculate c0 we must check if there is a risk of overflow */ + /* Remember operands cannot be larger than 99999 and result */ + /* larger than 1e9. */ + /****************************************************************/ + bool overflow_risk; + overflow_risk = false; + + if ( + ( (t_low > 31622) && (k_low >= 10000) ) || + ( (k_low > 31622) && (t_low >= 10000) ) + ) + { + overflow_risk = true; + } + + if (! overflow_risk) + { + c0.tv_sec = 0; + c0.tv_nsec = t_low * k_low; + normalize_timespec(c0); + } + else + { + c0 = exact_long_multiply_smaller_10e5(t_low, k_low); + } + add_timespec(result, result, c0); + + return result; +} + +// ------------------------------------------------------------- + + +static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier) +{ + struct timespec result; + struct timespec intermediate; + + result.tv_sec = time.tv_sec * multiplier; // No overflow check here + result.tv_nsec = 0; + + intermediate = exact_long_multiply(time.tv_nsec, multiplier); + + add_timespec(result, result, intermediate); + + return result; +} + +// --------------------------------------------------------- + +static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider) +{ + struct timespec result; + long reminder; + + + result.tv_sec = time.tv_sec / divider; + result.tv_nsec = 0; + + /* We iterate until the reminder is lower than 2 (to later fit in + * a 32 bit signed integer multiplied by 1e9 */ + + reminder = time.tv_sec % divider; + + + if (reminder == 0) + { + /* We are lucky no reminder so no need to transfer it to the + nsec scale. + */ + result.tv_nsec = time.tv_nsec/divider; + return result; + } + + long enhacer; + long back_enhacer; + long next_dividend; + int next_numeral; /* Between 0 and 9 */ + enhacer = 1; + do + { + enhacer *= 10; + back_enhacer = 1000000000 / enhacer; + next_numeral = (time.tv_nsec / back_enhacer) % 10; + + // Note: a possible overflow may happen here with large denominators + if (reminder > 200000000) + { + /* An overflow is going to be produced */ + abort(); + } + next_dividend = reminder * 10 + next_numeral; + + result.tv_nsec += (next_dividend / divider) * back_enhacer; + reminder = next_dividend % divider; + } while (back_enhacer > 1); + + + return result; +} + +// --------------------------------------------------------- + /* Comparison */ /**************/ @@ -264,6 +516,55 @@ static inline bool fosa_rel_time_smaller_or_equal(fosa_rel_time_t relt1, fosa_re } +// ----------------------------------------------------------- + +static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2) +{ + bool result; + + result = timespec_equal(relt1, relt2); + + return result; +} + + +// ----------------------------------------------------------- + +static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2) +{ + bool result; + + result = timespec_equal(abst1, abst2); + + return result; +} + +// ----------------------------------------------------------- + +static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt) +{ + bool result; + + result = timespec_is_null(relt); + + return result; +} + + +// ----------------------------------------------------------- + +static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst) +{ + bool result; + + result = timespec_is_null(abst); + + return result; +} + + + + /* Conversion */ /**************/ static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec) @@ -358,6 +659,51 @@ static inline long fosa_abs_time_to_usec(fosa_abs_time_t abst) return result; } +// -------------------------------------------------- + +static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec) +{ + fosa_rel_time_t result; + + nsec_to_timespec(result, nsec); + + return result; +} + +// -------------------------------------------------- + +static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt) +{ + long result; + + result = timespec_to_nsec(relt); + + return result; +} + + +// -------------------------------------------------- + +static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec) +{ + fosa_abs_time_t result; + + nsec_to_timespec(result, nsec); + + return result; +} + +// -------------------------------------------------- + +static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst) +{ + long result; + + result = timespec_to_nsec(abst); + + return result; +} + // -------------------------------------------------- @@ -387,5 +733,27 @@ static inline struct timespec fosa_abs_time_to_timespec(fosa_abs_time_t abst) return (struct timespec) abst; } +// -------------------------------------------------- + +static inline double fosa_rel_time_to_double(fosa_rel_time_t relt) +{ + double result; + + result = relt.tv_nsec*0.000000001 + (double)relt.tv_sec; + + return result; +} + +// -------------------------------------------------- + +static inline fosa_rel_time_t fosa_double_to_rel_time(double time) +{ + fosa_rel_time_t result; + + result.tv_sec = (long) time; + result.tv_nsec = (long) ( (time - (double)result.tv_sec) * 1e9 ); + + return result; +} #endif /* !FOSA_TIME_TIMESPEC_H_ */ diff --git a/src_marte/tests/test_time/fosa_test_time.c b/src_marte/tests/test_time/fosa_test_time.c index c335402..d8a26b5 100644 --- a/src_marte/tests/test_time/fosa_test_time.c +++ b/src_marte/tests/test_time/fosa_test_time.c @@ -109,6 +109,45 @@ int main() /* fosa_rel_time_decr (negative) */ rel_time_result = fosa_rel_time_decr(rel_time2, rel_time1); // assert( check_exact_rel_msec(rel_time_result, 1100) ); + +/* + struct timespec t1 = {0, 876352172}; + fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1); + long factor = 573102543; + struct timespec product = {502239658, 336773396}; + fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product); +*/ + + struct timespec t1 = {0, 876352172}; + struct timespec product = {50223965, 570771688}; + long factor = 57310254; + struct timespec product_divided_by_17 = {2954350, 915927746}; // inexact division + struct timespec product_divided_by_3 = {16741321, 856923896}; // exact division + + fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1); + fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product); + fosa_rel_time_t product_17_rel = fosa_timespec_to_rel_time(product_divided_by_17); + fosa_rel_time_t product_3_rel = fosa_timespec_to_rel_time(product_divided_by_3); + + /* fosa_rel_time_times_integer */ + /* fosa_rel_time_divided_by_integer */ + rel_time_result = fosa_rel_time_times_integer(rel_time2, 4); + assert( check_exact_rel_msec(rel_time_result, 1600) ); + + rel_time_result = fosa_rel_time_divided_by_integer(rel_time_result, 4); + assert( check_exact_rel_msec(rel_time_result, 400) ); + + rel_time_result = fosa_rel_time_times_integer(t1_rel, factor); + assert( fosa_rel_time_equal(rel_time_result, product_rel) ); + + rel_time_result = fosa_rel_time_divided_by_integer(product_rel, factor); + assert( fosa_rel_time_equal(rel_time_result, t1_rel) ); + + rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 17); + assert( fosa_rel_time_equal(rel_time_result, product_17_rel) ); + + rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 3); + assert( fosa_rel_time_equal(rel_time_result, product_3_rel) ); /* fosa_abs_time_smaller */ test = fosa_abs_time_smaller(abs_time1, abs_time2); @@ -202,6 +241,8 @@ int main() test = memcmp(&tspec_result, &tspec2, sizeof(tspec_result) ); assert(test == 0); + + printf("End of test OK!!\n"); return 0; -- 2.39.2