From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> This make use of gnuplot when using -a/--analyze to plot a graph of Latency-Packets: Found BR-ACL connection with handle 256 Address: XX:XX:XX:XX:XX:XX (Sony Home Entertainment&Sound Products Inc) 60 RX packets 22548 TX packets 22547 TX completed packets 3 msec min latency 73 msec max latency 11 msec median latency 6 octets TX min packet size 850 octets TX max packet size 847 octets TX median packet size 7000 +-------------------------------------------------------------------+ | + + + + + + + | | A Packets A | 6000 |-+ A +-| | | 5000 |-+ +-| | | | | 4000 |-+ +-| | | | | 3000 |-+ A +-| | | | | 2000 |-+ +-| | A | 1000 |-+ AA +-| | A A | | + AAAA+ + + + + + | 0 +-------------------------------------------------------------------+ 0 10 20 30 40 50 60 70 80 Latency --- monitor/analyze.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/monitor/analyze.c b/monitor/analyze.c index a20ba98b0be4..6fdb32f2dc55 100644 --- a/monitor/analyze.c +++ b/monitor/analyze.c @@ -28,6 +28,9 @@ #include "monitor/packet.h" #include "monitor/analyze.h" +#define TIMEVAL_MSEC(_tv) \ + (long long)((_tv)->tv_sec * 1000 + (_tv)->tv_usec / 1000) + struct hci_dev { uint16_t index; uint8_t type; @@ -69,12 +72,18 @@ struct hci_conn { struct timeval tx_lat_min; struct timeval tx_lat_max; struct timeval tx_lat_med; + struct queue *plot; uint16_t tx_pkt_min; uint16_t tx_pkt_max; uint16_t tx_pkt_med; struct queue *chan_list; }; +struct conn_plot { + long long x_msec; + size_t y_count; +}; + struct l2cap_chan { uint16_t cid; uint16_t psm; @@ -135,6 +144,42 @@ static struct l2cap_chan *chan_lookup(struct hci_conn *conn, uint16_t cid, return chan; } +static void tmp_write(void *data, void *user_data) +{ + struct conn_plot *plot = data; + FILE *tmp = user_data; + + fprintf(tmp, "%lld %zu\n", plot->x_msec, plot->y_count); +} + +static void conn_plot_draw(struct hci_conn *conn) +{ + const char *filename = "plot.tmp"; + FILE *gplot = popen("gnuplot", "w"); + FILE *tmp; + + if (!gplot) + return; + + if (queue_isempty(conn->plot)) + goto done; + + tmp = fopen(filename, "w"); + if (!tmp) + goto done; + + queue_foreach(conn->plot, tmp_write, tmp); + + fprintf(gplot, "set terminal dumb\n"); + fprintf(gplot, "set xlabel 'Latency'\n"); + fprintf(gplot, "plot './%s' using 1:2 t 'Packets'\n", filename); + fflush(gplot); + + fclose(tmp); +done: + pclose(gplot); +} + static void conn_destroy(void *data) { struct hci_conn *conn = data; @@ -187,6 +232,10 @@ static void conn_destroy(void *data) print_field("%u octets TX min packet size", conn->tx_pkt_min); print_field("%u octets TX max packet size", conn->tx_pkt_max); print_field("%u octets TX median packet size", conn->tx_pkt_med); + + conn_plot_draw(conn); + + queue_destroy(conn->plot, free); queue_destroy(conn->chan_list, chan_destroy); queue_destroy(conn->tx_queue, free); @@ -447,6 +496,35 @@ static void evt_cmd_complete(struct hci_dev *dev, struct timeval *tv, } } +static bool match_plot_latency(const void *data, const void *user_data) +{ + const struct conn_plot *plot = data; + const struct timeval *latency = user_data; + + return TIMEVAL_MSEC(latency) == plot->x_msec; +} + +static void conn_plot_add(struct hci_conn *conn, struct timeval *latency, + uint16_t count) +{ + struct conn_plot *plot; + + plot = queue_find(conn->plot, match_plot_latency, latency); + if (plot) { + plot->y_count += count; + return; + } + + if (!conn->plot) + conn->plot = queue_new(); + + plot = new0(struct conn_plot, 1); + plot->x_msec = TIMEVAL_MSEC(latency); + plot->y_count = count; + + queue_push_tail(conn->plot, plot); +} + static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, const void *data, uint16_t size) { @@ -504,6 +582,8 @@ static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, } else conn->tx_lat_med = res; + conn_plot_add(conn, &res, count); + free(last_tx); } } -- 2.41.0