[BlueZ PATCH v3] monitor: Use gnuplot to plot graph of Latency-Packets
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2023-07-27 21:10:23
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Luiz Augusto von Dentz <redacted>
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
10000 +------------------------------------------------------------------+
|+ + |
|+ |+ Packets +-----+ |
|+ || |
1000 |-+ +||++ |
|+ |||||+ + |
|+ ||||||+| |
|+ ||||||||+ |
|+ |||||||||+++ |
100 |-+ |||||||||||++++ |
|+ ||||||||||||||| + |
|+ ||||||||||||||| ++ |
|+ + |||||||||||||||+|| |
10 |-+| ||||||||||||||||||+++ |
|+ | ||||||||||||||||||||| |
|+ | ||||||||||||||||||||| + |
|+ | ++|||||||||||||||||||||++|++++ + |
| | |||||||||||||||||||||||||||||| | |
1 |-+|+|||||||||||||||||||||||||||||| + + | + + + |
+------------------------------------------------------------------+
0 10 20 30 40 50 60 70 80
Latency (ms)
---
monitor/analyze.c | 98 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 87 insertions(+), 11 deletions(-)
diff --git a/monitor/analyze.c b/monitor/analyze.c
index a20ba98b0be4..29aee5ad1680 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c@@ -17,6 +17,7 @@ #include <stdio.h> #include <string.h> #include <sys/time.h> +#include <unistd.h> #include "lib/bluetooth.h"
@@ -28,6 +29,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 +73,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 plot { + long long x_msec; + size_t y_count; +}; + struct l2cap_chan { uint16_t cid; uint16_t psm;
@@ -135,6 +145,47 @@ 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 plot *plot = data; + FILE *tmp = user_data; + + fprintf(tmp, "%lld %zu\n", plot->x_msec, plot->y_count); +} + +static void plot_draw(struct queue *queue) +{ + const char *filename = "analyze.tmp"; + FILE *gplot = popen("gnuplot", "w"); + FILE *tmp; + + if (!gplot) + return; + + if (queue_isempty(queue)) + goto done; + + tmp = fopen(filename, "w"); + if (!tmp) + goto done; + + queue_foreach(queue, tmp_write, tmp); + + fprintf(gplot, "set terminal dumb enhanced ansi\n"); + fprintf(gplot, "set xlabel 'Latency (ms)'\n"); + fprintf(gplot, "set tics nomirror\n"); + fprintf(gplot, "set log y\n"); + fprintf(gplot, "set yrange [0.5:*]\n"); + fprintf(gplot, "plot './%s' using 1:2 t 'Packets' w impulses\n", + filename); + fflush(gplot); + + fclose(tmp); +done: + pclose(gplot); + unlink(filename); +} + static void conn_destroy(void *data) { struct hci_conn *conn = data;
@@ -172,21 +223,17 @@ static void conn_destroy(void *data) print_field("%lu RX packets", conn->rx_num); print_field("%lu TX packets", conn->tx_num); print_field("%lu TX completed packets", conn->tx_num_comp); - print_field("%lld msec min latency", - (long long) - (conn->tx_lat_min.tv_sec * 1000 + - conn->tx_lat_min.tv_usec / 1000)); - print_field("%lld msec max latency", - (long long) - (conn->tx_lat_max.tv_sec * 1000 + - conn->tx_lat_max.tv_usec / 1000)); + print_field("%lld msec min latency", TIMEVAL_MSEC(&conn->tx_lat_min)); + print_field("%lld msec max latency", TIMEVAL_MSEC(&conn->tx_lat_max)); print_field("%lld msec median latency", - (long long) - (conn->tx_lat_med.tv_sec * 1000 + - conn->tx_lat_med.tv_usec / 1000)); + TIMEVAL_MSEC(&conn->tx_lat_med)); 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); + + plot_draw(conn->plot); + + queue_destroy(conn->plot, free); queue_destroy(conn->chan_list, chan_destroy); queue_destroy(conn->tx_queue, free);
@@ -203,6 +250,7 @@ static struct hci_conn *conn_alloc(struct hci_dev *dev, uint16_t handle, conn->handle = handle; conn->type = type; conn->tx_queue = queue_new(); + conn->plot = queue_new(); conn->chan_list = queue_new();
@@ -447,6 +495,32 @@ 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 plot *plot = data; + const struct timeval *latency = user_data; + + return TIMEVAL_MSEC(latency) == plot->x_msec; +} + +static void plot_add(struct queue *queue, struct timeval *latency, + uint16_t count) +{ + struct plot *plot; + + plot = queue_find(queue, match_plot_latency, latency); + if (plot) { + plot->y_count += count; + return; + } + + plot = new0(struct plot, 1); + plot->x_msec = TIMEVAL_MSEC(latency); + plot->y_count = count; + + queue_push_tail(queue, plot); +} + static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, const void *data, uint16_t size) {
@@ -504,6 +578,8 @@ static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, } else conn->tx_lat_med = res; + plot_add(conn->plot, &res, count); + free(last_tx); } }
--
2.41.0