From 9c42f5f9ebc5b4e5d7bd0c33a0ce7de27c27d893 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Mon, 18 Apr 2022 13:08:27 -0700 Subject: [PATCH 4/6] Use CLOCK_REALTIME resolution for (TICKS . HZ) This gives Elisp code a clearer view of timestamps, for uses like (time-convert nil t). * src/emacs.c (main): Call init_timefns earlier. * src/keyboard.c (Fcurrent_idle_time): * src/sysdep.c (Fcurrent_time): Use make_lisp_realtime instead of make_lisp_time, for realtime timestamps (e.g., they come from gettime). * src/sysdep.c (make_lisp_s_us): Also define if HAVE_GETRUSAGE. Simplify by calling make_lisp_time_clockres. (Fget_internal_run_time): Fix resolution by calling make_lisp_s_us. * src/timefns.c (realtime_lisphz, realtime_hz, realtime_res): New static vars. (init_time_res): New function. (init_timefns): Initialize the new vars (make_lisp_time_clockres): Now extern. (make_lisp_realtime): New function. --- etc/NEWS | 6 ++++++ src/emacs.c | 7 ++++--- src/fileio.c | 5 ++++- src/keyboard.c | 4 ++-- src/sysdep.c | 14 ++++++-------- src/systime.h | 3 +++ src/timefns.c | 36 +++++++++++++++++++++++++++++++++--- 7 files changed, 58 insertions(+), 17 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index c5a136ea68..38317fef03 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1950,6 +1950,12 @@ For example, '(time-add nil '(1 . 1000))' no longer warns that the '(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a temporary transition aid for Emacs 27, has served its purpose. ++++ +** (TICKS . HZ) timestamps now report system clock resolution. +For example, the macOS system clock resolution is 1 μs so +(time-convert nil t) now acts like (time-convert nil 1000000). +Formerly, time-convert used a clock resolution of 1 ns regardless. + +++ ** 'encode-time' now also accepts a 6-element list with just time and date. (encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR)) is now short for diff --git a/src/emacs.c b/src/emacs.c index 3100852b2c..15a4a25770 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1894,6 +1894,10 @@ main (int argc, char **argv) init_signals (); + /* This calls putenv and so must precede init_process_emacs. + It must also precede init_window_once, which creates timestamps. */ + init_timefns (); + noninteractive1 = noninteractive; /* Perform basic initializations (not merely interning symbols). */ @@ -2383,9 +2387,6 @@ main (int argc, char **argv) init_charset (); - /* This calls putenv and so must precede init_process_emacs. */ - init_timefns (); - init_editfns (); /* These two call putenv. */ diff --git a/src/fileio.c b/src/fileio.c index c418036fc6..2a857d10dd 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -5840,7 +5840,10 @@ DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime, mtime = make_timespec (0, UNKNOWN_MODTIME_NSECS - flag); } else - mtime = lisp_time_argument (time_flag); + { + mtime = lisp_time_argument (time_flag); + /* FIXME: Do not assume mtime resolution is 1 ns. */ + } current_buffer->modtime = mtime; current_buffer->modtime_size = -1; diff --git a/src/keyboard.c b/src/keyboard.c index 19c8fdf1dc..3eb0694eda 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4668,8 +4668,8 @@ DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0, (void) { if (timespec_valid_p (timer_idleness_start_time)) - return make_lisp_time (timespec_sub (current_timespec (), - timer_idleness_start_time)); + return make_lisp_realtime (timespec_sub (current_timespec (), + timer_idleness_start_time)); return Qnil; } diff --git a/src/sysdep.c b/src/sysdep.c index 36636d0ed5..b15d5c359e 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -3169,16 +3169,14 @@ list_system_processes (void) #endif /* !defined (WINDOWSNT) */ -#if defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__ +#if (defined HAVE_GETRUSAGE \ + || defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__) static Lisp_Object make_lisp_s_us (time_t s, long us) { - Lisp_Object sec = make_int (s); - Lisp_Object usec = make_fixnum (us); - Lisp_Object hz = make_fixnum (1000000); - Lisp_Object ticks = CALLN (Fplus, CALLN (Ftimes, sec, hz), usec); - return Ftime_convert (Fcons (ticks, hz), Qnil); + return make_lisp_time_clockres (make_timespec (s, us * 1000), + make_fixnum (1000000), 1000000, 1000); } #endif @@ -4238,7 +4236,7 @@ DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time, #ifdef HAVE_GETRUSAGE struct rusage usage; time_t secs; - int usecs; + long int usecs; if (getrusage (RUSAGE_SELF, &usage) < 0) /* This shouldn't happen. What action is appropriate? */ @@ -4252,7 +4250,7 @@ DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time, usecs -= 1000000; secs++; } - return make_lisp_time (make_timespec (secs, usecs * 1000)); + return make_lisp_s_us (secs, usecs); #else /* ! HAVE_GETRUSAGE */ #ifdef WINDOWSNT return w32_get_internal_run_time (); diff --git a/src/systime.h b/src/systime.h index 75088bd4a6..419da80826 100644 --- a/src/systime.h +++ b/src/systime.h @@ -86,7 +86,10 @@ timespec_valid_p (struct timespec t) /* defined in timefns.c */ extern struct timeval make_timeval (struct timespec) ATTRIBUTE_CONST; +extern Lisp_Object make_lisp_realtime (struct timespec); extern Lisp_Object make_lisp_time (struct timespec); +extern Lisp_Object make_lisp_time_clockres (struct timespec, Lisp_Object, + long int, long int); extern Lisp_Object timespec_to_lisp (struct timespec); extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, struct timespec *); diff --git a/src/timefns.c b/src/timefns.c index 3f8efadf54..0d0a8a5922 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -77,12 +77,17 @@ Copyright (C) 1985-1987, 1989, 1993-2022 Free Software Foundation, Inc. enum { CURRENT_TIME_LIST = true }; #endif +/* Clock resolution of struct timespec. */ #if FIXNUM_OVERFLOW_P (1000000000) static Lisp_Object timespec_hz; #else # define timespec_hz make_fixnum (TIMESPEC_HZ) #endif +/* Clock resolution of realtime, in various forms. HZ*RES == TIMESPEC_HZ. */ +static Lisp_Object realtime_lisphz; +static long int realtime_hz, realtime_res; + #define TRILLION 1000000000000 #if FIXNUM_OVERFLOW_P (TRILLION) static Lisp_Object trillion; @@ -302,9 +307,24 @@ tzlookup (Lisp_Object zone, bool settz) return new_tz; } +static void +init_time_res (void) +{ + realtime_res = gettime_res (); + eassume (0 < realtime_res); + if (TIMESPEC_HZ < realtime_res) + realtime_res = TIMESPEC_HZ; + realtime_hz = TIMESPEC_HZ / realtime_res; + realtime_lisphz = make_int (realtime_hz); +} + void init_timefns (void) { + pdumper_do_now_and_after_load (init_time_res); + if (FIXNUM_OVERFLOW_P (TIMESPEC_HZ) && !initialized) + staticpro (&realtime_lisphz); + #ifdef HAVE_UNEXEC /* A valid but unlikely setting for the TZ environment variable. It is OK (though a bit slower) if the user chooses this value. */ @@ -589,7 +609,7 @@ timespec_to_lisp (struct timespec t) /* 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 +Lisp_Object make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz, long int hz, long int res) { @@ -604,13 +624,23 @@ make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz, return timespec_clockres_to_lisp (t, lisphz, hz, res); } -/* Convert T to a Lisp timestamp. */ +/* Convert T to a Lisp timestamp, assuming full resolution. */ Lisp_Object make_lisp_time (struct timespec t) { return make_lisp_time_clockres (t, timespec_hz, TIMESPEC_HZ, 1); } +/* Convert T to a Lisp timestamp, assuming gettime resolution. */ +Lisp_Object +make_lisp_realtime (struct timespec t) +{ + if (NILP (realtime_lisphz)) + abort (); + return make_lisp_time_clockres (t, realtime_lisphz, + realtime_hz, realtime_res); +} + /* Return NUMERATOR / DENOMINATOR, rounded to the nearest double. Arguments must be Lisp integers, and DENOMINATOR must be positive. */ static double @@ -1799,7 +1829,7 @@ DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, the current time in seconds. */) (void) { - return make_lisp_time (current_timespec ()); + return make_lisp_realtime (current_timespec ()); } DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, -- 2.35.1