gdb: Use C++11 std::chrono
authorPedro Alves <palves@redhat.com>
Wed, 23 Nov 2016 15:36:26 +0000 (15:36 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 23 Nov 2016 15:36:26 +0000 (15:36 +0000)
This patch fixes a few problems with GDB's time handling.

#1 - It avoids problems with gnulib's C++ namespace support

On MinGW, the struct timeval that should be passed to gnulib's
gettimeofday replacement is incompatible with libiberty's
timeval_sub/timeval_add.  That's because gnulib also replaces "struct
timeval" with its own definition, while libiberty expects the
system's.

E.g., in code like this:

  gettimeofday (&prompt_ended, NULL);
  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
  timeval_add (&prompt_for_continue_wait_time,
               &prompt_for_continue_wait_time, &prompt_delta);

That's currently handled in gdb by not using gnulib's gettimeofday at
all (see common/gdb_sys_time.h), but that #undef hack won't work with
if/when we enable gnulib's C++ namespace support, because that mode
adds compile time warnings for uses of ::gettimeofday, which are hard
errors with -Werror.

#2 - But there's an elephant in the room: gettimeofday is not monotonic...

We're using it to:

  a) check how long functions take, for performance analysis
  b) compute when in the future to fire events in the event-loop
  c) print debug timestamps

But that's exactly what gettimeofday is NOT meant for.  Straight from
the man page:

~~~
       The time returned by gettimeofday() is affected by
       discontinuous jumps in the system time (e.g., if the system
       administrator manually changes the system time).  If you need a
       monotonically increasing clock, see clock_gettime(2).
~~~

std::chrono (part of the C++11 standard library) has a monotonic clock
exactly for such purposes (std::chrono::steady_clock).  This commit
switches to use that instead of gettimeofday, fixing all the issues
mentioned above.

gdb/ChangeLog:
2016-11-23  Pedro Alves  <palves@redhat.com>

* Makefile.in (SFILES): Add common/run-time-clock.c.
(HFILES_NO_SRCDIR): Add common/run-time-clock.h.
(COMMON_OBS): Add run-time-clock.o.
* common/run-time-clock.c, common/run-time-clock.h: New files.
* defs.h (struct timeval, print_transfer_performance): Delete
declarations.
* event-loop.c (struct gdb_timer) <when>: Now a
std::chrono::steady_clock::time_point.
(create_timer): use std::chrono::steady_clock instead of
gettimeofday.  Use new instead of malloc.
(delete_timer): Use delete instead of xfree.
(duration_cast_timeval): New.
(update_wait_timeout): Use std::chrono::steady_clock instead of
gettimeofday.
* maint.c: Include <chrono> instead of "gdb_sys_time.h", <time.h>
and "timeval-utils.h".
(scoped_command_stats::~scoped_command_stats)
(scoped_command_stats::scoped_command_stats): Use
std::chrono::steady_clock instead of gettimeofday.  Use
user_cpu_time_clock instead of get_run_time.
* maint.h: Include "run-time-clock.h" and <chrono>.
(scoped_command_stats): <m_start_cpu_time>: Now a
user_cpu_time_clock::time_point.
<m_start_wall_time>: Now a std::chrono::steady_clock::time_point.
* mi/mi-main.c: Include "run-time-clock.h" and <chrono> instead of
"gdb_sys_time.h" and <sys/resource.h>.
(rusage): Delete.
(mi_execute_command): Use new instead of XNEW.
(mi_load_progress): Use std::chrono::steady_clock instead of
gettimeofday.
(timestamp): Rewrite in terms of std::chrono::steady_clock,
user_cpu_time_clock and system_cpu_time_clock.
(timeval_diff): Delete.
(print_diff): Adjust to use std::chrono::steady_clock,
user_cpu_time_clock and system_cpu_time_clock.
* mi/mi-parse.h: Include "run-time-clock.h" and <chrono> instead
of "gdb_sys_time.h".
(struct mi_timestamp): Change fields types to
std::chrono::steady_clock::time_point, user_cpu_time_clock::time
and system_cpu_time_clock::time_point, instead of struct timeval.
* symfile.c: Include <chrono> instead of <time.h> and
"gdb_sys_time.h".
(struct time_range): New.
(generic_load): Use std::chrono::steady_clock instead of
gettimeofday.
(print_transfer_performance): Replace timeval parameters with a
std::chrono::steady_clock::duration parameter.  Adjust.
* utils.c: Include <chrono> instead of "timeval-utils.h",
"gdb_sys_time.h", and <time.h>.
(prompt_for_continue_wait_time): Now a
std::chrono::steady_clock::duration.
(defaulted_query, prompt_for_continue): Use
std::chrono::steady_clock instead of
gettimeofday/timeval_sub/timeval_add.
(reset_prompt_for_continue_wait_time): Use
std::chrono::steady_clock::duration instead of struct timeval.
(get_prompt_for_continue_wait_time): Return a
std::chrono::steady_clock::duration instead of struct timeval.
(vfprintf_unfiltered): Use std::chrono::steady_clock instead of
gettimeofday.  Use std::string.  Use '.' instead of ':'.
* utils.h: Include <chrono>.
(get_prompt_for_continue_wait_time): Return a
std::chrono::steady_clock::duration instead of struct timeval.

gdb/gdbserver/ChangeLog:
2016-11-23  Pedro Alves  <palves@redhat.com>

