From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 45897 invoked by alias); 17 Nov 2016 17:15:43 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 45822 invoked by uid 89); 17 Nov 2016 17:15:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.8 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=500000, WHEN, occasion, lasted X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 17 Nov 2016 17:15:31 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3F6E3C0528A6 for ; Thu, 17 Nov 2016 17:15:30 +0000 (UTC) Received: from localhost.localdomain (ovpn03.gateway.prod.ext.phx2.redhat.com [10.5.9.3]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uAHHFSHx028160 for ; Thu, 17 Nov 2016 12:15:29 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH] gdb: Use C++11 std::chrono Date: Thu, 17 Nov 2016 17:15:00 -0000 Message-Id: <1479402927-4639-1-git-send-email-palves@redhat.com> X-SW-Source: 2016-11/txt/msg00488.txt.bz2 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. std::chrono is a brilliant API IMO, designed to catch problems at compile time, and to offload factor conversions (minutes <-> seconds <-> microseconds, etc.) to the library, often at compile time. It also supports the obvious <,>,-,+ operators, making code comparing timestamps or computing time ranges more natural. I.e., libiberty's timeval_add/timeval_sub are just +/- with std::chrono. Checking whether a timer has elapsed is just using a natural "when > now" check. Another nice thing with std::chrono is that it's super easy to create extra clocks that follow the same interface, and leverage all the std::chrono::duration/ratio niceties. The patch adds a couple to count user/system CPU time. See the new cpu_time_clock.h|c files. The fact that the API is strongly typed and catches problems with mismatching clocks/time_point at compile time is very nice. It's not visible in the resulting patch, of course, but that helped write it. [The best intro I know of to std::chrono is the proposal for the standard itself: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm I highly recommend reading that, all the way up to the "threads" chapter, at least. Should make understanding this patch much easier.] gdb/ChangeLog: * Makefile.in (SFILES): Add common/cpu-time-clock.c. (HFILES_NO_SRCDIR): Add common/cpu-time-clock.h. (COMMON_OBS): Add cpu-time-clock.o. (cpu-time-clock.o): New rule. * common/cpu-time-clock.c, common/cpu-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. gdb/gdbserver/ChangeLog: * debug.c: Include instead of "gdb_sys_time.h". (debug_vprintf): Use std::chrono::steady_clock instead of gettimeofday. * tracepoint.c: Include instead of "gdb_sys_time.h". (get_timestamp): 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 "cpu-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 "cpu-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 "cpu-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 time_range 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. * utils.h: Include . (get_prompt_for_continue_wait_time): Return a std::chrono::steady_clock::duration instead of struct timeval. --- gdb/Makefile.in | 9 ++++- gdb/common/cpu-time-clock.c | 48 +++++++++++++++++++++++ gdb/common/cpu-time-clock.h | 52 +++++++++++++++++++++++++ gdb/defs.h | 14 ------- gdb/event-loop.c | 94 +++++++++++++++++++++------------------------ gdb/gdbserver/debug.c | 13 +++---- gdb/gdbserver/tracepoint.c | 10 ++--- gdb/maint.c | 31 +++++++-------- gdb/maint.h | 7 +++- gdb/mi/mi-main.c | 75 ++++++++++-------------------------- gdb/mi/mi-parse.h | 12 +++--- gdb/symfile.c | 47 +++++++++++++++-------- gdb/utils.c | 57 +++++++++++---------------- gdb/utils.h | 3 +- 14 files changed, 262 insertions(+), 210 deletions(-) create mode 100644 gdb/common/cpu-time-clock.c create mode 100644 gdb/common/cpu-time-clock.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index c473472..e3e5ba8 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -895,6 +895,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ common/errors.c common/common-debug.c common/common-exceptions.c \ common/btrace-common.c common/fileio.c common/common-regcache.c \ common/signals-state-save-restore.c common/new-op.c \ + common/cpu-time-clock.c \ $(SUBDIR_GCC_COMPILE_SRCS) LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c @@ -988,7 +989,7 @@ common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \ common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\ nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \ tid-parse.h ser-event.h \ -common/signals-state-save-restore.h +common/signals-state-save-restore.h common/cpu-time-clock.h # Header files that already have srcdir in them, or which are in objdir. @@ -1088,7 +1089,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ format.o registry.o btrace.o record-btrace.o waitstatus.o \ print-utils.o rsp-low.o errors.o common-debug.o debug.o \ common-exceptions.o btrace-common.o fileio.o \ - common-regcache.o new-op.o \ + common-regcache.o new-op.o cpu-time-clock.o \ $(SUBDIR_GCC_COMPILE_OBS) TSOBS = inflow.o @@ -2298,6 +2299,10 @@ new-op.o: ${srcdir}/common/new-op.c $(COMPILE) $(srcdir)/common/new-op.c $(POSTCOMPILE) +cpu-time-clock.o: ${srcdir}/common/cpu-time-clock.c + $(COMPILE) $(srcdir)/common/cpu-time-clock.c + $(POSTCOMPILE) + # # gdb/target/ dependencies # diff --git a/gdb/common/cpu-time-clock.c b/gdb/common/cpu-time-clock.c new file mode 100644 index 0000000..3c69532 --- /dev/null +++ b/gdb/common/cpu-time-clock.c @@ -0,0 +1,48 @@ +/* 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 "cpu-time-clock.h" +#if defined HAVE_SYS_RESOURCE_H +#include +#endif + +using namespace std::chrono; + +/* Count the total amount of time spent executing in user mode. */ + +user_cpu_time_clock::time_point +user_cpu_time_clock::now () noexcept +{ + return time_point (microseconds (get_run_time ())); +} + +/* Count the total amount of time spent executing in kernel mode. */ + +system_cpu_time_clock::time_point +system_cpu_time_clock::now () noexcept +{ +#ifdef HAVE_GETRUSAGE + struct rusage rusage; + getrusage (RUSAGE_SELF, &rusage); + return time_point (seconds (rusage.ru_stime.tv_sec) + + microseconds (rusage.ru_stime.tv_usec)); +#else + return time_point (duration::zero ()); +#endif +} diff --git a/gdb/common/cpu-time-clock.h b/gdb/common/cpu-time-clock.h new file mode 100644 index 0000000..f982769 --- /dev/null +++ b/gdb/common/cpu-time-clock.h @@ -0,0 +1,52 @@ +/* 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 CPU_TIME_CLOCK_H +#define CPU_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; + + static time_point now () noexcept; +}; + +/* 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; + + static time_point now () noexcept; +}; + +#endif diff --git a/gdb/defs.h b/gdb/defs.h index 6d0d2dd..3d21f62 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 f94a6fa..9e8cf66 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/debug.c b/gdb/gdbserver/debug.c index 54f2665..dd987ed 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. */ @@ -41,14 +41,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 ", s.count (), us.count ()); } #endif diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 7700ad1..1444a0d 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 738571c..2a8f067 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); + user_cpu_time_clock::duration cmd_time + = user_cpu_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 = user_cpu_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 8d03800..68132ae 100644 --- a/gdb/maint.h +++ b/gdb/maint.h @@ -19,6 +19,9 @@ #ifndef MAINT_H #define MAINT_H +#include "cpu-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; + user_cpu_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 984a415..d1ce78c 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 "cpu-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,18 +2409,9 @@ 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; - } + microseconds update_threshold (500000); + steady_clock::time_point time_now = steady_clock::now (); + steady_clock::duration delta = time_now - last_update; new_section = (previous_sect_name ? strcmp (previous_sect_name, section_name) : 1); @@ -2451,13 +2435,11 @@ 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) + if (delta > update_threshold) { 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 +2462,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 (); - - 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 + using namespace std::chrono; + tv->wallclock = steady_clock::now (); + tv->utime = user_cpu_time_clock::now (); + tv->stime = system_cpu_time_clock::now (); } static void @@ -2517,23 +2486,19 @@ 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..ac3c654 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 "cpu-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 f524f56..6e791d5 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,23 @@ clear_memory_write_data (void *arg) VEC_free (memory_write_request_s, vec); } +/* A time range. */ + +struct time_range +{ + std::chrono::steady_clock::time_point start; + std::chrono::steady_clock::time_point end; +}; + +static void print_transfer_performance (struct ui_file *stream, + unsigned long data_count, + unsigned long write_count, + const time_range &time); + 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 +2142,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 +2173,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); + {start_time, end_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 the range of time in + which 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) + const time_range &time) { - ULONGEST time_count; 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; + using namespace std::chrono; + milliseconds ms = duration_cast (time.end - time.start); 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 751f099..73c07ec 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,20 @@ 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:%ld %s%s", + s.count (), 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 36f5294..62091f0 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.5.5