mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
iperf: added Tx bandwidth limit option
This commit is contained in:
parent
ba62cbc04f
commit
3f7cf8a540
@ -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);
|
||||
|
@ -14,6 +14,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 {
|
||||
@ -147,25 +149,40 @@ 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)
|
||||
{
|
||||
bool retry = false;
|
||||
uint8_t *buffer;
|
||||
uint8_t delay = 0;
|
||||
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;
|
||||
|
||||
buffer = s_iperf_ctrl.buffer;
|
||||
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 (type == IPERF_TRANS_TYPE_UDP) {
|
||||
if (false == retry) {
|
||||
delay = 1;
|
||||
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;
|
||||
}
|
||||
retry = false;
|
||||
prev_time = send_time;
|
||||
}
|
||||
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
|
||||
actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
|
||||
@ -175,17 +192,9 @@ static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint
|
||||
if (actual_send != want_send) {
|
||||
if (type == IPERF_TRANS_TYPE_UDP) {
|
||||
err = iperf_get_socket_error_code(send_socket);
|
||||
if (err == ENOMEM) {
|
||||
vTaskDelay(delay);
|
||||
if (delay < IPERF_MAX_DELAY) {
|
||||
delay <<= 1;
|
||||
}
|
||||
retry = true;
|
||||
continue;
|
||||
} else {
|
||||
if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
|
||||
ESP_LOGE(TAG, "udp client send abort: err=%d", err);
|
||||
}
|
||||
// ENOMEM is expected under heavy load => do not print it
|
||||
if (err != ENOMEM) {
|
||||
iperf_show_socket_error_reason("udp client send", send_socket);
|
||||
}
|
||||
}
|
||||
if (type == IPERF_TRANS_TYPE_TCP) {
|
||||
@ -196,6 +205,10 @@ static void socket_send(int send_socket, struct sockaddr_storage dest_addr, uint
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +329,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);
|
||||
@ -423,7 +436,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);
|
||||
|
@ -70,6 +70,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;
|
||||
@ -167,6 +168,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",
|
||||
@ -345,6 +356,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 = {
|
||||
|
@ -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 = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user