* debug.c: Include <chrono> instead of "gdb_sys_time.h".
(debug_vprintf): Use std::chrono::steady_clock instead of
gettimeofday.  Use '.' instead of ':'.
* tracepoint.c: Include <chrono> instead of "gdb_sys_time.h".
(get_timestamp): Use std::chrono::steady_clock instead of
gettimeofday.

16 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/common/run-time-clock.c [new file with mode: 0644]
gdb/common/run-time-clock.h [new file with mode: 0644]
gdb/defs.h
gdb/event-loop.c
gdb/gdbserver/ChangeLog
gdb/gdbserver/debug.c
gdb/gdbserver/tracepoint.c
gdb/maint.c
gdb/maint.h
gdb/mi/mi-main.c
gdb/mi/mi-parse.h
gdb/symfile.c
gdb/utils.c
gdb/utils.h

index a9a82491f740d850c4e03151ee862e20e643442e..a2a11e2461b5fbd7903f3fea83a6d60828ed2b93 100644 (file)
@@ -1,3 +1,69 @@
+2016-11-23  Pedro Alves  <palves@redhat.com>
+
+       * Makefile.in (SFILES): Add common/run-time-clock.c.
+       (HFILES_NO_SRCDIR): Add common/run-time-clock.h.
+       (COMMON_OBS): Add run-time-clock.o.
+       * common/run-time-clock.c, common/run-time-clock.h: New files.
+       * defs.h (struct timeval, print_transfer_performance): Delete
+       declarations.
+       * event-loop.c (struct gdb_timer) <when>: Now a
+       std::chrono::steady_clock::time_point.
+       (create_timer): use std::chrono::steady_clock instead of
+       gettimeofday.  Use new instead of malloc.
+       (delete_timer): Use delete instead of xfree.
+       (duration_cast_timeval): New.
+       (update_wait_timeout): Use std::chrono::steady_clock instead of
+       gettimeofday.
+       * maint.c: Include <chrono> instead of "gdb_sys_time.h", <time.h>
+       and "timeval-utils.h".
+       (scoped_command_stats::~scoped_command_stats)
+       (scoped_command_stats::scoped_command_stats): Use
+       std::chrono::steady_clock instead of gettimeofday.  Use
+       user_cpu_time_clock instead of get_run_time.
+       * maint.h: Include "run-time-clock.h" and <chrono>.
+       (scoped_command_stats): <m_start_cpu_time>: Now a
+       user_cpu_time_clock::time_point.
+       <m_start_wall_time>: Now a std::chrono::steady_clock::time_point.
+       * mi/mi-main.c: Include "run-time-clock.h" and <chrono> instead of
+       "gdb_sys_time.h" and <sys/resource.h>.
+       (rusage): Delete.
+       (mi_execute_command): Use new instead of XNEW.
+       (mi_load_progress): Use std::chrono::steady_clock instead of
+       gettimeofday.
+       (timestamp): Rewrite in terms of std::chrono::steady_clock,
+       user_cpu_time_clock and system_cpu_time_clock.
+       (timeval_diff): Delete.
+       (print_diff): Adjust to use std::chrono::steady_clock,
+       user_cpu_time_clock and system_cpu_time_clock.
+       * mi/mi-parse.h: Include "run-time-clock.h" and <chrono> instead
+       of "gdb_sys_time.h".
+       (struct mi_timestamp): Change fields types to
+       std::chrono::steady_clock::time_point, user_cpu_time_clock::time
+       and system_cpu_time_clock::time_point, instead of struct timeval.
+       * symfile.c: Include <chrono> instead of <time.h> and
+       "gdb_sys_time.h".
+       (struct time_range): New.
+       (generic_load): Use std::chrono::steady_clock instead of
+       gettimeofday.
+       (print_transfer_performance): Replace timeval parameters with a
+       std::chrono::steady_clock::duration parameter.  Adjust.
+       * utils.c: Include <chrono> instead of "timeval-utils.h",
+       "gdb_sys_time.h", and <time.h>.
+       (prompt_for_continue_wait_time): Now a
+       std::chrono::steady_clock::duration.
+       (defaulted_query, prompt_for_continue): Use
+       std::chrono::steady_clock instead of
+       gettimeofday/timeval_sub/timeval_add.
+       (reset_prompt_for_continue_wait_time): Use
+       std::chrono::steady_clock::duration instead of struct timeval.
+       (get_prompt_for_continue_wait_time): Return a
+       std::chrono::steady_clock::duration instead of struct timeval.
+       (vfprintf_unfiltered): Use std::chrono::steady_clock instead of
+       gettimeofday.  Use std::string.  Use '.' instead of ':'.
+       * utils.h: Include <chrono>.
+       (get_prompt_for_continue_wait_time): Return a
+       std::chrono::steady_clock::duration instead of struct timeval.
+
 2016-11-22  Simon Marchi  <simon.marchi@polymtl.ca>
 
        * Makefile.in: Fix whitespace formatting.
index e3e3ce4cba141cca21ce503f53ab5f9207a8f076..44a743ee6587fa75e3fc15d80a65252a711bfe4d 100644 (file)
@@ -1201,6 +1201,7 @@ SFILES = \
        common/print-utils.c \
        common/ptid.c \
        common/rsp-low.c \
+       common/run-time-clock.c \
        common/signals.c \
        common/signals-state-save-restore.c \
        common/vec.c \
