[PATCH] mt set per-command remote-packets on|off

Doug Evans
2013-11-27T22:44:00Z

Hi.

If there are no objections, I plan to check this in.
It adds "mt set per-command packet on|off", and is helpful
in examining remote serial protocol issues.

Tested on amd64-linux.

2013-11-27 Doug Evans <dje@google.com>

* NEWS: Mention new command "mt set per-command remote-packet on|off".
* maint.c: #include "remote.h".
(per_command_packet): New static global.
(struct cmd_stats): New members packet_enabled, start_packets_sent,
start_packets_rcvd, start_packet_bytes_sent, start_packet_bytes_rcvd.
(report_command_stats): Print packet stats if asked.
(make_command_stats_cleanup): Collect packet stats if asked.
(_initialize_maint_cmds): New command "mt set per-command remote-packet
on|off".
* remote.c (struct remote_state): New members packets_sent,
packets_received, bytes_sent, bytes_received.
(get_remote_packet_stats): New function.
(putpkt_binary, getpkt_or_notif_sane_1): Update stats.
* remote.h (get_remote_packet_stats): Declare.

doc/
* gdb.texinfo (Maintenance Commands): Add docs for
"mt set per-command remote-packet {on,off}".

diff --git a/gdb/NEWS b/gdb/NEWS
index 5110b27..d393b4c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -74,6 +74,7 @@ maint set|show per-command
maint set|show per-command space
maint set|show per-command time
maint set|show per-command symtab
+maint set|show per-command remote-packets
Enable display of per-command gdb resource usage.

remove-symbol-file FILENAME
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 004c376..d613da5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -37611,6 +37611,23 @@ number of primary symbol tables
@item
number of blocks in the blockvector
@end enumerate
+
+@item maint set per-command remote-packets [on|off]
+@itemx maint show per-command remote-packets
+Enable or disable the printing of remote protocol packet statistics
+for each command.
+If enabled, @value{GDBN} will display the following information:
+
+@enumerate a
+@item
+number of packets sent
+@item
+number of packets received
+@item
+number of bytes sent
+@item
+number of bytes received
+@end enumerate
@end table

@kindex maint space
diff --git a/gdb/maint.c b/gdb/maint.c
index 71c4b85..cb8decc 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -42,7 +42,7 @@
#include "top.h"
#include "timeval-utils.h"
#include "maint.h"
-
+#include "remote.h"
#include "cli/cli-decode.h"
#include "cli/cli-utils.h"
#include "cli/cli-setshow.h"
@@ -746,6 +746,10 @@ static int per_command_space;

static int per_command_symtab;

+/* If nonzero, display basic remote-protocol packet stats for each command. */
+
+static int per_command_remote_packets;
+
/* mt per-command commands. */

static struct cmd_list_element *per_command_setlist;
@@ -765,6 +769,7 @@ struct cmd_stats
int time_enabled : 1;
int space_enabled : 1;
int symtab_enabled : 1;
+ int remote_packets_enabled : 1;
long start_cpu_time;
struct timeval start_wall_time;
long start_space;
@@ -774,6 +779,10 @@ struct cmd_stats
int start_nr_primary_symtabs;
/* Total number of blocks. */
int start_nr_blocks;
+ /* Total number of packets sent/received. */
+ long start_packets_sent, start_packets_rcvd;
+ /* Total number of packet bytes sent/received. */
+ long start_packet_bytes_sent, start_packet_bytes_rcvd;
};

