From dcb07cfa156a8e9f768c7f2b5d32f27b6dfe939f Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 23 Nov 2016 15:36:26 +0000 Subject: 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/symfile.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'gdb/symfile.c') 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)) { -- cgit v1.2.1