@@ -1485,6 +1486,7 @@ HFILES_NO_SRCDIR = \
        common/ptid.h \
        common/queue.h \
        common/rsp-low.h \
+       common/run-time-clock.h \
        common/signals-state-save-restore.h \
        common/symbol.h \
        common/vec.h \
@@ -1739,6 +1741,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
        registry.o \
        reverse.o \
        rsp-low.o \
+       run-time-clock.o \
        rust-lang.o \
        selftest.o \
        sentinel-frame.o \
diff --git a/gdb/common/run-time-clock.c b/gdb/common/run-time-clock.c
new file mode 100644 (file)
index 0000000..f9dc7a0
--- /dev/null
@@ -0,0 +1,58 @@
+/* User/system CPU time clocks that follow the std::chrono interface.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "run-time-clock.h"
+#if defined HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+using namespace std::chrono;
+
+run_time_clock::time_point
+run_time_clock::now () noexcept
+{
+  return time_point (microseconds (get_run_time ()));
+}
+
+#ifdef HAVE_GETRUSAGE
+static std::chrono::microseconds
+timeval_to_microseconds (struct timeval *tv)
+{
+  return (seconds (tv->tv_sec) + microseconds (tv->tv_usec));
+}
+#endif
+
+void
+run_time_clock::now (user_cpu_time_clock::time_point &user,
+                    system_cpu_time_clock::time_point &system) noexcept
+{
+#ifdef HAVE_GETRUSAGE
+  struct rusage rusage;
+
+  getrusage (RUSAGE_SELF, &rusage);
+
+  microseconds utime = timeval_to_microseconds (&rusage.ru_utime);
+  microseconds stime = timeval_to_microseconds (&rusage.ru_stime);
+  user = user_cpu_time_clock::time_point (utime);
+  system = system_cpu_time_clock::time_point (stime);
+#else
+  user = user_cpu_time_clock::time_point (microseconds (get_run_time ()));
+  system = system_cpu_time_clock::time_point (microseconds::zero ());
+#endif
+}
diff --git a/gdb/common/run-time-clock.h b/gdb/common/run-time-clock.h
new file mode 100644 (file)
index 0000000..ee531bb
--- /dev/null
@@ -0,0 +1,75 @@
+/* User/system CPU time clocks that follow the std::chrono interface.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RUN_TIME_CLOCK_H
+#define RUN_TIME_CLOCK_H
+
+#include <chrono>
+
+/* Count the total amount of time spent executing in user mode.  */
+
+struct user_cpu_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<user_cpu_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  /* Use run_time_clock::now instead.  */
+  static time_point now () noexcept = delete;
+};
+
+/* Count the total amount of time spent executing in kernel mode.  */
+
+struct system_cpu_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<system_cpu_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  /* Use run_time_clock::now instead.  */
+  static time_point now () noexcept = delete;
+};
+
+/* Count the total amount of time spent executing in userspace+kernel
+   mode.  */
+
+struct run_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<run_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  static time_point now () noexcept;
+
+  /* Return the user/system time as separate time points, if
+     supported.  If not supported, then the combined user+kernel time
+     is returned in USER and SYSTEM is set to zero.  */
+  static void now (user_cpu_time_clock::time_point &user,
+                  system_cpu_time_clock::time_point &system) noexcept;
+};
+
+#endif
index 6d0d2dd433a374ea3a5cac0d795d9543a27ff55e..3d21f62f52cc3a59d5effb62dcb78014acdfc092 100644 (file)
@@ -303,20 +303,6 @@ extern void symbol_file_command (char *, int);
 /* * Remote targets may wish to use this as their load function.  */
 extern void generic_load (const char *name, int from_tty);
 
-/* * Report on STREAM the performance of memory transfer operation,
-   such as 'load'.
-   @param DATA_COUNT is the number of bytes transferred.
-   @param WRITE_COUNT is the number of separate write operations, or 0,
-   if that information is not available.
-   @param START_TIME is the time at which an operation was started.
-   @param END_TIME is the time at which an operation ended.  */
-struct timeval;
-extern void print_transfer_performance (struct ui_file *stream,
-                                       unsigned long data_count,
-                                       unsigned long write_count,
-                                       const struct timeval *start_time,
-                                       const struct timeval *end_time);
-
 /* From top.c */
 
 typedef void initialize_file_ftype (void);
index f94a6fa135f579cf0cdaf2920d3f663ce1dfcf4b..9e8cf66c8fd02f26ff149d5c9c1faeb9d9d20b23 100644 (file)
@@ -212,7 +212,7 @@ gdb_notifier;
    first occasion after WHEN.  */
 struct gdb_timer
   {
-    struct timeval when;
+    std::chrono::steady_clock::time_point when;
     int timer_id;
     struct gdb_timer *next;
     timer_handler_func *proc;      /* Function to call to do the work.  */
@@ -1097,33 +1097,22 @@ delete_async_event_handler (async_event_handler **async_handler_ptr)
   *async_handler_ptr = NULL;
 }
 
-/* Create a timer that will expire in MILLISECONDS from now.  When the
-   timer is ready, PROC will be executed.  At creation, the timer is
-   aded to the timers queue.  This queue is kept sorted in order of
-   increasing timers.  Return a handle to the timer struct.  */
+/* Create a timer that will expire in MS milliseconds from now.  When
+   the timer is ready, PROC will be executed.  At creation, the timer
+   is added to the timers queue.  This queue is kept sorted in order
+   of increasing timers.  Return a handle to the timer struct.  */
+
 int
