monitor: Use gnuplot to plot graph of Latency-Packets
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 26 Jul 2023 22:14:26 +0000 (15:14 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 5 Jan 2024 13:34:03 +0000 (19:04 +0530)
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

index 74d8886..e687b1a 100755 (executable)
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include "lib/bluetooth.h"
 
@@ -30,6 +31,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;
@@ -71,12 +75,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;
@@ -137,6 +147,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 out 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;
@@ -174,21 +225,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);
@@ -205,6 +252,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();
 
@@ -449,6 +497,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)
 {
@@ -506,6 +580,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);
                }
        }