[tz] [PATCH] * zdump.c: Tune performance of -c with large numbers on 64-bit hosts.
Paul Eggert
eggert at cs.ucla.edu
Thu Aug 15 07:33:09 UTC 2013
On my platform (Ubuntu 13.04 x86-64, Xeon E3-1225 V2), this sped up
'zdump -V -c 2147483647,2147483648 America/Los_Angeles'
from 13.880 to 0.000 seconds user+system time.
(INTMAX_MAX): Define if the system doesn't.
(SECSPER400YEARS): New macro.
(SECSPER400YEARS_FITS): New constant.
(yeartot): Speed up by using division instead of
repeated subtraction.
---
zdump.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 46 insertions(+), 17 deletions(-)
diff --git a/zdump.c b/zdump.c
index 788020a..36c1838 100644
--- a/zdump.c
+++ b/zdump.c
@@ -60,9 +60,15 @@ typedef int int_fast32_t;
# if defined LLONG_MAX || defined __LONG_LONG_MAX__
typedef long long intmax_t;
# define PRIdMAX "lld"
+# ifdef LLONG_MAX
+# define INTMAX_MAX LLONG_MAX
+# else
+# define INTMAX_MAX __LONG_LONG_MAX__
+# endif
# else
typedef long intmax_t;
# define PRIdMAX "ld"
+# define INTMAX_MAX LONG_MAX
# endif
#endif
#ifndef SCNdMAX
@@ -140,6 +146,17 @@ typedef long intmax_t;
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
+#define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \
+ + SECSPERLYEAR * (intmax_t) (100 - 3))
+
+/*
+** True if SECSPER400YEARS is known to be representable as an
+** intmax_t. It's OK that SECSPER400YEARS_FITS can in theory be false
+** even if SECSPER400YEARS is representable, because when that happens
+** the code merely runs a bit more slowly, and this slowness doesn't
+** occur on any practical platform.
+*/
+enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
#ifndef HAVE_GETTEXT
#define HAVE_GETTEXT 0
@@ -490,30 +507,42 @@ main(int argc, char *argv[])
static time_t
yeartot(const intmax_t y)
{
- register intmax_t myy;
- register int_fast32_t seconds;
+ register intmax_t myy, seconds, years;
register time_t t;
myy = EPOCH_YEAR;
t = 0;
- while (myy != y) {
- if (myy < y) {
+ while (myy < y) {
+ if (SECSPER400YEARS_FITS && 400 <= y - myy) {
+ intmax_t diff400 = (y - myy) / 400;
+ if (INTMAX_MAX / SECSPER400YEARS < diff400)
+ return absolute_max_time;
+ seconds = diff400 * SECSPER400YEARS;
+ years = diff400 * 400;
+ } else {
seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
- ++myy;
- if (t > absolute_max_time - seconds) {
- t = absolute_max_time;
- break;
- }
- t += seconds;
+ years = 1;
+ }
+ myy += years;
+ if (t > absolute_max_time - seconds)
+ return absolute_max_time;
+ t += seconds;
+ }
+ while (y < myy) {
+ if (SECSPER400YEARS_FITS && y + 400 <= myy && myy < 0) {
+ intmax_t diff400 = (myy - y) / 400;
+ if (INTMAX_MAX / SECSPER400YEARS < diff400)
+ return absolute_min_time;
+ seconds = diff400 * SECSPER400YEARS;
+ years = diff400 * 400;
} else {
- --myy;
- seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
- if (t < absolute_min_time + seconds) {
- t = absolute_min_time;
- break;
- }
- t -= seconds;
+ seconds = isleap(myy - 1) ? SECSPERLYEAR : SECSPERNYEAR;
+ years = 1;
}
+ myy -= years;
+ if (t < absolute_min_time + seconds)
+ return absolute_min_time;
+ t -= seconds;
}
return t;
}
--
1.8.1.2
More information about the tz
mailing list