diff options
author | Doug Evans <dje@google.com> | 2013-03-21 17:37:30 +0000 |
---|---|---|
committer | Doug Evans <dje@google.com> | 2013-03-21 17:37:30 +0000 |
commit | bd712aed2f88ab824d403c55a212c2be3f41a335 (patch) | |
tree | 490fa4cc174545d0a4962ef985b39c00ffad42e3 /gdb/maint.c | |
parent | d76488d84eb95326e157d8deca0f626914036667 (diff) | |
download | gdb-bd712aed2f88ab824d403c55a212c2be3f41a335.zip gdb-bd712aed2f88ab824d403c55a212c2be3f41a335.tar.gz gdb-bd712aed2f88ab824d403c55a212c2be3f41a335.tar.bz2 |
New commands "mt set per-command {space,time,symtab} {on,off}".
* NEWS: Add entry.
* event-top.c: #include "maint.h".
* main.c: #include "maint.h".
* maint.c: #include <sys/time.h>, <time.h>, block.h, top.h,
timeval-utils.h, maint.h, cli/cli-setshow.h.
(per_command_time, per_command_space): New static globals.
(per_command_symtab): New static global.
(per_command_setlist, per_command_showlist): New static globals.
(struct cmd_stats): Move here from utils.c.
(set_per_command_time): Renamed from set_display_time in utils.c
and moved here. All callers updated.
(set_per_command_space): Renamed from set_display_space in utils.c
and moved here. All callers updated.
(count_symtabs_and_blocks): New function.
(report_command_stats): Moved here from utils.c. Add support for
printing symtab stats. Only print data if enabled before command
executed.
(make_command_stats_cleanup): Ditto.
(sert_per_command_cmd, show_per_command_cmd): New functions.
(_initialize_maint_cmds): Add new commands
mt set per-command {space,time,symtab} {on,off}.
* maint.h: New file.
* top.c: #include "maint.h".
* utils.c (reset_prompt_for_continue_wait_time): New function.
(get_prompt_for_continue_wait_time): New function.
* utils.h (reset_prompt_for_continue_wait_time): Declare
(get_prompt_for_continue_wait_time): Declare.
(make_command_stats_cleanup): Moved to maint.h.
(set_display_time, set_display_space): Moved to maint.h and renamed
to set_per_command_time, set_per_command_space.
* cli/cli-setshow.c (parse_cli_boolean_value): Renamed from
parse_binary_operation and made non-static. Don't call error,
just return an error marker. All callers updated.
* cli/cli-setshow.h (parse_cli_boolean_value): Declare.
doc/
* gdb.texinfo (Maintenance Commands): Add docs for
"mt set per-command {space,time,symtab} {on,off}".
testsuite/
* gdb.base/maint.exp: Update tests for per-command stats.
Diffstat (limited to 'gdb/maint.c')
-rw-r--r-- | gdb/maint.c | 291 |
1 files changed, 289 insertions, 2 deletions
diff --git a/gdb/maint.c b/gdb/maint.c index b835db6..db3e63d 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -24,9 +24,12 @@ #include "arch-utils.h" #include <ctype.h> #include <signal.h> +#include <sys/time.h> +#include <time.h> #include "command.h" #include "gdbcmd.h" #include "symtab.h" +#include "block.h" #include "gdbtypes.h" #include "demangle.h" #include "gdbcore.h" @@ -36,9 +39,13 @@ #include "objfiles.h" #include "value.h" #include "gdb_assert.h" +#include "top.h" +#include "timeval-utils.h" +#include "maint.h" #include "cli/cli-decode.h" #include "cli/cli-utils.h" +#include "cli/cli-setshow.h" extern void _initialize_maint_cmds (void); @@ -164,7 +171,7 @@ maintenance_time_display (char *args, int from_tty) if (args == NULL || *args == '\0') printf_unfiltered (_("\"maintenance time\" takes a numeric argument.\n")); else - set_display_time (strtol (args, NULL, 10)); + set_per_command_time (strtol (args, NULL, 10)); } static void @@ -173,7 +180,7 @@ maintenance_space_display (char *args, int from_tty) if (args == NULL || *args == '\0') printf_unfiltered ("\"maintenance space\" takes a numeric argument.\n"); else - set_display_space (strtol (args, NULL, 10)); + set_per_command_space (strtol (args, NULL, 10)); } /* The "maintenance info" command is defined as a prefix, with @@ -725,7 +732,243 @@ maintenance_set_profile_cmd (char *args, int from_tty, error (_("Profiling support is not available on this system.")); } #endif + +/* If nonzero, display time usage both at startup and for each command. */ +static int per_command_time; + +/* If nonzero, display space usage both at startup and for each command. */ + +static int per_command_space; + +/* If nonzero, display basic symtab stats for each command. */ + +static int per_command_symtab; + +/* mt per-command commands. */ + +static struct cmd_list_element *per_command_setlist; +static struct cmd_list_element *per_command_showlist; + +/* Records a run time and space usage to be used as a base for + reporting elapsed time or change in space. */ + +struct cmd_stats +{ + /* Zero if the saved time is from the beginning of GDB execution. + One if from the beginning of an individual command execution. */ + int msg_type; + /* Track whether the stat was enabled at the start of the command + so that we can avoid printing anything if it gets turned on by + the current command. */ + int time_enabled : 1; + int space_enabled : 1; + int symtab_enabled : 1; + long start_cpu_time; + struct timeval start_wall_time; + long start_space; + /* Total number of symtabs (over all objfiles). */ + int start_nr_symtabs; + /* Of those, a count of just the primary ones. */ + int start_nr_primary_symtabs; + /* Total number of blocks. */ + int start_nr_blocks; +}; + +/* Set whether to display time statistics to NEW_VALUE + (non-zero means true). */ + +void +set_per_command_time (int new_value) +{ + per_command_time = new_value; +} + +/* Set whether to display space statistics to NEW_VALUE + (non-zero means true). */ + +void +set_per_command_space (int new_value) +{ + per_command_space = new_value; +} + +/* Count the number of symtabs and blocks. */ + +static void +count_symtabs_and_blocks (int *nr_symtabs_ptr, int *nr_primary_symtabs_ptr, + int *nr_blocks_ptr) +{ + struct objfile *o; + struct symtab *s; + int nr_symtabs = 0; + int nr_primary_symtabs = 0; + int nr_blocks = 0; + + ALL_SYMTABS (o, s) + { + ++nr_symtabs; + if (s->primary) + { + ++nr_primary_symtabs; + nr_blocks += BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); + } + } + + *nr_symtabs_ptr = nr_symtabs; + *nr_primary_symtabs_ptr = nr_primary_symtabs; + *nr_blocks_ptr = nr_blocks; +} + +/* As indicated by display_time and display_space, report GDB's elapsed time + and space usage from the base time and space provided in ARG, which + must be a pointer to a struct cmd_stat. This function is intended + to be called as a cleanup. */ + +static void +report_command_stats (void *arg) +{ + struct cmd_stats *start_stats = (struct cmd_stats *) arg; + int msg_type = start_stats->msg_type; + + if (start_stats->time_enabled) + { + long cmd_time = get_run_time () - start_stats->start_cpu_time; + struct timeval now_wall_time, delta_wall_time, wait_time; + + gettimeofday (&now_wall_time, NULL); + timeval_sub (&delta_wall_time, + &now_wall_time, &start_stats->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); + + printf_unfiltered (msg_type == 0 + ? _("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); + } + + if (start_stats->space_enabled) + { +#ifdef HAVE_SBRK + char *lim = (char *) sbrk (0); + + long space_now = lim - lim_at_start; + long space_diff = space_now - start_stats->start_space; + + printf_unfiltered (msg_type == 0 + ? _("Space used: %ld (%s%ld during startup)\n") + : _("Space used: %ld (%s%ld for this command)\n"), + space_now, + (space_diff >= 0 ? "+" : ""), + space_diff); +#endif + } + + if (start_stats->symtab_enabled) + { + int nr_symtabs, nr_primary_symtabs, nr_blocks; + + count_symtabs_and_blocks (&nr_symtabs, &nr_primary_symtabs, &nr_blocks); + printf_unfiltered (_("#symtabs: %d (+%d)," + " #primary symtabs: %d (+%d)," + " #blocks: %d (+%d)\n"), + nr_symtabs, + nr_symtabs - start_stats->start_nr_symtabs, + nr_primary_symtabs, + nr_primary_symtabs - start_stats->start_nr_primary_symtabs, + nr_blocks, + nr_blocks - start_stats->start_nr_blocks); + } +} + +/* Create a cleanup that reports time and space used since its creation. + MSG_TYPE is zero for gdb startup, otherwise it is one(1) to report + data for individual commands. */ + +struct cleanup * +make_command_stats_cleanup (int msg_type) +{ + struct cmd_stats *new_stat; + + /* Early exit if we're not reporting any stats. */ + if (!per_command_time + && !per_command_space + && !per_command_symtab) + return make_cleanup (null_cleanup, 0); + + new_stat = XZALLOC (struct cmd_stats); + + new_stat->msg_type = msg_type; + + if (per_command_space) + { +#ifdef HAVE_SBRK + char *lim = (char *) sbrk (0); + new_stat->start_space = lim - lim_at_start; + new_stat->space_enabled = 1; +#endif + } + + if (per_command_time) + { + new_stat->start_cpu_time = get_run_time (); + gettimeofday (&new_stat->start_wall_time, NULL); + new_stat->time_enabled = 1; + } + + if (per_command_symtab) + { + int nr_symtabs, nr_primary_symtabs, nr_blocks; + + count_symtabs_and_blocks (&nr_symtabs, &nr_primary_symtabs, &nr_blocks); + new_stat->start_nr_symtabs = nr_symtabs; + new_stat->start_nr_primary_symtabs = nr_primary_symtabs; + new_stat->start_nr_blocks = nr_blocks; + new_stat->symtab_enabled = 1; + } + + /* Initalize timer to keep track of how long we waited for the user. */ + reset_prompt_for_continue_wait_time (); + + return make_cleanup_dtor (report_command_stats, new_stat, xfree); +} + +/* Handle unknown "mt set per-command" arguments. + In this case have "mt set per-command on|off" affect every setting. */ + +static void +set_per_command_cmd (char *args, int from_tty) +{ + struct cmd_list_element *list; + size_t length; + int val; + + val = parse_cli_boolean_value (args); + if (val < 0) + error (_("Bad value for 'mt set per-command no'.")); + + for (list = per_command_setlist; list != NULL; list = list->next) + if (list->var_type == var_boolean) + { + gdb_assert (list->type == set_cmd); + do_set_command (args, from_tty, list); + } +} + +/* Command "show per-command" displays summary of all the current + "show per-command " settings. */ + +static void +show_per_command_cmd (char *args, int from_tty) +{ + cmd_show_list (per_command_showlist, from_tty, ""); +} + void _initialize_maint_cmds (void) { @@ -802,12 +1045,56 @@ Call internal GDB demangler routine to demangle a C++ link name\n\ and prints the result."), &maintenancelist); + add_prefix_cmd ("per-command", class_maintenance, set_per_command_cmd, _("\ +Per-command statistics settings."), + &per_command_setlist, "set per-command ", + 1/*allow-unknown*/, &maintenance_set_cmdlist); + + add_prefix_cmd ("per-command", class_maintenance, show_per_command_cmd, _("\ +Show per-command statistics settings."), + &per_command_showlist, "show per-command ", + 0/*allow-unknown*/, &maintenance_show_cmdlist); + + add_setshow_boolean_cmd ("time", class_maintenance, + &per_command_time, _("\ +Set whether to display per-command execution time."), _("\ +Show whether to display per-command execution time."), + _("\ +If enabled, the execution time for each command will be\n\ +displayed following the command's output."), + NULL, NULL, + &per_command_setlist, &per_command_showlist); + + add_setshow_boolean_cmd ("space", class_maintenance, + &per_command_space, _("\ +Set whether to display per-command space usage."), _("\ +Show whether to display per-command space usage."), + _("\ +If enabled, the space usage for each command will be\n\ +displayed following the command's output."), + NULL, NULL, + &per_command_setlist, &per_command_showlist); + + add_setshow_boolean_cmd ("symtab", class_maintenance, + &per_command_symtab, _("\ +Set whether to display per-command symtab statistics."), _("\ +Show whether to display per-command symtab statistics."), + _("\ +If enabled, the basic symtab statistics for each command will be\n\ +displayed following the command's output."), + NULL, NULL, + &per_command_setlist, &per_command_showlist); + + /* This is equivalent to "mt set per-command time on". + Kept because some people are used to typing "mt time 1". */ add_cmd ("time", class_maintenance, maintenance_time_display, _("\ Set the display of time usage.\n\ If nonzero, will cause the execution time for each command to be\n\ displayed, following the command's output."), &maintenancelist); + /* This is equivalent to "mt set per-command space on". + Kept because some people are used to typing "mt space 1". */ add_cmd ("space", class_maintenance, maintenance_space_display, _("\ Set the display of space usage.\n\ If nonzero, will cause the execution space for each command to be\n\ |