-create_timer (int milliseconds, timer_handler_func * proc, 
+create_timer (int ms, timer_handler_func *proc,
              gdb_client_data client_data)
 {
+  using namespace std::chrono;
   struct gdb_timer *timer_ptr, *timer_index, *prev_timer;
-  struct timeval time_now, delta;
-
-  /* Compute seconds.  */
-  delta.tv_sec = milliseconds / 1000;
-  /* Compute microseconds.  */
-  delta.tv_usec = (milliseconds % 1000) * 1000;
 
-  gettimeofday (&time_now, NULL);
+  steady_clock::time_point time_now = steady_clock::now ();
 
-  timer_ptr = XNEW (struct gdb_timer);
-  timer_ptr->when.tv_sec = time_now.tv_sec + delta.tv_sec;
-  timer_ptr->when.tv_usec = time_now.tv_usec + delta.tv_usec;
-  /* Carry?  */
-  if (timer_ptr->when.tv_usec >= 1000000)
-    {
-      timer_ptr->when.tv_sec += 1;
-      timer_ptr->when.tv_usec -= 1000000;
-    }
+  timer_ptr = new gdb_timer ();
+  timer_ptr->when = time_now + milliseconds (ms);
   timer_ptr->proc = proc;
   timer_ptr->client_data = client_data;
   timer_list.num_timers++;
@@ -1136,11 +1125,7 @@ create_timer (int milliseconds, timer_handler_func * proc,
        timer_index != NULL;
        timer_index = timer_index->next)
     {
-      /* If the seconds field is greater or if it is the same, but the
-         microsecond field is greater.  */
-      if ((timer_index->when.tv_sec > timer_ptr->when.tv_sec)
-         || ((timer_index->when.tv_sec == timer_ptr->when.tv_sec)
-             && (timer_index->when.tv_usec > timer_ptr->when.tv_usec)))
+      if (timer_index->when > timer_ptr->when)
        break;
     }
 
@@ -1194,47 +1179,56 @@ delete_timer (int id)
        ;
       prev_timer->next = timer_ptr->next;
     }
-  xfree (timer_ptr);
+  delete timer_ptr;
 
   gdb_notifier.timeout_valid = 0;
 }
 
