From dcb07cfa156a8e9f768c7f2b5d32f27b6dfe939f Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 23 Nov 2016 15:36:26 +0000 Subject: [PATCH] gdb: Use C++11 std::chrono 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 * 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) : 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 instead of "gdb_sys_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 . (scoped_command_stats): : Now a user_cpu_time_clock::time_point. : Now a std::chrono::steady_clock::time_point. * mi/mi-main.c: Include "run-time-clock.h" and instead of "gdb_sys_time.h" and . (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 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 instead of 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 instead of "timeval-utils.h", "gdb_sys_time.h", and . (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 . (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 * debug.c: Include instead of "gdb_sys_time.h". (debug_vprintf): Use std::chrono::steady_clock instead of gettimeofday. Use '.' instead of ':'. * tracepoint.c: Include instead of "gdb_sys_time.h". (get_timestamp): Use std::chrono::steady_clock instead of gettimeofday. --- gdb/ChangeLog | 66 ++++++++++++++++++++++++++ gdb/Makefile.in | 3 ++ gdb/common/run-time-clock.c | 58 +++++++++++++++++++++++ gdb/common/run-time-clock.h | 75 +++++++++++++++++++++++++++++ gdb/defs.h | 14 ------ gdb/event-loop.c | 94 +++++++++++++++++-------------------- gdb/gdbserver/ChangeLog | 9 ++++ gdb/gdbserver/debug.c | 16 +++---- gdb/gdbserver/tracepoint.c | 10 ++-- gdb/maint.c | 31 ++++++------ gdb/maint.h | 7 ++- gdb/mi/mi-main.c | 73 +++++++--------------------- gdb/mi/mi-parse.h | 12 +++-- gdb/symfile.c | 39 ++++++++------- gdb/utils.c | 58 ++++++++++------------- gdb/utils.h | 3 +- 16 files changed, 358 insertions(+), 210 deletions(-) create mode 100644 gdb/common/run-time-clock.c create mode 100644 gdb/common/run-time-clock.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a9a82491f74..a2a11e2461b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,69 @@ +2016-11-23 Pedro Alves + + * 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) : 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 instead of "gdb_sys_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 . + (scoped_command_stats): : Now a + user_cpu_time_clock::time_point. + : Now a std::chrono::steady_clock::time_point. + * mi/mi-main.c: Include "run-time-clock.h" and instead of + "gdb_sys_time.h" and . + (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 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 instead of 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 instead of "timeval-utils.h", + "gdb_sys_time.h", and . + (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 . + (get_prompt_for_continue_wait_time): Return a + std::chrono::steady_clock::duration instead of struct timeval. + 2016-11-22 Simon Marchi * Makefile.in: Fix whitespace formatting. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e3e3ce4cba1..44a743ee658 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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 index 00000000000..f9dc7a00605 --- /dev/null +++ b/gdb/common/run-time-clock.c @@ -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 . */ + +#include "common-defs.h" +#include "run-time-clock.h" +#if defined HAVE_SYS_RESOURCE_H +#include +#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 index 00000000000..ee531bb6589 --- /dev/null +++ b/gdb/common/run-time-clock.h @@ -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 . */ + +#ifndef RUN_TIME_CLOCK_H +#define RUN_TIME_CLOCK_H + +#include + +/* 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; + + 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; + + 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; + + 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 diff --git a/gdb/defs.h b/gdb/defs.h index 6d0d2dd433a..3d21f62f52c 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -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); diff --git a/gdb/event-loop.c b/gdb/event-loop.c index f94a6fa135f..9e8cf66c8fd 100644 --- a/gdb/event-loop.c +++ b/gdb/event-loop.c @@ -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 +static struct timeval +duration_cast_timeval (const Duration &d) +{ + using namespace std::chrono; + seconds sec = duration_cast (d); + microseconds msec = duration_cast (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 diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 701e22ed0ce..8b83461668c 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,12 @@ +2016-11-23 Pedro Alves + + * debug.c: Include instead of "gdb_sys_time.h". + (debug_vprintf): Use std::chrono::steady_clock instead of + gettimeofday. Use '.' instead of ':'. + * tracepoint.c: Include instead of "gdb_sys_time.h". + (get_timestamp): Use std::chrono::steady_clock instead of + gettimeofday. + 2016-11-22 Simon Marchi * Makefile.in: Fix whitespace formatting. diff --git a/gdb/gdbserver/debug.c b/gdb/gdbserver/debug.c index 54f2665d929..0e6a3a68505 100644 --- a/gdb/gdbserver/debug.c +++ b/gdb/gdbserver/debug.c @@ -17,7 +17,7 @@ along with this program. If not, see . */ #include "server.h" -#include "gdb_sys_time.h" +#include /* 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 (now.time_since_epoch ()); + microseconds us = duration_cast (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 diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 7700ad121fc..1444a0db31c 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -25,7 +25,7 @@ #include #include #include -#include "gdb_sys_time.h" +#include #include #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 (now.time_since_epoch ()).count (); } void diff --git a/gdb/maint.c b/gdb/maint.c index 738571c73c0..b43dbf9d9d0 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -24,8 +24,6 @@ #include "arch-utils.h" #include #include -#include "gdb_sys_time.h" -#include #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 (cmd_time).count (), + duration (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 diff --git a/gdb/maint.h b/gdb/maint.h index 8d038009945..2af405d57e4 100644 --- a/gdb/maint.h +++ b/gdb/maint.h @@ -19,6 +19,9 @@ #ifndef MAINT_H #define MAINT_H +#include "run-time-clock.h" +#include + 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; diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 984a415a052..4d276c867d1 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -56,15 +56,8 @@ #include "observer.h" #include -#include "gdb_sys_time.h" - -#if defined HAVE_SYS_RESOURCE_H -#include -#endif - -#ifdef HAVE_GETRUSAGE -struct rusage rusage; -#endif +#include "run-time-clock.h" +#include 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 wallclock = end->wallclock - start->wallclock; + duration utime = end->utime - start->utime; + duration 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 diff --git a/gdb/mi/mi-parse.h b/gdb/mi/mi-parse.h index d5595b37e93..dc8d21b5c6b 100644 --- a/gdb/mi/mi-parse.h +++ b/gdb/mi/mi-parse.h @@ -20,15 +20,17 @@ #ifndef MI_PARSE_H #define MI_PARSE_H -#include "gdb_sys_time.h" +#include "run-time-clock.h" +#include /* 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 diff --git a/gdb/symfile.c b/gdb/symfile.c index f524f56b367..517c277c722 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -61,8 +61,7 @@ #include #include #include -#include -#include "gdb_sys_time.h" +#include #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 (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)) { diff --git a/gdb/utils.c b/gdb/utils.c index 751f09949d6..8ca0a2ee779 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -37,7 +37,6 @@ #endif #include -#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 +#include #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 (now.time_since_epoch ()); + microseconds us = duration_cast (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); diff --git a/gdb/utils.h b/gdb/utils.h index 36f5294abd1..62091f07894 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -23,6 +23,7 @@ #include "exceptions.h" #include "common/scoped_restore.h" +#include 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 (); /* Parsing utilites. */ -- 2.30.2