From 37d6fcd92a0ff8d86b7392479e101514c541f403 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 11 Jul 2024 15:28:58 +0200 Subject: [PATCH] Avoid mpz for some common timestamp cases MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Performance problem reported by Gerd Möllmann and Mattias Engdegård in: https://lists.gnu.org/r/emacs-devel/2024-06/msg00530.html https://lists.gnu.org/r/emacs-devel/2024-06/msg00539.html * src/timefns.c (CFORM_SECS_ONLY): The exact tv_nsec value is now ignored if nonnegative (i.e., the only thing that matters is that it’s nonnegative). (decode_time_components): Use intmax_t instead of mpz arithmetic if the tick count fits. Add another ‘default: eassume (false);’ so that the revised code pacifies --enable-gcc-warnings with GCC 11.4.0 on x86-64. (cherry picked from commit e30706fd12bce459b56123ad36a4e8c1c9d374e1) --- src/timefns.c | 84 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/src/timefns.c b/src/timefns.c index ad39d1307cd..8c30016360d 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -570,7 +570,8 @@ enum cform { CFORM_TICKS_HZ, /* struct ticks_hz */ CFORM_TIMESPEC, /* struct timespec */ - CFORM_SECS_ONLY, /* struct timespec but tv_nsec == 0 if timespec valid */ + CFORM_SECS_ONLY, /* struct timespec but tv_nsec irrelevant + if timespec valid */ CFORM_DOUBLE /* double */ }; @@ -894,11 +895,22 @@ decode_time_components (enum timeform form, } break; - default: - if (! (INTEGERP (high) && INTEGERP (low) - && FIXNUMP (usec) && FIXNUMP (psec))) - return (struct err_time) { .err = EINVAL }; + case TIMEFORM_HI_LO: + hz = make_fixnum (1); + goto check_high_low; + + case TIMEFORM_HI_LO_US: + hz = make_fixnum (1000000); + goto check_high_low_usec; + case TIMEFORM_HI_LO_US_PS: + hz = trillion; + if (!FIXNUMP (psec)) + return (struct err_time) { .err = EINVAL }; + check_high_low_usec: + if (!FIXNUMP (usec)) + return (struct err_time) { .err = EINVAL }; + check_high_low: { EMACS_INT us = XFIXNUM (usec); EMACS_INT ps = XFIXNUM (psec); @@ -906,25 +918,73 @@ decode_time_components (enum timeform form, /* Normalize out-of-range lower-order components by carrying each overflow into the next higher-order component. */ us += ps / 1000000 - (ps % 1000000 < 0); + EMACS_INT s_from_us_ps = us / 1000000 - (us % 1000000 < 0); + ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); + us = us % 1000000 + 1000000 * (us % 1000000 < 0); + + if (FASTER_TIMEFNS && FIXNUMP (high) && FIXNUMP (low)) + { + /* Use intmax_t arithmetic if the tick count fits. */ + intmax_t iticks; + bool v = false; + v |= ckd_mul (&iticks, XFIXNUM (high), 1 << LO_TIME_BITS); + v |= ckd_add (&iticks, iticks, XFIXNUM (low) + s_from_us_ps); + if (!v) + { + if (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY) + return (struct err_time) { + .time = { + .ts = s_ns_to_timespec (iticks, us * 1000 + ps / 1000) + } + }; + + switch (form) + { + case TIMEFORM_HI_LO: + break; + + case TIMEFORM_HI_LO_US: + v |= ckd_mul (&iticks, iticks, 1000000); + v |= ckd_add (&iticks, iticks, us); + break; + + case TIMEFORM_HI_LO_US_PS: + { + int_fast64_t million = 1000000; + v |= ckd_mul (&iticks, iticks, TRILLION); + v |= ckd_add (&iticks, iticks, us * million + ps); + } + break; + + default: + eassume (false); + } + + if (!v) + return (struct err_time) { + .time = decode_ticks_hz (make_int (iticks), hz, cform) + }; + } + } + + if (! (INTEGERP (high) && INTEGERP (low))) + return (struct err_time) { .err = EINVAL }; + mpz_t *s = &mpz[1]; - mpz_set_intmax (*s, us / 1000000 - (us % 1000000 < 0)); + mpz_set_intmax (*s, s_from_us_ps); mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); - ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); - us = us % 1000000 + 1000000 * (us % 1000000 < 0); switch (form) { case TIMEFORM_HI_LO: /* Floats and nil were handled above, so it was an integer. */ mpz_swap (mpz[0], *s); - hz = make_fixnum (1); break; case TIMEFORM_HI_LO_US: mpz_set_ui (mpz[0], us); mpz_addmul_ui (mpz[0], *s, 1000000); - hz = make_fixnum (1000000); break; case TIMEFORM_HI_LO_US_PS: @@ -938,7 +998,6 @@ decode_time_components (enum timeform form, mpz_set_intmax (mpz[0], i * 1000000 + ps); mpz_addmul (mpz[0], *s, ztrillion); #endif - hz = trillion; } break; @@ -948,6 +1007,9 @@ decode_time_components (enum timeform form, ticks = make_integer_mpz (); } break; + + default: + eassume (false); } return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; -- 2.39.2