Ver código fonte

iperf: added Tx bandwidth limit option

Ondrej Kosta 4 anos atrás
pai
commit
c8b08b9a4b

+ 2 - 0
examples/common_components/iperf/include/iperf.h

@@ -33,6 +33,7 @@ extern "C" {
 #define IPERF_DEFAULT_PORT 5001
 #define IPERF_DEFAULT_INTERVAL 3
 #define IPERF_DEFAULT_TIME 30
+#define IPERF_DEFAULT_NO_BW_LIMIT -1
 
 #define IPERF_TRAFFIC_TASK_NAME "iperf_traffic"
 #define IPERF_TRAFFIC_TASK_PRIORITY 4
@@ -67,6 +68,7 @@ typedef struct {
     uint32_t interval;
     uint32_t time;
     uint16_t len_send_buf;
+    int32_t bw_lim;
 } iperf_cfg_t;
 
 esp_err_t iperf_start(iperf_cfg_t *cfg);

+ 38 - 9
examples/common_components/iperf/iperf.c

@@ -15,6 +15,8 @@
 #include "freertos/task.h"
 #include "esp_check.h"
 #include "esp_log.h"
+#include "esp_rom_sys.h"
+#include "esp_timer.h"
 #include "iperf.h"
 
 typedef struct {
@@ -137,12 +139,15 @@ static void socket_recv(int recv_socket, struct sockaddr_storage listen_addr, ui
     }
 }
 
-static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint8_t type)
+static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint8_t type, int bw_lim)
 {
     uint8_t *buffer;
-    uint8_t delay = 1;
     int actual_send = 0;
     int want_send = 0;
+    int period_us = -1;
+    int delay_us = 0;
+    int64_t prev_time = 0;
+    int64_t send_time = 0;
     int err = 0;
     const socklen_t socklen = (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
     const char *error_log = (type == IPERF_TRANS_TYPE_TCP) ? "tcp client send" : "udp client send";
@@ -151,15 +156,33 @@ static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint
     want_send = s_iperf_ctrl.buffer_len;
     iperf_start_report();
 
+    if (bw_lim > 0) {
+        period_us = want_send * 8 / bw_lim;
+    }
+
     while (!s_iperf_ctrl.finish) {
+        if (period_us > 0) {
+            send_time = esp_timer_get_time();
+            if (actual_send > 0){
+                // Last packet "send" was successful, check how much off the previous loop duration was to the ideal send period. Result will adjust the
+                // next send delay.
+                delay_us += period_us + (int32_t)(prev_time - send_time);
+            } else {
+                // Last packet "send" was not successful. Ideally we should try to catch up the whole previous loop duration (e.g. prev_time - send_time).
+                // However, that's not possible since the most probable reason why the send was unsuccessful is the HW was not able to process the packet.
+                // Hence, we cannot queue more packets with shorter (or no) delay to catch up since we are already at the performance edge. The best we
+                // can do is to reset the send delay (which is probably big negative number) and start all over again.
+                delay_us = 0;
+            }
+            prev_time = send_time;
+        }
+
         actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, socklen);
         if (actual_send != want_send) {
             if (type == IPERF_TRANS_TYPE_UDP) {
                 err = iperf_get_socket_error_code(send_socket);
-                if (err == ENOMEM) {
-                    vTaskDelay(delay);
-                    delay = MIN(delay << 1, IPERF_MAX_DELAY);
-                } else {
+                // ENOMEM is expected under heavy load => do not print it
+                if (err != ENOMEM) {
                     iperf_show_socket_error_reason(error_log, send_socket);
                 }
             } else if (type == IPERF_TRANS_TYPE_TCP) {
@@ -167,9 +190,12 @@ static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint
                 break;
             }
         } else {
-            delay = 1;
             s_iperf_ctrl.actual_len += actual_send;
         }
+        // The send delay may be negative, it indicates we are trying to catch up and hence to not delay the loop at all.
+        if (delay_us > 0) {
+            esp_rom_delay_us(delay_us);
+        }
     }
 }
 
@@ -290,7 +316,7 @@ static esp_err_t iperf_run_tcp_client(void)
         memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
     }
 