+/* Convert a std::chrono duration to a struct timeval.  */
+
+template<typename Duration>
+static struct timeval
+duration_cast_timeval (const Duration &d)
+{
+  using namespace std::chrono;
+  seconds sec = duration_cast<seconds> (d);
+  microseconds msec = duration_cast<microseconds> (d - sec);
+
+  struct timeval tv;
+  tv.tv_sec = sec.count ();
+  tv.tv_usec = msec.count ();
+  return tv;
+}
+
 /* Update the timeout for the select() or poll().  Returns true if the
    timer has already expired, false otherwise.  */
 
 static int
 update_wait_timeout (void)
 {
-  struct timeval time_now, delta;
-
   if (timer_list.first_timer != NULL)
     {
-      gettimeofday (&time_now, NULL);
-      delta.tv_sec = timer_list.first_timer->when.tv_sec - time_now.tv_sec;
-      delta.tv_usec = timer_list.first_timer->when.tv_usec - time_now.tv_usec;
-      /* Borrow?  */
-      if (delta.tv_usec < 0)
-       {
-         delta.tv_sec -= 1;
-         delta.tv_usec += 1000000;
-       }
+      using namespace std::chrono;
+      steady_clock::time_point time_now = steady_clock::now ();
+      struct timeval timeout;
 
-      /* Cannot simply test if delta.tv_sec is negative because time_t
-         might be unsigned.  */
-      if (timer_list.first_timer->when.tv_sec < time_now.tv_sec
-         || (timer_list.first_timer->when.tv_sec == time_now.tv_sec
-             && timer_list.first_timer->when.tv_usec < time_now.tv_usec))
+      if (timer_list.first_timer->when < time_now)
        {
          /* It expired already.  */
-         delta.tv_sec = 0;
-         delta.tv_usec = 0;
+         timeout.tv_sec = 0;
+         timeout.tv_usec = 0;
+       }
+      else
+       {
+         steady_clock::duration d = timer_list.first_timer->when - time_now;
+         timeout = duration_cast_timeval (d);
        }
 
       /* Update the timeout for select/ poll.  */
       if (use_poll)
        {
 #ifdef HAVE_POLL
-         gdb_notifier.poll_timeout = delta.tv_sec * 1000;
+         gdb_notifier.poll_timeout = timeout.tv_sec * 1000;
 #else
          internal_error (__FILE__, __LINE__,
                          _("use_poll without HAVE_POLL"));
@@ -1242,12 +1236,12 @@ update_wait_timeout (void)
        }
       else
        {
-         gdb_notifier.select_timeout.tv_sec = delta.tv_sec;
-         gdb_notifier.select_timeout.tv_usec = delta.tv_usec;
+         gdb_notifier.select_timeout.tv_sec = timeout.tv_sec;
+         gdb_notifier.select_timeout.tv_usec = timeout.tv_usec;
        }
       gdb_notifier.timeout_valid = 1;
 
-      if (delta.tv_sec == 0 && delta.tv_usec == 0)
+      if (timer_list.first_timer->when < time_now)
        return 1;
     }
   else
index 701e22ed0ce79db0452c6b280d92226cf132abc5..8b83461668c7893da02b897437b9403365e63d84 100644 (file)
@@ -1,3 +1,12 @@
+2016-11-23  Pedro Alves  <palves@redhat.com>
+
+       * debug.c: Include <chrono> instead of "gdb_sys_time.h".
+       (debug_vprintf): Use std::chrono::steady_clock instead of
+       gettimeofday.  Use '.' instead of ':'.
+       * tracepoint.c: Include <chrono> instead of "gdb_sys_time.h".
+       (get_timestamp): Use std::chrono::steady_clock instead of
+       gettimeofday.
+
 2016-11-22  Simon Marchi  <simon.marchi@polymtl.ca>
 
        * Makefile.in: Fix whitespace formatting.
index 54f2665d929187aface5a9b30d5d11b87373869a..0e6a3a6850550be0bd9d28edbc567c2e779e8ada 100644 (file)
@@ -17,7 +17,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
-#include "gdb_sys_time.h"
+#include <chrono>
 
 /* Enable miscellaneous debugging output.  The name is historical - it
    was originally used to debug LinuxThreads support.  */
@@ -27,8 +27,7 @@ int debug_threads;
 int debug_timestamp;
 
 /* Print a debugging message.
-   If the text begins a new line it is preceded by a timestamp, if the
-   system has gettimeofday.
+   If the text begins a new line it is preceded by a timestamp.
    We don't get fancy with newline checking, we just check whether the
    previous call ended with "\n".  */
 
@@ -41,14 +40,13 @@ debug_vprintf (const char *format, va_list ap)
 
   if (debug_timestamp && new_line)
     {
-      struct timeval tm;
+      using namespace std::chrono;
 
-      gettimeofday (&tm, NULL);
+      steady_clock::time_point now = steady_clock::now ();
+      seconds s = duration_cast<seconds> (now.time_since_epoch ());
+      microseconds us = duration_cast<microseconds> (now.time_since_epoch ()) - s;
 
-      /* If gettimeofday doesn't exist, and as a portability solution it has
-        been replaced with, e.g., time, then it doesn't make sense to print
-        the microseconds field.  Is there a way to check for that?  */
-      fprintf (stderr, "%ld:%06ld ", (long) tm.tv_sec, (long) tm.tv_usec);
+      fprintf (stderr, "%ld.%06ld ", (long) s.count (), (long) us.count ());
     }
 #endif
 
index 7700ad121fcca8d27cec44413216a049e70941be..1444a0db31c547f03f0dd3a8a8ff50b40bb4b3d7 100644 (file)
@@ -25,7 +25,7 @@
 #include <ctype.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include "gdb_sys_time.h"
+#include <chrono>
 #include <inttypes.h>
 #include "ax.h"
 #include "tdesc.h"
@@ -7410,12 +7410,10 @@ getauxval (unsigned long type)
 static LONGEST
 get_timestamp (void)
 {
-   struct timeval tv;
+  using namespace std::chrono;
 
-   if (gettimeofday (&tv, 0) != 0)
-     return -1;
-   else
-     return (LONGEST) tv.tv_sec * 1000000 + tv.tv_usec;
+  steady_clock::time_point now = steady_clock::now ();
+  return duration_cast<microseconds> (now.time_since_epoch ()).count ();
 }
 
 void
index 738571c73c049a8077c75fcc0f28a9540fee049c..b43dbf9d9d0c1e1e130d2c78be18d06211b461f7 100644 (file)
@@ -24,8 +24,6 @@
 #include "arch-utils.h"
 #include <ctype.h>
 #include <signal.h>
-#include "gdb_sys_time.h"
-#include <time.h>
 #include "command.h"
 #include "gdbcmd.h"
 #include "symtab.h"
@@ -39,7 +37,6 @@
 #include "objfiles.h"
 #include "value.h"
 #include "top.h"
-#include "timeval-utils.h"
 #include "maint.h"
 #include "selftest.h"
 
@@ -822,23 +819,21 @@ scoped_command_stats::~scoped_command_stats ()
 
   if (m_time_enabled && per_command_time)
     {
-      long cmd_time = get_run_time () - m_start_cpu_time;
-      struct timeval now_wall_time, delta_wall_time, wait_time;
+      using namespace std::chrono;
 
-      gettimeofday (&now_wall_time, NULL);
-      timeval_sub (&delta_wall_time,
-                  &now_wall_time, &m_start_wall_time);
+      run_time_clock::duration cmd_time
+       = run_time_clock::now () - m_start_cpu_time;
 
+      steady_clock::duration wall_time
+       = steady_clock::now () - m_start_wall_time;
       /* Subtract time spend in prompt_for_continue from walltime.  */
-      wait_time = get_prompt_for_continue_wait_time ();
-      timeval_sub (&delta_wall_time, &delta_wall_time, &wait_time);
+      wall_time -= get_prompt_for_continue_wait_time ();
 
       printf_unfiltered (!m_msg_type
-                        ? _("Startup time: %ld.%06ld (cpu), %ld.%06ld (wall)\n")
-                        : _("Command execution time: %ld.%06ld (cpu), %ld.%06ld (wall)\n"),
-                        cmd_time / 1000000, cmd_time % 1000000,
-                        (long) delta_wall_time.tv_sec,
-                        (long) delta_wall_time.tv_usec);
+                        ? _("Startup time: %.6f (cpu), %.6f (wall)\n")
+                        : _("Command execution time: %.6f (cpu), %.6f (wall)\n"),
+                        duration<double> (cmd_time).count (),
+                        duration<double> (wall_time).count ());
     }
 
   if (m_space_enabled && per_command_space)
