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/mi/mi-main.c | 73 ++++++++++++++----------------------------------------- gdb/mi/mi-parse.h | 12 +++++---- 2 files changed, 25 insertions(+), 60 deletions(-) (limited to 'gdb/mi') diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 984a415..4d276c8 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 d5595b3..dc8d21b 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 -- cgit v1.1