Russian Qt Forum

Qt => Работа с сетью => Тема начата: eugene.n от Апрель 28, 2014, 15:23



Название: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 28, 2014, 15:23
Есть сеть 10 Гбит/с (комп-комп). Nuttcp показывает максимальную скорость 1 Гбит/с при пакетах размером 1000 байт. При паккетах 8000 байт - скорость 6-7 Гбит/с. В настройках сетевой карты включена функция jumboframe (разрешено отправлять пакеты большого размера (<9000) без фрагментации IP-пакета).



C:\>ping 192.168.13.1 -f -l 8000

Обмен пакетами с 192.168.13.1 по с 8000 байтами данных:
Ответ от 192.168.13.1: число байт=8000 время<1мс TTL=128
Ответ от 192.168.13.1: число байт=8000 время<1мс TTL=128
Ответ от 192.168.13.1: число байт=8000 время<1мс TTL=128
Ответ от 192.168.13.1: число байт=8000 время<1мс TTL=128

Статистика Ping для 192.168.13.1:
    Пакетов: отправлено = 4, получено = 4, потеряно = 0
    (0% потерь)
Приблизительное время приема-передачи в мс:
    Минимальное = 0мсек, Максимальное = 0 мсек, Среднее = 0 мсек



Видно что IP-пакеты не фрагментированы. То есть, тратиться время на фрагментацию не должно.

Пробуем послать пакеты такого же размера с помощью QUdpSocket.

Код:
QByteArray packet;
QUdpSocket *udpSocket = new QUdpSocket(this);
while(udpSocket->writeDatagram(packet.data(), packet.size(), QHostAddress("192.168.13.1"), 3333) == -1);

При размере пакета 1000 байт получаем скорость 1 Гбит, но при размере пакета 8000 байт - скорость падает до 300 Мбит/с.

В описании функции writeDatagram() говорится, что пакеты по 8000 байт шлются без проблем, нужно лишь убедиться в том, что не будут фрагментированы ip-пакеты.

Так в чем же проблема? Почему writeDatagram() работает так медленно с большими пакетами или почему я не могу достичь скорости хотя бы 6 Гб/с (даже при пакетах маленького размера)?


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: LisandreL от Апрель 28, 2014, 23:01
Цитировать
QByteArray packet;
QUdpSocket *udpSocket = new QUdpSocket(this);
while(udpSocket->writeDatagram(packet.data(), packet.size(), QHostAddress("192.168.13.1"), 3333) == -1);
Может побольше кусок кода дадите?
В принципе вполне возможно, что из цикла вываливаетесь и что дальше происходит - не понятно.
Ну и кроме QHostAddress("192.168.13.1") - заменить на константу / переменную. Иначе каждый раз разбор адреса происходит из сторки.
А packet.data() => packet.constData() - так быстрее. Или вообще в пользу массива char посмотреть.
В общем советую по профилировать - совсем не факт, что тормозит именно сокет.

P.S. Может быть стоит вызывать waitForBytesWritten, а может наоборот хуже сделает, не знаю.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 08:58
А packet.data() => packet.constData() - так быстрее. Или вообще в пользу массива char посмотреть.