@@ -892,8 +887,10 @@ scoped_command_stats::scoped_command_stats (bool msg_type)
 
   if (msg_type == 0 || per_command_time)
     {
-      m_start_cpu_time = get_run_time ();
-      gettimeofday (&m_start_wall_time, NULL);
+      using namespace std::chrono;
+
+      m_start_cpu_time = run_time_clock::now ();
+      m_start_wall_time = steady_clock::now ();
       m_time_enabled = 1;
     }
   else
index 8d0380099454dea6ce8cd335e5ced89234249572..2af405d57e4ba83c06d30759f4b6bb6a52595734 100644 (file)
@@ -19,6 +19,9 @@
 #ifndef MAINT_H
 #define MAINT_H
 
+#include "run-time-clock.h"
+#include <chrono>
+
 extern void set_per_command_time (int);
 
 extern void set_per_command_space (int);
@@ -48,8 +51,8 @@ class scoped_command_stats
   int m_time_enabled : 1;
   int m_space_enabled : 1;
   int m_symtab_enabled : 1;
-  long m_start_cpu_time;
-  struct timeval m_start_wall_time;
+  run_time_clock::time_point m_start_cpu_time;
+  std::chrono::steady_clock::time_point m_start_wall_time;
   long m_start_space;
   /* Total number of symtabs (over all objfiles).  */
   int m_start_nr_symtabs;
index 984a415a052a6c74e1fb61e0d326cde0e75dc9d0..4d276c867d162f5c9bff1ddee015ca42dc42d1fd 100644 (file)
 #include "observer.h"
 
 #include <ctype.h>