/* Set whether to display time statistics to NEW_VALUE
@@ -885,6 +894,30 @@ report_command_stats (void *arg)
nr_blocks,
nr_blocks - start_stats->start_nr_blocks);
}
+
+ if (start_stats->remote_packets_enabled)
+ {
+ long packets_sent, packets_rcvd, bytes_sent, bytes_rcvd;
+
+ get_remote_packet_stats (&packets_sent, &packets_rcvd,
+ &bytes_sent, &bytes_rcvd);
+ if (packets_sent > 0)
+ {
+ printf_unfiltered (_("#pkts sent: %ld (+%ld),"
+ " #pkts rcvd: %ld (+%ld)\n"
+ "#bytes sent: %ld (+%ld),"
+ " #bytes rcvd: %ld (+%ld)\n"),
+ packets_sent,
+ packets_sent - start_stats->start_packets_sent,
+ packets_rcvd,
+ packets_rcvd - start_stats->start_packets_rcvd,
+ bytes_sent,
+ bytes_sent - start_stats->start_packet_bytes_sent,
+ bytes_rcvd,
+ (bytes_rcvd
+ - start_stats->start_packet_bytes_rcvd));
+ }
+ }
}

/* Create a cleanup that reports time and space used since its creation.
@@ -933,6 +966,19 @@ make_command_stats_cleanup (int msg_type)
new_stat->symtab_enabled = 1;
}

+ if (per_command_remote_packets)
+ {
+ long packets_sent, packets_rcvd, bytes_sent, bytes_rcvd;
+
+ get_remote_packet_stats (&packets_sent, &packets_rcvd,
+ &bytes_sent, &bytes_rcvd);
+ new_stat->start_packets_sent = packets_sent;
+ new_stat->start_packets_rcvd = packets_rcvd;
+ new_stat->start_packet_bytes_sent = bytes_sent;
+ new_stat->start_packet_bytes_rcvd = bytes_rcvd;
+ new_stat->remote_packets_enabled = 1;
+ }
+
/* Initalize timer to keep track of how long we waited for the user. */
reset_prompt_for_continue_wait_time ();

@@ -1086,6 +1132,16 @@ displayed following the command's output."),
NULL, NULL,
&per_command_setlist, &per_command_showlist);

+ add_setshow_boolean_cmd ("remote-packets", class_maintenance,
+ &per_command_remote_packets, _("\
+Set whether to display per-command remote-protocol packet statistics."), _("\
+Show whether to display per-command remote-protocol packet statistics."),
+ _("\
+If enabled, the remote protocol packet 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, _("\
diff --git a/gdb/remote.c b/gdb/remote.c
index 186c058..429a49c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -426,6 +426,14 @@ struct remote_state

/* The state of remote notification. */
struct remote_notif_state *notif_state;
+
+ /* Statistics for measuring protocol efficiency.
+ Note: These record data at the protocol level, so to speak.
+ If we're communicating over a flaky channel and have to resent packets
+ that is not accounted for here. It's recommended to track resends, etc.
+ separately. */
+ long packets_sent, packets_received;
+ long bytes_sent, bytes_received;
};

/* Private data that we'll store in (struct thread_info)->private. */
@@ -629,6 +637,20 @@ get_remote_state (void)
return get_remote_state_raw ();
}

+/* Fetch the current packet statistics. */
+
+void
+get_remote_packet_stats (long *packets_sent, long *packets_received,
+ long *bytes_sent, long *bytes_received)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ *packets_sent = rs->packets_sent;
+ *packets_received = rs->packets_received;
+ *bytes_sent = rs->bytes_sent;
+ *bytes_received = rs->bytes_received;
+}
+
static int
compare_pnums (const void *lhs_, const void *rhs_)
{
@@ -7305,6 +7327,10 @@ putpkt_binary (char *buf, int cnt)
*p++ = tohex ((csum >> 4) & 0xf);
*p++ = tohex (csum & 0xf);

+ /* Update the stats counters. */
+ ++rs->packets_sent;
+ rs->bytes_sent += p - buf2;
+
/* Send it over and over until we get a positive ack. */

while (1)
@@ -7748,6 +7774,10 @@ getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever,
return -1;
}

+ /* Update the stats counters. */
+ ++rs->packets_received;
+ rs->bytes_received += val;
+
/* If we got an ordinary packet, return that to our caller. */
if (c == '$')
{
diff --git a/gdb/remote.h b/gdb/remote.h
index b6ea547..1b4c482 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -71,4 +71,10 @@ extern int remote_register_number_and_offset (struct gdbarch *gdbarch,
int *poffset);

extern void remote_notif_get_pending_events (struct notif_client *np);
+
+extern void get_remote_packet_stats (long *packets_sent,
+ long *packets_received,
+ long *bytes_sent,
+ long *bytes_received);
+
#endif