From 68bd5fdbb6a94fd90575e2e2199365a0c2b9db68 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Apr 2022 13:08:26 -0700 Subject: [PATCH 2/6] Refactor to simplify clock resolution support * src/timefns.c (timespec_mpz, timespec_ticks): New args HZ, RES. All callers changed. (timespec_clockres_to_lisp): New function, extended from timespec_to_lisp. (timespec_to_lisp): Use it. (make_lisp_time_clockres): New function, extended from make_lisp_time. (make_lisp_time): Use it. --- src/timefns.c | 61 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/timefns.c b/src/timefns.c index b0b84a438c..3f8efadf54 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -482,30 +482,37 @@ mpz_set_time (mpz_t rop, time_t t) mpz_set_uintmax (rop, t); } -/* Store into mpz[0] a clock tick count for T, assuming a - TIMESPEC_HZ-frequency clock. Use mpz[1] as a temp. */ +/* Store into mpz[0] a clock tick count for T, assuming a HZ-frequency + clock with resolution RES ns (so that HZ*RES = TIMESPEC_HZ). + Use mpz[1] as a temp. */ static void -timespec_mpz (struct timespec t) +timespec_mpz (struct timespec t, long int hz, long int res) { - /* mpz[0] = sec * TIMESPEC_HZ + nsec. */ - mpz_set_ui (mpz[0], t.tv_nsec); + /* mpz[0] = sec * hz + nsec / res. */ + mpz_set_ui (mpz[0], t.tv_nsec / res); mpz_set_time (mpz[1], t.tv_sec); - mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ); + mpz_addmul_ui (mpz[0], mpz[1], hz); } -/* Convert T to a Lisp integer counting TIMESPEC_HZ ticks. */ +/* Convert T to a Lisp integer counting HZ ticks each consisting + of RES ns. */ static Lisp_Object -timespec_ticks (struct timespec t) +timespec_ticks (struct timespec t, long int hz, long int res) { + eassume (0 <= t.tv_nsec && t.tv_nsec < TIMESPEC_HZ); + eassume (0 < hz && hz <= TIMESPEC_HZ); + eassume (0 < res && res <= TIMESPEC_HZ); + eassume (hz * res == TIMESPEC_HZ); + /* For speed, use intmax_t arithmetic if it will do. */ intmax_t accum; if (FASTER_TIMEFNS - && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum) - && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum)) + && !INT_MULTIPLY_WRAPV (t.tv_sec, hz, &accum) + && !INT_ADD_WRAPV (t.tv_nsec / res, accum, &accum)) return make_int (accum); /* Fall back on bignum arithmetic. */ - timespec_mpz (t); + timespec_mpz (t, hz, res); return make_integer_mpz (); } @@ -565,9 +572,26 @@ lisp_time_seconds (struct lisp_time t) return make_integer_mpz (); } -/* Convert T to a Lisp timestamp. */ +/* Return (TICKS . LISPHZ) for time T, assuming a LISPHZ,HZ,RES clock. */ +static Lisp_Object +timespec_clockres_to_lisp (struct timespec t, Lisp_Object lisphz, + long int hz, long int res) +{ + return Fcons (timespec_ticks (t, hz, res), lisphz); +} + +/* Return (TICKS . HZ) for time T, assuming a clock resolution of 1 ns. */ Lisp_Object -make_lisp_time (struct timespec t) +timespec_to_lisp (struct timespec t) +{ + return timespec_clockres_to_lisp (t, timespec_hz, TIMESPEC_HZ, 1); +} + +/* Convert T to a Lisp timestamp, assuming a LISPHZ or HZ-frequency + clock with resolution RES ns (so that HZ*RES = TIMESPEC_HZ). */ +static Lisp_Object +make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz, + long int hz, long int res) { if (CURRENT_TIME_LIST) { @@ -577,14 +601,14 @@ make_lisp_time (struct timespec t) make_fixnum (ns / 1000), make_fixnum (ns % 1000 * 1000)); } else - return timespec_to_lisp (t); + return timespec_clockres_to_lisp (t, lisphz, hz, res); } -/* Return (TICKS . HZ) for time T. */ +/* Convert T to a Lisp timestamp. */ Lisp_Object -timespec_to_lisp (struct timespec t) +make_lisp_time (struct timespec t) { - return Fcons (timespec_ticks (t), timespec_hz); + return make_lisp_time_clockres (t, timespec_hz, TIMESPEC_HZ, 1); } /* Return NUMERATOR / DENOMINATOR, rounded to the nearest double. @@ -747,7 +771,8 @@ decode_time_components (enum timeform form, } case TIMEFORM_NIL: - return decode_ticks_hz (timespec_ticks (current_timespec ()), + return decode_ticks_hz (timespec_ticks (current_timespec (), + TIMESPEC_HZ, 1), timespec_hz, result, dresult); default: -- 2.35.1