-#include "gdb_sys_time.h"
-
-#if defined HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-#ifdef HAVE_GETRUSAGE
-struct rusage rusage;
-#endif
+#include "run-time-clock.h"
+#include <chrono>
 
 enum
   {
@@ -2169,7 +2162,7 @@ mi_execute_command (const char *cmd, int from_tty)
 
       if (do_timings)
        {
-         command->cmd_start = XNEW (struct mi_timestamp);
+         command->cmd_start = new mi_timestamp ();
          timestamp (command->cmd_start);
        }
 
@@ -2390,8 +2383,8 @@ mi_load_progress (const char *section_name,
                  unsigned long total_sent,
                  unsigned long grand_total)
 {
-  struct timeval time_now, delta, update_threshold;
-  static struct timeval last_update;
+  using namespace std::chrono;
+  static steady_clock::time_point last_update;
   static char *previous_sect_name = NULL;
   int new_section;
   struct ui_out *saved_uiout;
@@ -2416,19 +2409,6 @@ mi_load_progress (const char *section_name,
 
   uiout = current_uiout;
 
-  update_threshold.tv_sec = 0;
-  update_threshold.tv_usec = 500000;
-  gettimeofday (&time_now, NULL);
-
-  delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
-  delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
-
-  if (delta.tv_usec < 0)
-    {
-      delta.tv_sec -= 1;
-      delta.tv_usec += 1000000L;
-    }
-
   new_section = (previous_sect_name ?
                 strcmp (previous_sect_name, section_name) : 1);
   if (new_section)
@@ -2451,13 +2431,12 @@ mi_load_progress (const char *section_name,
       gdb_flush (mi->raw_stdout);
     }
 
-  if (delta.tv_sec >= update_threshold.tv_sec &&
-      delta.tv_usec >= update_threshold.tv_usec)
+  steady_clock::time_point time_now = steady_clock::now ();
+  if (time_now - last_update > milliseconds (500))
     {
       struct cleanup *cleanup_tuple;
 
-      last_update.tv_sec = time_now.tv_sec;
-      last_update.tv_usec = time_now.tv_usec;
+      last_update = time_now;
       if (current_token)
        fputs_unfiltered (current_token, mi->raw_stdout);
       fputs_unfiltered ("+download", mi->raw_stdout);
@@ -2480,23 +2459,10 @@ mi_load_progress (const char *section_name,
 static void
 timestamp (struct mi_timestamp *tv)
 {
-  gettimeofday (&tv->wallclock, NULL);
-#ifdef HAVE_GETRUSAGE
-  getrusage (RUSAGE_SELF, &rusage);
-  tv->utime.tv_sec = rusage.ru_utime.tv_sec;
-  tv->utime.tv_usec = rusage.ru_utime.tv_usec;
-  tv->stime.tv_sec = rusage.ru_stime.tv_sec;
-  tv->stime.tv_usec = rusage.ru_stime.tv_usec;
-#else
-  {
-    long usec = get_run_time ();
+  using namespace std::chrono;
 
-    tv->utime.tv_sec = usec/1000000L;
-    tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec;
-    tv->stime.tv_sec = 0;
-    tv->stime.tv_usec = 0;
-  }
-#endif
+  tv->wallclock = steady_clock::now ();
+  run_time_clock::now (tv->utime, tv->stime);
 }
 
 static void
@@ -2517,23 +2483,20 @@ mi_print_timing_maybe (struct ui_file *file)
     print_diff_now (file, current_command_ts);
 }
 
-static long
-timeval_diff (struct timeval start, struct timeval end)
-{
-  return ((end.tv_sec - start.tv_sec) * 1000000L)
-    + (end.tv_usec - start.tv_usec);
-}
-
 static void
 print_diff (struct ui_file *file, struct mi_timestamp *start,
            struct mi_timestamp *end)
 {
+  using namespace std::chrono;
+
+  duration<double> wallclock = end->wallclock - start->wallclock;
+  duration<double> utime = end->utime - start->utime;
+  duration<double> stime = end->stime - start->stime;
+
   fprintf_unfiltered
     (file,
      ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}",
-     timeval_diff (start->wallclock, end->wallclock) / 1000000.0,
-     timeval_diff (start->utime, end->utime) / 1000000.0,
-     timeval_diff (start->stime, end->stime) / 1000000.0);
+     wallclock.count (), utime.count (), stime.count ());
 }
 
 void
index d5595b37e935292a509176b27a7469f1813998c2..dc8d21b5c6b8d019c3390aa3d2e8568ccc1a30ab 100644 (file)
 #ifndef MI_PARSE_H
 #define MI_PARSE_H
 
-#include "gdb_sys_time.h"
+#include "run-time-clock.h"
+#include <chrono>
 
 /* MI parser */
 
 /* Timestamps for current command and last asynchronous command.  */
-struct mi_timestamp {
-  struct timeval wallclock;
-  struct timeval utime;
-  struct timeval stime;
+struct mi_timestamp
+{
+  std::chrono::steady_clock::time_point wallclock;
+  user_cpu_time_clock::time_point utime;
+  system_cpu_time_clock::time_point stime;
 };
 
 enum mi_command_type
index f524f56b367e825426bfa1c1fac9148fbd85d0cf..517c277c722e0b5bb93a3f0080bf25c1eb34d661 100644 (file)
@@ -61,8 +61,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <ctype.h>
-#include <time.h>
-#include "gdb_sys_time.h"
+#include <chrono>
 
 #include "psymtab.h"
 
@@ -2066,11 +2065,15 @@ clear_memory_write_data (void *arg)
   VEC_free (memory_write_request_s, vec);
 }
 
+static void print_transfer_performance (struct ui_file *stream,
+                                       unsigned long data_count,
+                                       unsigned long write_count,
+                                       std::chrono::steady_clock::duration d);
+
 void
 generic_load (const char *args, int from_tty)
 {
   bfd *loadfile_bfd;
-  struct timeval start_time, end_time;
   char *filename;
   struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
   struct load_section_data cbdata;
@@ -2131,13 +2134,15 @@ generic_load (const char *args, int from_tty)
 
   bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
 
-  gettimeofday (&start_time, NULL);
+  using namespace std::chrono;
+
+  steady_clock::time_point start_time = steady_clock::now ();
 
   if (target_write_memory_blocks (cbdata.requests, flash_discard,
                                  load_progress) != 0)
     error (_("Load failed"));
 
-  gettimeofday (&end_time, NULL);
+  steady_clock::time_point end_time = steady_clock::now ();
 
   entry = bfd_get_start_address (loadfile_bfd);
   entry = gdbarch_addr_bits_remove (target_gdbarch (), entry);
@@ -2160,32 +2165,32 @@ generic_load (const char *args, int from_tty)
 
   print_transfer_performance (gdb_stdout, total_progress.data_count,
                              total_progress.write_count,
-                             &start_time, &end_time);
+                             end_time - start_time);
 
   do_cleanups (old_cleanups);
 }
 
-/* Report how fast the transfer went.  */
+/* Report on STREAM the performance of a memory transfer operation,
+   such as 'load'.  DATA_COUNT is the number of bytes transferred.
+   WRITE_COUNT is the number of separate write operations, or 0, if
+   that information is not available.  TIME is how long the operation
+   lasted.  */
 
-void
+static void
 print_transfer_performance (struct ui_file *stream,
                            unsigned long data_count,
                            unsigned long write_count,
-                           const struct timeval *start_time,
-                           const struct timeval *end_time)
+                           std::chrono::steady_clock::duration time)
 {
-  ULONGEST time_count;
+  using namespace std::chrono;
   struct ui_out *uiout = current_uiout;
 
-  /* Compute the elapsed time in milliseconds, as a tradeoff between
-     accuracy and overflow.  */
-  time_count = (end_time->tv_sec - start_time->tv_sec) * 1000;
-  time_count += (end_time->tv_usec - start_time->tv_usec) / 1000;
+  milliseconds ms = duration_cast<milliseconds> (time);
 
   ui_out_text (uiout, "Transfer rate: ");
-  if (time_count > 0)
+  if (ms.count () > 0)
     {
-      unsigned long rate = ((ULONGEST) data_count * 1000) / time_count;
+      unsigned long rate = ((ULONGEST) data_count * 1000) / ms.count ();
 
       if (ui_out_is_mi_like_p (uiout))
        {
index 751f09949d624da8c10d20e279d60d114028dc63..8ca0a2ee779f90f024fe726baffe604ae5e0f730 100644 (file)
@@ -37,7 +37,6 @@
 #endif
 
 #include <signal.h>
-#include "timeval-utils.h"
 #include "gdbcmd.h"
 #include "serial.h"
 #include "bfd.h"
@@ -61,8 +60,7 @@
 
 #include "readline/readline.h"
 
-#include "gdb_sys_time.h"
-#include <time.h>
+#include <chrono>
 
 #include "gdb_usleep.h"
 #include "interps.h"
@@ -98,7 +96,7 @@ static void set_width (void);
    Modified in prompt_for_continue and defaulted_query.
    Used in report_command_stats.  */
 
-static struct timeval prompt_for_continue_wait_time;
+static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 /* A flag indicating whether to timestamp debugging messages.  */
 
@@ -1184,9 +1182,6 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
   int def_value;
   char def_answer, not_def_answer;
   char *y_string, *n_string, *question, *prompt;
-  /* Used to add duration we waited for user to respond to
-     prompt_for_continue_wait_time.  */
-  struct timeval prompt_started, prompt_ended, prompt_delta;
   struct cleanup *old_chain;
 
   /* Set up according to which answer is the default.  */
@@ -1261,8 +1256,10 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
                      annotation_level > 1 ? "\n\032\032query\n" : "");
   make_cleanup (xfree, prompt);
 
-  /* Used for calculating time spend waiting for user.  */
-  gettimeofday (&prompt_started, NULL);
+  /* Used to add duration we waited for user to respond to
+     prompt_for_continue_wait_time.  */
+  using namespace std::chrono;
+  steady_clock::time_point prompt_started = steady_clock::now ();
 
   prepare_to_handle_input ();
 
@@ -1307,10 +1304,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
     }
 
   /* Add time spend in this routine to prompt_for_continue_wait_time.  */
-  gettimeofday (&prompt_ended, NULL);
-  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
-  timeval_add (&prompt_for_continue_wait_time,
-               &prompt_for_continue_wait_time, &prompt_delta);
+  prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
     printf_filtered (("\n\032\032post-query\n"));
@@ -1816,12 +1810,11 @@ prompt_for_continue (void)
 {
   char *ignore;
   char cont_prompt[120];
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   /* Used to add duration we waited for user to respond to
      prompt_for_continue_wait_time.  */
-  struct timeval prompt_started, prompt_ended, prompt_delta;
-  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
-
-  gettimeofday (&prompt_started, NULL);
+  using namespace std::chrono;
+  steady_clock::time_point prompt_started = steady_clock::now ();
 
   if (annotation_level > 1)
     printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));
