]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix process-attributes time precision on GNU/Linux
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 5 Mar 2022 03:21:38 +0000 (19:21 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 5 Mar 2022 03:29:05 +0000 (19:29 -0800)
* src/sysdep.c [GNU_LINUX]:
(time_from_jiffies): Simplify by using time-convert.  Change args
and result type.  All uses changed.
(ltime_from_jiffies): Remove; call time_from_jiffies instead.
(put_jiffies): New function.
(get_up_time): Return Lisp_Object not struct timespec.
All uses changed.  Simplify by using time-add.
(system_process_attributes): Simplify by using the above.
This fixes some minor problems where timestamps promised more
precision than was actually available.  When info is not
available (e.g., sysconf fails) do not place it into the alist.
* src/timefns.c (float_time): Now extern.

src/sysdep.c
src/systime.h
src/timefns.c

index c9101f94818fbaa41d8e2c28d27f59eaf41d2fd0..a266307588c4d31a5bfe969b535a26f67e86d072 100644 (file)
@@ -3177,70 +3177,45 @@ make_lisp_timeval (long sec, long usec)
 #endif
 
 #ifdef GNU_LINUX
-static struct timespec
-time_from_jiffies (unsigned long long tval, long hz)
-{
-  unsigned long long s = tval / hz;
-  unsigned long long frac = tval % hz;
-  int ns;
-
-  if (TYPE_MAXIMUM (time_t) < s)
-    time_overflow ();
-  if (LONG_MAX - 1 <= ULLONG_MAX / TIMESPEC_HZ
-      || frac <= ULLONG_MAX / TIMESPEC_HZ)
-    ns = frac * TIMESPEC_HZ / hz;
-  else
-    {
-      /* This is reachable only in the unlikely case that HZ * HZ
-        exceeds ULLONG_MAX.  It calculates an approximation that is
-        guaranteed to be in range.  */
-      long hz_per_ns = hz / TIMESPEC_HZ + (hz % TIMESPEC_HZ != 0);
-      ns = frac / hz_per_ns;
-    }
 
-  return make_timespec (s, ns);
+static Lisp_Object
+time_from_jiffies (unsigned long long ticks, Lisp_Object hz, Lisp_Object form)
+{
+  return Ftime_convert (Fcons (make_uint (ticks), hz), form);
 }
 
 static Lisp_Object
-ltime_from_jiffies (unsigned long long tval, long hz)
+put_jiffies (Lisp_Object attrs, Lisp_Object propname,
+            unsigned long long ticks, Lisp_Object hz)
 {
-  struct timespec t = time_from_jiffies (tval, hz);
-  return make_lisp_time (t);
+  return Fcons (Fcons (propname, time_from_jiffies (ticks, hz, Qnil)), attrs);
 }
 
-static struct timespec
+static Lisp_Object
 get_up_time (void)
 {
   FILE *fup;
-  struct timespec up = make_timespec (0, 0);
+  Lisp_Object up = Qnil;
 
   block_input ();
   fup = emacs_fopen ("/proc/uptime", "r");
 
   if (fup)
     {
-      unsigned long long upsec, upfrac;
+      unsigned long long upsec;
+      EMACS_UINT upfrac;
       int upfrac_start, upfrac_end;
 
-      if (fscanf (fup, "%llu.%n%llu%n",
+      if (fscanf (fup, "%llu.%n%"pI"u%n",
                  &upsec, &upfrac_start, &upfrac, &upfrac_end)
          == 2)
        {
-         if (TYPE_MAXIMUM (time_t) < upsec)
-           {
-             upsec = TYPE_MAXIMUM (time_t);
-             upfrac = TIMESPEC_HZ - 1;
-           }
-         else
-           {
-             int upfraclen = upfrac_end - upfrac_start;
-             for (; upfraclen < LOG10_TIMESPEC_HZ; upfraclen++)
-               upfrac *= 10;
-             for (; LOG10_TIMESPEC_HZ < upfraclen; upfraclen--)
-               upfrac /= 10;
-             upfrac = min (upfrac, TIMESPEC_HZ - 1);
-           }
-         up = make_timespec (upsec, upfrac);
+         EMACS_INT hz = 1;
+         for (int i = upfrac_start; i < upfrac_end; i++)
+           hz *= 10;
+         Lisp_Object sec = make_uint (upsec);
+         Lisp_Object subsec = Fcons (make_fixnum (upfrac), make_fixnum (hz));
+         up = Ftime_add (sec, subsec);
        }
       fclose (fup);
     }
@@ -3361,7 +3336,6 @@ system_process_attributes (Lisp_Object pid)
   unsigned long long u_time, s_time, cutime, cstime, start;
   long priority, niceness, rss;
   unsigned long minflt, majflt, cminflt, cmajflt, vsize;
-  struct timespec tnow, tstart, tboot, telapsed, us_time;
   double pcpu, pmem;
   Lisp_Object attrs = Qnil;
   Lisp_Object decoded_cmd;
@@ -3449,45 +3423,41 @@ system_process_attributes (Lisp_Object pid)
          attrs = Fcons (Fcons (Qmajflt, INT_TO_INTEGER (majflt)), attrs);
          attrs = Fcons (Fcons (Qcminflt, INT_TO_INTEGER (cminflt)), attrs);
          attrs = Fcons (Fcons (Qcmajflt, INT_TO_INTEGER (cmajflt)), attrs);
+
          clocks_per_sec = sysconf (_SC_CLK_TCK);
-         if (clocks_per_sec < 0)
-           clocks_per_sec = 100;
-         attrs = Fcons (Fcons (Qutime,
-                               ltime_from_jiffies (u_time, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qstime,
-                               ltime_from_jiffies (s_time, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qtime,
-                               ltime_from_jiffies (s_time + u_time,
-                                                   clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qcutime,
-                               ltime_from_jiffies (cutime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qcstime,
-                               ltime_from_jiffies (cstime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qctime,
-                               ltime_from_jiffies (cstime + cutime,
-                                                   clocks_per_sec)),
-                        attrs);
+         if (0 < clocks_per_sec)
+           {
+             Lisp_Object hz = make_int (clocks_per_sec);
+             attrs = put_jiffies (attrs, Qutime, u_time, hz);
+             attrs = put_jiffies (attrs, Qstime, s_time, hz);
+             attrs = put_jiffies (attrs, Qtime, s_time + u_time, hz);
+             attrs = put_jiffies (attrs, Qcutime, cutime, hz);
+             attrs = put_jiffies (attrs, Qcstime, cstime, hz);
+             attrs = put_jiffies (attrs, Qctime, cstime + cutime, hz);
+
+             Lisp_Object uptime = get_up_time ();
+             if (!NILP (uptime))
+               {
+                 Lisp_Object now = Ftime_convert (Qnil, hz);
+                 Lisp_Object boot = Ftime_subtract (now, uptime);
+                 Lisp_Object tstart = time_from_jiffies (start, hz, hz);
+                 Lisp_Object lstart =
+                   Ftime_convert (Ftime_add (boot, tstart), Qnil);
+                 attrs = Fcons (Fcons (Qstart, lstart), attrs);
+                 Lisp_Object etime =
+                   Ftime_convert (Ftime_subtract (uptime, tstart), Qnil);
+                 attrs = Fcons (Fcons (Qetime, etime), attrs);
+                 pcpu = (100.0 * (s_time + u_time)
+                         / (clocks_per_sec * float_time (etime)));
+                 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
+               }
+           }
+
          attrs = Fcons (Fcons (Qpri, make_fixnum (priority)), attrs);
          attrs = Fcons (Fcons (Qnice, make_fixnum (niceness)), attrs);
          attrs = Fcons (Fcons (Qthcount, INT_TO_INTEGER (thcount)), attrs);
-         tnow = current_timespec ();
-         telapsed = get_up_time ();
-         tboot = timespec_sub (tnow, telapsed);
-         tstart = time_from_jiffies (start, clocks_per_sec);
-         tstart = timespec_add (tboot, tstart);
-         attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs);
          attrs = Fcons (Fcons (Qvsize, INT_TO_INTEGER (vsize / 1024)), attrs);
          attrs = Fcons (Fcons (Qrss, INT_TO_INTEGER (4 * rss)), attrs);
-         telapsed = timespec_sub (tnow, tstart);
-         attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs);
-         us_time = time_from_jiffies (u_time + s_time, clocks_per_sec);
-         pcpu = timespectod (us_time) / timespectod (telapsed);
-         attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs);
          pmem = 4.0 * 100 * rss / procfs_get_total_memory ();
          if (pmem > 100)
            pmem = 100;
index f3b1b2394dad8b41b02d675ab8cc408e76f99e15..41d728f1c2981bab967ab4adf289c7f4737fd8c4 100644 (file)
@@ -92,6 +92,7 @@ extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object,
                               Lisp_Object, struct timespec *);
 extern struct timespec lisp_time_argument (Lisp_Object);
 extern AVOID time_overflow (void);
+extern double float_time (Lisp_Object);
 extern void init_timefns (void);
 extern void syms_of_timefns (void);
 
index 795a6484ce9eb1fb99de19a6dc939420c56bf884..9b5b090ba71c655b3902c61ccb77fd9551bd4081 100644 (file)
@@ -881,7 +881,7 @@ decode_lisp_time (Lisp_Object specified_time, bool decode_secs_only,
 
 /* Convert a Lisp timestamp SPECIFIED_TIME to double.
    Signal an error if unsuccessful.  */
-static double
+double
 float_time (Lisp_Object specified_time)
 {
   double t;