Низкая пропускная способность 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;
}
Другие вопросы по тегам