@@ -1844,10 +1837,7 @@ prompt_for_continue (void)
   make_cleanup (xfree, ignore);
 
   /* Add time spend in this routine to prompt_for_continue_wait_time.  */
-  gettimeofday (&prompt_ended, NULL);
-  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
-  timeval_add (&prompt_for_continue_wait_time,
-               &prompt_for_continue_wait_time, &prompt_delta);
+  prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
     printf_unfiltered (("\n\032\032post-prompt-for-continue\n"));
@@ -1877,15 +1867,15 @@ prompt_for_continue (void)
 void
 reset_prompt_for_continue_wait_time (void)
 {
-  static const struct timeval zero_timeval = { 0 };
+  using namespace std::chrono;
 
-  prompt_for_continue_wait_time = zero_timeval;
+  prompt_for_continue_wait_time = steady_clock::duration::zero ();
 }
 
 /* Fetch the cumulative time spent in prompt_for_continue.  */
 
-struct timeval
-get_prompt_for_continue_wait_time (void)
+std::chrono::steady_clock::duration
+get_prompt_for_continue_wait_time ()
 {
   return prompt_for_continue_wait_time;
 }
@@ -2308,21 +2298,21 @@ vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
   old_cleanups = make_cleanup (xfree, linebuffer);
   if (debug_timestamp && stream == gdb_stdlog)
     {
-      struct timeval tm;
-      char *timestamp;
+      using namespace std::chrono;
       int len, need_nl;
 
-      gettimeofday (&tm, NULL);
+      steady_clock::time_point now = steady_clock::now ();
+      seconds s = duration_cast<seconds> (now.time_since_epoch ());
+      microseconds us = duration_cast<microseconds> (now.time_since_epoch () - s);
 
       len = strlen (linebuffer);
       need_nl = (len > 0 && linebuffer[len - 1] != '\n');
 
-      timestamp = xstrprintf ("%ld:%ld %s%s",
-                             (long) tm.tv_sec, (long) tm.tv_usec,
-                             linebuffer,
-                             need_nl ? "\n": "");
-      make_cleanup (xfree, timestamp);
-      fputs_unfiltered (timestamp, stream);
+      std::string timestamp = string_printf ("%ld.%06ld %s%s",
+                                            (long) s.count (),
+                                            (long) us.count (),
+                                            linebuffer, need_nl ? "\n": "");
+      fputs_unfiltered (timestamp.c_str (), stream);
     }
   else
     fputs_unfiltered (linebuffer, stream);
index 36f5294abd11cf948f1bfb9ef18463f67f4d76d4..62091f078945c4e2b3e1f576c70c6d63cad411dc 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "exceptions.h"
 #include "common/scoped_restore.h"
+#include <chrono>
 
 extern void initialize_utils (void);
 
@@ -51,7 +52,7 @@ extern const char *gdb_bfd_errmsg (bfd_error_type error_tag, char **matching);
 /* Reset the prompt_for_continue clock.  */
 void reset_prompt_for_continue_wait_time (void);
 /* Return the time spent in prompt_for_continue.  */
-struct timeval get_prompt_for_continue_wait_time (void);
+std::chrono::steady_clock::duration get_prompt_for_continue_wait_time ();
 \f
 /* Parsing utilites.  */