Низкая пропускная способность UDP по сравнению с производительностью iperf UDP
При измерении пропускной способности UDP между ПК с Windows и устройством на базе Zynq с помощью инструмента iperf2 я получаю около 950 Мбит / с по выделенному каналу Ethernet 1 Гбит / с. Тем не менее, когда я использую свое собственное приложение UDP на ПК, я получаю только около 50 Мбит / с, что существенно ниже пропускной способности, чем измеряется iperf. Конечно, в моем приложении UDP нет никакой обработки, только во время цикла, в котором я вызываю функцию sendto, с пакетами UDP размером 1470 байт. Приложение на устройстве Zynq предоставляется XAPP1026, поэтому оно не мое. Я смотрю на код iperf, пытаясь выяснить, что они делают по-другому, но в основном я не могу найти какие-либо параметры сокетов или udp или что-то подобное, что они делают, чтобы максимизировать пропускную способность UDP.
Вот код основной функции (MAXUDP определить 1470):
int main(int argc, char** argv)
{
int sockfd;
struct sockaddr_in servaddr;
char sendline[MAXUDP];
int i;
int j;
const int tr_size = ( 200 * MB );
const int npackets = ( tr_size / MAXUDP );
const int neval = 2;
DWORD start;
DWORD end;
int optval;
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 1), &wsaData) != 0 )
{
printf( "Err: %d\n", WSAGetLastError() );
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
servaddr.sin_addr.s_addr = inet_addr("172.16.0.215");
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
Connect(sockfd, (const SA*) &servaddr, sizeof(servaddr));
optval = 208*KB;
Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*) &optval, sizeof optval);
prep_data(sendline, MAXUDP);
for ( i = 1; i <= neval; i++ )
{
start = GetTickCount();
for ( j = 0; j < npackets/neval; j++ )
sendto(sockfd, sendline, MAXUDP, 0, NULL, NULL);
end = GetTickCount() - start;
printf("Time elapsed: %d sec.\n", end/1000);
printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000, (tr_size/neval)/end - (tr_size/neval)/end/1000);
}
return 0;
}
Итак, мой основной вопрос - как увеличить пропускную способность UDP таким же образом, как это делает iperf?
ОБНОВЛЕНИЕ: я переключился на Ubuntu PC. Результаты разные, но все же происходит нечто случайное. Первое, что я делаю, это устанавливаю IP-адреса для eth0 (ifconfig eth0 172.16.0.200 netmask 255.255.255.0
) и адрес шлюза (route add default gw 172.16.0.1
). Когда я запускаю iperf с iperf -c 172.16.0.215 -i 5 -t 25 -u -b 1000m
) Я получаю около 800 Мбит / с. Однако, после нескольких запусков iperf таким же образом, внезапно я начинаю получать только около 15 Мбит / с или даже намного меньше. Я понял, что мне нужно еще раз установить IP-адрес, маску сети и адреса шлюза, чтобы получить 800 Мбит / с. Кроме того, мое приложение UDP ведет себя так же. Я измеряю 957 Мбит / с (с MAXUDP
установить 1470) после того, как я запустил команды для установки IP-адресов. Но после нескольких итераций он замедляется примерно до 11 Мбит / с. Затем я снова устанавливаю IP-адреса, и поведение повторяется. Итак, как сказал Карим в своем ответе, проблема не в самом коде, а скорее в некоторых ОС, связанных с настройкой netif. Однако я должен запустить свое UDP-приложение в Windows, поэтому мне нужно выяснить, что там происходит. Если у вас, ребята, есть идеи о том, что может происходить в Windows, пожалуйста, дайте мне сейчас.
2 ответа
Почему вы определили MAXUDP 1470? Попробуйте установить его на 65535, измерить еще раз и сообщить здесь.
Не следует путать размер кадра Ethernet (1500 байт) с размером дейтаграммы UDP. Разные вещи. Позвольте стеку IP выполнять необходимую фрагментацию вместо вашего приложения. Это может быть более эффективным.
Вы ошиблись в способе расчета пропускной способности. Ваш размер задается в байтах, поэтому вы рассчитываете пропускную способность в байтах, а iperf - в битах.
менять
printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000, (tr_size/neval)/end - (tr_size/neval)/end/1000);
к этому
printf("Throughput: %d.%3d MB/s\n", ((tr_size/neval)/end/1000)*8, (tr_size/neval)/end - ((tr_size/neval)/end/1000)*8);
Я запустил версию вашего кода на моей машине, и я получаю пропускную способность 1 ГБ. Вот
#include <netinet/in.h>
#include <string.h>
#include <sys/time.h>
#include <cstdio>
#include <arpa/inet.h>
#include <fcntl.h>
#define MAXUDP 1470
#define SERV_PORT 5001
static inline long int getCurTimeInMs()
{
struct timeval tp;
gettimeofday(&tp, NULL);
return tp.tv_sec * 1000 + tp.tv_usec / 1000;
}
int main(int argc, char** argv)
{
int sockfd;
struct sockaddr_in servaddr;
char sendline[MAXUDP];
int i;
int j;
const int tr_size = ( 10000 * 1024*1024 );
const int npackets = ( tr_size / MAXUDP );
const int neval = 2;
int optval;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
servaddr.sin_addr.s_addr = inet_addr("10.0.1.2");
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
connect(sockfd, (const sockaddr*) &servaddr, sizeof(servaddr));
optval = 208*1024;
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*) &optval, sizeof optval);
long int start = 0, end = 0;
for ( i = 1; i <= neval; i++ )
{
start = getCurTimeInMs();
for ( j = 0; j < npackets/neval; j++ )
sendto(sockfd, sendline, MAXUDP, 0, NULL, NULL);
end = getCurTimeInMs() - start;
printf("Time elapsed: %d sec.\n", end/1000);
printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000 * 8, (tr_size/neval)/end - (tr_size/neval)/end/1000);
}
return 0;
}