aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2024-07-11 15:28:58 +0200
committerPaul Eggert2024-07-11 16:01:41 +0200
commite30706fd12bce459b56123ad36a4e8c1c9d374e1 (patch)
treea7f80134870feeb2904b1b7295c00cfb5f6501cd /src
parente8b3c4cb58ce6e78b9bcfb9146f0ac6ece0d3055 (diff)
downloademacs-e30706fd12bce459b56123ad36a4e8c1c9d374e1.tar.gz
emacs-e30706fd12bce459b56123ad36a4e8c1c9d374e1.zip
Avoid mpz for some common timestamp cases
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.
Diffstat (limited to 'src')
-rw-r--r--src/timefns.c84
1 files 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
570 { 570 {
571 CFORM_TICKS_HZ, /* struct ticks_hz */ 571 CFORM_TICKS_HZ, /* struct ticks_hz */
572 CFORM_TIMESPEC, /* struct timespec */ 572 CFORM_TIMESPEC, /* struct timespec */
573 CFORM_SECS_ONLY, /* struct timespec but tv_nsec == 0 if timespec valid */ 573 CFORM_SECS_ONLY, /* struct timespec but tv_nsec irrelevant
574 if timespec valid */
574 CFORM_DOUBLE /* double */ 575 CFORM_DOUBLE /* double */
575 }; 576 };
576 577
@@ -894,11 +895,22 @@ decode_time_components (enum timeform form,
894 } 895 }
895 break; 896 break;
896 897
897 default: 898 case TIMEFORM_HI_LO:
898 if (! (INTEGERP (high) && INTEGERP (low) 899 hz = make_fixnum (1);
899 && FIXNUMP (usec) && FIXNUMP (psec))) 900 goto check_high_low;
900 return (struct err_time) { .err = EINVAL }; 901
902 case TIMEFORM_HI_LO_US:
903 hz = make_fixnum (1000000);
904 goto check_high_low_usec;
901 905
906 case TIMEFORM_HI_LO_US_PS:
907 hz = trillion;
908 if (!FIXNUMP (psec))
909 return (struct err_time) { .err = EINVAL };
910 check_high_low_usec:
911 if (!FIXNUMP (usec))
912 return (struct err_time) { .err = EINVAL };
913 check_high_low:
902 { 914 {
903 EMACS_INT us = XFIXNUM (usec); 915 EMACS_INT us = XFIXNUM (usec);
904 EMACS_INT ps = XFIXNUM (psec); 916 EMACS_INT ps = XFIXNUM (psec);
@@ -906,25 +918,73 @@ decode_time_components (enum timeform form,
906 /* Normalize out-of-range lower-order components by carrying 918 /* Normalize out-of-range lower-order components by carrying
907 each overflow into the next higher-order component. */ 919 each overflow into the next higher-order component. */
908 us += ps / 1000000 - (ps % 1000000 < 0); 920 us += ps / 1000000 - (ps % 1000000 < 0);
921 EMACS_INT s_from_us_ps = us / 1000000 - (us % 1000000 < 0);
922 ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0);
923 us = us % 1000000 + 1000000 * (us % 1000000 < 0);
924
925 if (FASTER_TIMEFNS && FIXNUMP (high) && FIXNUMP (low))
926 {
927 /* Use intmax_t arithmetic if the tick count fits. */
928 intmax_t iticks;
929 bool v = false;
930 v |= ckd_mul (&iticks, XFIXNUM (high), 1 << LO_TIME_BITS);
931 v |= ckd_add (&iticks, iticks, XFIXNUM (low) + s_from_us_ps);
932 if (!v)
933 {
934 if (cform == CFORM_TIMESPEC || cform == CFORM_SECS_ONLY)
935 return (struct err_time) {
936 .time = {
937 .ts = s_ns_to_timespec (iticks, us * 1000 + ps / 1000)
938 }
939 };
940
941 switch (form)
942 {
943 case TIMEFORM_HI_LO:
944 break;
945
946 case TIMEFORM_HI_LO_US:
947 v |= ckd_mul (&iticks, iticks, 1000000);
948 v |= ckd_add (&iticks, iticks, us);
949 break;
950
951 case TIMEFORM_HI_LO_US_PS:
952 {
953 int_fast64_t million = 1000000;
954 v |= ckd_mul (&iticks, iticks, TRILLION);
955 v |= ckd_add (&iticks, iticks, us * million + ps);
956 }
957 break;
958
959 default:
960 eassume (false);
961 }
962
963 if (!v)
964 return (struct err_time) {
965 .time = decode_ticks_hz (make_int (iticks), hz, cform)
966 };
967 }
968 }
969
970 if (! (INTEGERP (high) && INTEGERP (low)))
971 return (struct err_time) { .err = EINVAL };
972
909 mpz_t *s = &mpz[1]; 973 mpz_t *s = &mpz[1];
910 mpz_set_intmax (*s, us / 1000000 - (us % 1000000 < 0)); 974 mpz_set_intmax (*s, s_from_us_ps);
911 mpz_add (*s, *s, *bignum_integer (&mpz[0], low)); 975 mpz_add (*s, *s, *bignum_integer (&mpz[0], low));
912 mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS); 976 mpz_addmul_ui (*s, *bignum_integer (&mpz[0], high), 1 << LO_TIME_BITS);
913 ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0);
914 us = us % 1000000 + 1000000 * (us % 1000000 < 0);
915 977
916 switch (form) 978 switch (form)
917 { 979 {
918 case TIMEFORM_HI_LO: 980 case TIMEFORM_HI_LO:
919 /* Floats and nil were handled above, so it was an integer. */ 981 /* Floats and nil were handled above, so it was an integer. */
920 mpz_swap (mpz[0], *s); 982 mpz_swap (mpz[0], *s);
921 hz = make_fixnum (1);
922 break; 983 break;
923 984
924 case TIMEFORM_HI_LO_US: 985 case TIMEFORM_HI_LO_US:
925 mpz_set_ui (mpz[0], us); 986 mpz_set_ui (mpz[0], us);
926 mpz_addmul_ui (mpz[0], *s, 1000000); 987 mpz_addmul_ui (mpz[0], *s, 1000000);
927 hz = make_fixnum (1000000);
928 break; 988 break;
929 989
930 case TIMEFORM_HI_LO_US_PS: 990 case TIMEFORM_HI_LO_US_PS:
@@ -938,7 +998,6 @@ decode_time_components (enum timeform form,
938 mpz_set_intmax (mpz[0], i * 1000000 + ps); 998 mpz_set_intmax (mpz[0], i * 1000000 + ps);
939 mpz_addmul (mpz[0], *s, ztrillion); 999 mpz_addmul (mpz[0], *s, ztrillion);
940 #endif 1000 #endif
941 hz = trillion;
942 } 1001 }
943 break; 1002 break;
944 1003
@@ -948,6 +1007,9 @@ decode_time_components (enum timeform form,
948 ticks = make_integer_mpz (); 1007 ticks = make_integer_mpz ();
949 } 1008 }
950 break; 1009 break;
1010
1011 default:
1012 eassume (false);
951 } 1013 }
952 1014
953 return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) }; 1015 return (struct err_time) { .time = decode_ticks_hz (ticks, hz, cform) };