diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-08-27 14:23:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-09-03 13:23:50 +0300 |
commit | 581c71dd40074cc6985cdc8cc9ffe006a4411d0a (patch) | |
tree | 4c649ba77324b3ce6725d8457b4a7fc9c4dfc4b3 | |
parent | 9db7e9c3d8a9d6ef9e6d6a8edd9d4dcf9640b42e (diff) | |
download | gdbm-581c71dd40074cc6985cdc8cc9ffe006a4411d0a.tar.gz gdbm-581c71dd40074cc6985cdc8cc9ffe006a4411d0a.tar.bz2 |
gdbmtool: new command "perror"; new options -t, -T; improve timing output
* doc/gdbm.texi: Document the perror command.
* src/gdbmshell.c: New command: perror.
(run_command): In timing mode, print also user and system CPU times.
Print traces on stderr.
* src/gdbmtool.c: New options: -t (--trace) and -T (--timing).
-rw-r--r-- | doc/gdbm.texi | 52 | ||||
-rw-r--r-- | src/gdbmshell.c | 112 | ||||
-rw-r--r-- | src/gdbmtool.c | 12 |
3 files changed, 162 insertions, 14 deletions
diff --git a/doc/gdbm.texi b/doc/gdbm.texi index ee24b48..9a5b676 100644 --- a/doc/gdbm.texi +++ b/doc/gdbm.texi @@ -3015,6 +3015,16 @@ Disable file locking. @itemx --no-mmap Disable memory mapping. +@item -T +@itemx --timing +Print time spent in each command. This is equivalent to setting the +@code{timing} variable. @xref{variables, timing}. + +@item -t +@itemx --trace +Enable command tracing. This is equivalent to setting the +@code{trace} variable. @xref{variables, trace}. + @anchor{-q option} @item -q @itemx --quiet @@ -3192,6 +3202,28 @@ lines of a multi-line command. The default value is @samp{%_>%_}. @end deftypevr +@deftypevr {gdbmtool variable} bool timing +When each command terminates, print an additional line listing times +spent in that command. The line is formatted as follows: + +@example +[reorganize r=0.070481 u=0.000200 s=0.000033] +@end example + +@noindent +Here, @samp{reorganize} is the name of the command that finished, the +number after @samp{r=} is real time spent executing the command, the +number after @samp{u=} is the user CPU time used and the number after +@samp{s=} is the system CPU time used. +@end deftypevr + +@deftypevr {gdbmtool variable} bool trace +Enable command tracing. This is similar to the shell @option{-t} +option: before executing each command, @command{gdbmtool} will print +on standard error a line starting with a plus sign and followed by the +command name and its arguments. +@end deftypevr + @anchor{quiet} @deftypevr {gdbmtool variable} bool quiet Whether to display a welcome banner at startup. To affect @@ -3565,6 +3597,26 @@ Synchronize after each write. Default is @code{off}. @xref{open parameters}, for a detailed description of these variables. @end deffn +@deffn {command verb} perror [@var{code}] +Describe the given GDBM error code. + +The descripion occupies one or two lines. The second line is present +if the system error number should be checked when handling this code. +In this case, the second line states @samp{Examine errno}. + +If @var{code} is omitted, the latest error that occurred in the +current database is described. Second line of the output (if +present), contains description of the latest system error. + +Example: + +@example +gdbmtool> perror 3 +GDBM error code 3: "File open error" +Examine errno. +@end example +@end deffn + @deffn {command verb} quit Close the database and quit the utility. @end deffn diff --git a/src/gdbmshell.c b/src/gdbmshell.c index d7aa9f1..32c9142 100644 --- a/src/gdbmshell.c +++ b/src/gdbmshell.c @@ -25,6 +25,7 @@ #include <sys/ioctl.h> #include <sys/wait.h> #include <sys/time.h> +#include <sys/resource.h> #include <termios.h> #include <stdarg.h> #ifdef HAVE_LOCALE_H @@ -1591,6 +1592,37 @@ source_handler (struct command_param *param, return 0; } +static int +perror_handler (struct command_param *param, struct command_environ *cenv) +{ + int n; + + if (param->argc) + { + if (getnum (&n, PARAM_STRING (param, 0), NULL)) + return 1; + } + else if (checkdb ()) + { + return 1; + } + else + { + n = gdbm_last_errno (gdbm_file); + } + fprintf (cenv->fp, "GDBM error code %d: \"%s\"\n", n, gdbm_strerror (n)); + if (gdbm_check_syserr (n)) + { + if (param->argc) + fprintf (cenv->fp, "Examine errno.\n"); + else + fprintf (cenv->fp, "System error code %d: \"%s\"\n", + gdbm_last_syserr (gdbm_file), + strerror (gdbm_last_syserr (gdbm_file))); + } + return 0; +} + struct history_param { int from; @@ -1934,7 +1966,14 @@ static struct command command_tab[] = { { { NULL } }, TRUE, REPEAT_NEVER, - N_("invoke the shell") }, + N_("invoke the shell") }, + { S(perror), T_CMD, + NULL, perror_handler, NULL, + { { "[CODE]", GDBM_ARG_STRING }, + { NULL } }, + TRUE, + REPEAT_NEVER, + N_("describe GDBM error code") }, #undef S { NULL } }; @@ -2426,10 +2465,6 @@ run_last_command (void) return 0; } -#define DIFFTIME(now,then)\ - (((now).tv_sec - (then).tv_sec) \ - + ((double)((now).tv_usec - (then).tv_usec))/1000000) - static void format_arg (struct gdbmarg *arg, struct argdef *def, FILE *fp) { @@ -2472,6 +2507,52 @@ format_arg (struct gdbmarg *arg, struct argdef *def, FILE *fp) } } } + +struct timing +{ + struct timeval real; + struct timeval user; + struct timeval sys; +}; + +void +timing_start (struct timing *t) +{ + struct rusage r; + gettimeofday (&t->real, NULL); + getrusage (RUSAGE_SELF, &r); + t->user = r.ru_utime; + t->sys = r.ru_stime; +} + +static inline struct timeval +timeval_sub (struct timeval a, struct timeval b) +{ + struct timeval diff; + + diff.tv_sec = a.tv_sec - b.tv_sec; + diff.tv_usec = a.tv_usec - b.tv_usec; + if (diff.tv_usec < 0) + { + --diff.tv_sec; + diff.tv_usec += 1000000; + } + + return diff; +} + +void +timing_stop (struct timing *t) +{ + struct rusage r; + struct timeval now; + + gettimeofday (&now, NULL); + getrusage (RUSAGE_SELF, &r); + t->real = timeval_sub (now, t->real); + t->user = timeval_sub (r.ru_utime, t->user); + t->sys = timeval_sub (r.ru_stime, t->sys); +} int run_command (struct command *cmd, struct gdbmarglist *arglist) @@ -2485,7 +2566,7 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) struct command_param param = HANDLER_PARAM_INITIALIZER; struct command_environ cenv = COMMAND_ENVIRON_INITIALIZER; int rc = 0; - struct timeval start, stop; + struct timing tm; variable_get ("pager", VART_STRING, (void**) &pager); @@ -2548,19 +2629,19 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) if (variable_is_true ("trace")) { - fprintf (stdout, "+ %s", cmd->name); + fprintf (stderr, "+ %s", cmd->name); for (i = 0; i < param.argc; i++) { - format_arg (param.argv[i], &cmd->args[i], stdout); + format_arg (param.argv[i], &cmd->args[i], stderr); } if (param.vararg) { struct gdbmarg *arg; for (arg = param.vararg; arg; arg = arg->next) - format_arg (arg, NULL, stdout); + format_arg (arg, NULL, stderr); } - fputc ('\n', stdout); + fputc ('\n', stderr); } expected_lines = 0; @@ -2584,9 +2665,9 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) else cenv.fp = stdout; - gettimeofday (&start, NULL); + timing_start (&tm); rc = cmd->handler (¶m, &cenv); - gettimeofday (&stop, NULL); + timing_stop (&tm); if (cmd->end) cmd->end (cenv.data); else if (cenv.data) @@ -2594,8 +2675,11 @@ run_command (struct command *cmd, struct gdbmarglist *arglist) if (variable_is_true ("timing")) { - double t = DIFFTIME (stop, start); - fprintf (cenv.fp, "[%s t=%0.9f]\n", cmd->name, t); + fprintf (cenv.fp, "[%s r=%lu.%06lu u=%lu.%06lu s=%lu.%06lu]\n", + cmd->name, + tm.real.tv_sec, tm.real.tv_usec, + tm.user.tv_sec, tm.user.tv_usec, + tm.sys.tv_sec, tm.sys.tv_usec); } if (pagfp) diff --git a/src/gdbmtool.c b/src/gdbmtool.c index e8ca9aa..512dd88 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -105,6 +105,8 @@ struct gdbm_option optab[] = { N_("open database at the given file descriptor") }, { 'x', "extended", NULL, N_("extended format (numsync)") }, { 0, "numsync", NULL, NULL, PARSEOPT_ALIAS }, + { 't', "trace", NULL, N_("enable trace mode") }, + { 'T', "timing", NULL, N_("print timing after each command") }, #if GDBMTOOL_DEBUG { OPT_LEX_TRACE, "lex-trace", NULL, N_("enable lexical analyzer traces") }, { OPT_GRAM_TRACE, "gram-trace", NULL, N_("enable grammar traces") }, @@ -192,6 +194,16 @@ gdbmtool_init (void *data, instream_t *pinstr) variable_set ("filename", VART_STRING, optarg); break; + case 't': + bv = 1; + variable_set ("trace", VART_BOOL, &bv); + break; + + case 'T': + bv = 1; + variable_set ("timing", VART_BOOL, &bv); + break; + case 'q': bv = 1; variable_set ("quiet", VART_BOOL, &bv); |