aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-08-27 14:23:08 +0300
committerSergey Poznyakoff <gray@gnu.org>2021-09-03 13:23:50 +0300
commit581c71dd40074cc6985cdc8cc9ffe006a4411d0a (patch)
tree4c649ba77324b3ce6725d8457b4a7fc9c4dfc4b3
parent9db7e9c3d8a9d6ef9e6d6a8edd9d4dcf9640b42e (diff)
downloadgdbm-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.texi52
-rw-r--r--src/gdbmshell.c112
-rw-r--r--src/gdbmtool.c12
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 (&param, &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);

Return to:

Send suggestions and report system problems to the System administrator.