Не помогло :(

Код:

int packetCnt = 100000;  // кол-во пакетов
QByteArray packet;       // пакет каких-то данных
quint64 byteCnt = 0;     // кол-во переданных байт
QUdpSocket *udpSocket = new QUdpSocket(this);    // сокет UDP
QHostAddress host = QHostAddress("192.168.13.1");
int port = 3333;

packet.resize(8000);      // размер пакета 8000 байт

quint64 t0 = curTime.elapsed();
for(int i = 0; i < packetCnt; i++) {

    while(udpSocket->writeDatagram(packet.constData(), packet.size(), host, port) == -1);    // пытаемся отправить данные, пока не удастся
    
    byteCnt += packet.size();
    quint64 t1 = curTime.elapsed();
    if(t1 >= t0 + 1000) {          
        std::cout << "Передано " << byteCnt << " за 1 с." << std::endl;    // если прошла 1 секунда - выводим кол-во переданных байт
        byteCnt = 0;
        t0 = curTime.elapsed();
    }
}


Дело в том, что на пакетах маленького размера (1000-2000 байт) программа показывает скорость чуть больше 1 Гб/с, а на больших пакетах (5000 - 8000) скорость падает. в 3 -4 раза (Сторонние программы показывают пропускную способность канала до 7 - 7,5 Гб/с).

P.S. Может быть стоит вызывать waitForBytesWritten, а может наоборот хуже сделает, не знаю.
Кажется, это работает на сокетах с соединением. У меня без соединения.



Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Old от Апрель 29, 2014, 09:02
Посмотрите снифером, что реально отправляется в каждом из случаев.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 09:10
Посмотрите снифером, что реально отправляется в каждом из случаев.

Смотрел wireshark'ом. Всё ок. Пакеты не фрагментированы и данные целые (и со стороны клиента и со стороны сервера).


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Old от Апрель 29, 2014, 09:14
Смотрел wireshark'ом. Всё ок. Пакеты не фрагментированы и данные целые (и со стороны клиента и со стороны сервера).
Хм, чудеса. Попробуйте сокету делать flush.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 09:18
Смотрел wireshark'ом. Всё ок. Пакеты не фрагментированы и данные целые (и со стороны клиента и со стороны сервера).
Хм, чудеса. Попробуйте сокету делать flush.

Тот же результат :(


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Old от Апрель 29, 2014, 09:35
Посмотрел исходники, каких то тяжёлый операций не нашел, быстренько вызывается sendto.  ???
Странно.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: LisandreL от Апрель 29, 2014, 09:36
Код:
    quint64 t1 = curTime.elapsed();
    if(t1 >= t0 + 1000) {          
        std::cout << "Передано " << byteCnt << " за 1 с." << std::endl;    // если прошла 1 секунда - выводим кол-во переданных байт
        byteCnt = 0;
    }
Вы тут t0 = t1; не потеряли? А то, насколько я понимаю код, после 1 секунды лог будет выводиться на каждой итерациии, что вполне может тормозить передачу.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 09:40
Код:
    quint64 t1 = curTime.elapsed();
    if(t1 >= t0 + 1000) {          
        std::cout << "Передано " << byteCnt << " за 1 с." << std::endl;    // если прошла 1 секунда - выводим кол-во переданных байт
        byteCnt = 0;
    }
Вы тут t0 = t1; не потеряли? А то, насколько я понимаю код, после 1 секунды лог будет выводиться на каждой итерациии, что вполне может тормозить передачу.

Да, потерял. Спасибо. Исправил. Но не в этом дело)


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 10:23
Немного переформулировал вопрос. Почему я не могу достичь скорости хотя бы 6 Гб/с?   ??? ??? ???


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Old от Апрель 29, 2014, 10:29
Немного переформулировал вопрос. Почему я не могу достичь скорости хотя бы 6 Гб/с?   ??? ??? ???
Стоп. Я думал у вас есть программа, которая умеет отправлять датаграммы быстрее, чем такая же на Qt и вы хотите разобраться почему. Или вы просто предполагали, что с увеличением размера данных возрастет и скорость?


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 10:34
Немного переформулировал вопрос. Почему я не могу достичь скорости хотя бы 6 Гб/с?   ??? ??? ???
Стоп. Я думал у вас есть программа, которая умеет отправлять датаграммы быстрее, чем такая же на Qt и вы хотите разобраться почему. Или вы просто предполагали, что с увеличением размера данных возрастет и скорость?

Да, есть. В первом посте я писал что тестировал сеть с помощью nuttcp и получил скорость 1 Гб при пакетах ~1000Б. У моей программы выходит такая же скорость. У nuttcp при размере пакетов 8000Б получается скорость 6-7 Гб/с, а у моей программы она получается даже ниже чем 1 Гб/с при таких пакетах (8000Б).

А с увеличением размера пакетов скорость растет так как 10 Гбитная сетевая карточка лучше справляется с отправкой больших сегментов, нежели маленьких (при которых она сильно грузится).


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Old от Апрель 29, 2014, 10:57
Попробуйте посмотреть с помощью strace , как отправляет и как настраивает сокет nuttcp.
А потом сравните со своей, может что-то прояснимся.
Может они срочные сообщения отправляют или открывают сокет в неблокирующем режиме?


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Bepec от Апрель 29, 2014, 11:46
Или расширяют буфер на принимающей стороне...


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 11:59
Или расширяют буфер на принимающей стороне...

так моя программа даже не подозревает о существовании сервера, т.к. сокет без соединения. То есть, практически, мы измеряем не пропускную способность сети, а сколько байт может отправить клиент за 1 с.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Bepec от Апрель 29, 2014, 13:37
Тогда я вас не понимаю. Как можно измерить количество отправляемой информации за 1 секунду, если эту информацию никто не принимает? :) Никак. Ведь на отправляющей стороне вы в стороне от самого процесса отправки.

А вот если будет принимающая сторона, то она как раз и измеряет количество принятой информации. И если буфер маленький, часть (большая) пакета будет теряться.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 14:00
Тогда я вас не понимаю. Как можно измерить количество отправляемой информации за 1 секунду, если эту информацию никто не принимает? :) Никак. Ведь на отправляющей стороне вы в стороне от самого процесса отправки.

А вот если будет принимающая сторона, то она как раз и измеряет количество принятой информации. И если буфер маленький, часть (большая) пакета будет теряться.

Принимающая сторона есть. И там можно посмотреть что все данные пришли. Но клиент то не знает о принимающей стороне ничего, так что скорость отправки сообщений ни как не может зависеть от размера буфера приемника. Главный вопрос, почему writeDatagram() работает так медленно, когда у него в распоряжении канал в 10 Гбит/с.

ps. Согласен, что у меня измеряется не сама скорость передачи, а скорее (размер пакета) * (количество удачных завершений writeDatagram()). Принимающая сторона показывает такую же скорость (~1 Гбит/с). Ниже прикрепил график изменения скорости при изменении размера пакетов.


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: Bepec от Апрель 29, 2014, 14:36
Да, кстати буфер и на отправляющей стороне как бы увеличить можно, насколько я помню )

Ммм.. разовью мысль. Что будет если у сокета будет переполнен буфер отправки? Мб он будет ждать его освобождения и до того момента он заблокирует передачу иных пакетов?

PS немного сумбурно, но попробовать стоит :D


Название: Re: QUdpSocket + пакеты большого размера.
Отправлено: eugene.n от Апрель 29, 2014, 14:40
Да, кстати буфер и на отправляющей стороне как бы увеличить можно, насколько я помню )

Ммм.. разовью мысль. Что будет если у сокета будет переполнен буфер отправки? Мб он будет ждать его освобождения и до того момента он заблокирует передачу иных пакетов?

PS немного сумбурно, но попробовать стоит :D

Пробовал. Не помогло  :(

Код:
int bufferSize = 64 * 1024;   // до 4 * 1024 *1024
setsockopt(udpSocket->socketDescriptor(), SOL_SOCKET, SO_SNDBUF, (char *)&bufferSize, sizeof(bufferSize));