-    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_TCP);
+    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_TCP, s_iperf_ctrl.cfg.bw_lim);
 exit:
     if (client_socket != -1) {
         shutdown(client_socket, 0);
@@ -397,7 +423,7 @@ static esp_err_t iperf_run_udp_client(void)
         memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
     }
 
-    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_UDP);
+    socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_UDP, s_iperf_ctrl.cfg.bw_lim);
 exit:
     if (client_socket != -1) {
         shutdown(client_socket, 0);
@@ -474,6 +500,9 @@ esp_err_t iperf_start(iperf_cfg_t *cfg)
         s_iperf_ctrl.buffer = NULL;
         return ESP_FAIL;
     }
+
+    //ret = xTaskCreatePinnedToCore(dummy_task, "dummy_task", 1024, NULL, IPERF_TRAFFIC_TASK_PRIORITY+1, NULL, portNUM_PROCESSORS - 1);
+
     return ESP_OK;
 }
 

+ 12 - 0
examples/ethernet/iperf/main/cmd_ethernet.c

@@ -71,6 +71,7 @@ static struct {
     struct arg_int *length;
     struct arg_int *interval;
     struct arg_int *time;
+    struct arg_int *bw_limit;
     struct arg_lit *abort;
     struct arg_end *end;
 } iperf_args;
@@ -168,6 +169,16 @@ static int eth_cmd_iperf(int argc, char **argv)
         }
     }
 
+    /* iperf -b */
+    if (iperf_args.bw_limit->count == 0) {
+        cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
+    } else {
+        cfg.bw_lim = iperf_args.bw_limit->ival[0];
+        if (cfg.bw_lim <= 0) {
+            cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
+        }
+    }
+
     printf("mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d\r\n",
            cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
            cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
@@ -343,6 +354,7 @@ void register_ethernet(void)
     iperf_args.interval = arg_int0("i", "interval", "<interval>",
                                    "seconds between periodic bandwidth reports");
     iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
+    iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
     iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
     iperf_args.end = arg_end(1);
     const esp_console_cmd_t iperf_cmd = {

+ 13 - 0
examples/wifi/iperf/main/cmd_wifi.c

@@ -30,6 +30,7 @@ typedef struct {
     struct arg_int *length;
     struct arg_int *interval;
     struct arg_int *time;
+    struct arg_int *bw_limit;
     struct arg_lit *abort;
     struct arg_end *end;
 } wifi_iperf_t;
@@ -402,6 +403,17 @@ static int wifi_cmd_iperf(int argc, char **argv)
         }
     }
 
+    /* iperf -b */
+    if (iperf_args.bw_limit->count == 0) {
+        cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
+    } else {
+        cfg.bw_lim = iperf_args.bw_limit->ival[0];
+        if (cfg.bw_lim <= 0) {
+            cfg.bw_lim = IPERF_DEFAULT_NO_BW_LIMIT;
+        }
+    }
+
+
     ESP_LOGI(TAG, "mode=%s-%s sip=%d.%d.%d.%d:%d, dip=%d.%d.%d.%d:%d, interval=%d, time=%d",
              cfg.flag & IPERF_FLAG_TCP ? "tcp" : "udp",
              cfg.flag & IPERF_FLAG_SERVER ? "server" : "client",
@@ -476,6 +488,7 @@ void register_wifi(void)
     iperf_args.length = arg_int0("l", "len", "<length>", "Set read/write buffer size");
     iperf_args.interval = arg_int0("i", "interval", "<interval>", "seconds between periodic bandwidth reports");
     iperf_args.time = arg_int0("t", "time", "<time>", "time in seconds to transmit for (default 10 secs)");
+    iperf_args.bw_limit = arg_int0("b", "bandwidth", "<bandwidth>", "bandwidth to send at in Mbits/sec");
     iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
     iperf_args.end = arg_end(1);
     const esp_console_cmd_t iperf_cmd = {