Проблемы с производительностью при использовании необработанного TCP API lwIP
Я использую lwIP для добавления сетевых функций в мою систему. На моей платформе я построил буфер, который я хочу отправлять каждый раз, когда он заполнен. Это может произойти довольно быстро. Система напрямую подключена к коммутатору в частной локальной сети. Первоначально отправка данных имела очень большой промежуток времени между 2 секундами. Кроме того, пакеты имели размер 720 байт, если моя память обслуживает меня правильно. Используемый буфер в настоящее время имеет емкость около 20000 байт, и я мог бы решить увеличить его в будущем. Сеть имеет скорость 100 Мбит, и я хотел бы приблизиться к этим скоростям на моей платформе.
При поиске причины медленных скоростей я остановился на конфигурации lwIP. До этого я изменил свой механизм отправки. Я использую raw lwIP API и в настоящее время я записываю данные следующим образом:
tcp_write(<pcb>, (const void*) data, <bytes>, TCP_WRITE_FLAG_COPY);
//<bytes> is at most tcp_sndbuf(<pcb>)
Я знаю, что флаг копирования создает снижение производительности, но он добавлен, потому что я не хочу перезаписывать данные до их фактической отправки. (и флаг - не главная проблема, но что-то, что нужно отполировать, если он работает должным образом). В предыдущем решении я опустил флаг и просто ждал, когда все байты будут подтверждены ACK (после принудительной отправки данных после записи, вызвав tcp_output()) с помощью функции обратного вызова. (Это может быть хуже по производительности, и я не думаю, что это связано)
Я немного поиграл с настройками в lwIP, и это, казалось, имело какое-то значение. Я думаю, что размер окна особенно имел значение, хотя я не совсем уверен. В настоящий момент я значительно увеличил размер окна, и хотя я получаю пакет пакетов с интервалом около 2 мс (вместо 2 с!), За этим следует длительный период "ничего", а затем пакет снова. Я хочу, чтобы он непрерывно отправлял данные со скоростью, на которую он должен быть способен, которая должна составлять не более 100 Мбит, но, по крайней мере, 10 Мбит не странно ожидать, верно?
Я загрузил wireshark, чтобы увидеть, что происходит.
192.168.1.26 - мой настольный компьютер с Windows. 192.168.1.192 - это встроенная система, использующая lwIP.
Сначала я отправляю запрос на запуск с рабочего стола в систему lwIP, чтобы система знала, что должен начинать отправлять буфер каждый раз, когда он заполняется. Если это актуально, это соответствующая часть трассировки:
5 2.007754 192.168.1.26 192.168.1.192 TCP 61 [TCP segment of a reassembled PDU]
6 2.008196 192.168.1.192 192.168.1.26 TCP 60 patrolview > afs3-fileserver [SYN] Seq=0 Win=65535 Len=0 MSS=1400
7 2.226238 192.168.1.192 192.168.1.26 TCP 60 afs3-fileserver > 50015 [ACK] Seq=1 Ack=8 Win=65528 Len=0
13 4.976858 192.168.1.192 192.168.1.26 TCP 60 patrolview > afs3-fileserver [ACK] Seq=1 Ack=1 Win=65535 Len=0
22 6.976572 192.168.1.192 192.168.1.26 TCP 60 [TCP segment of a reassembled PDU]
23 7.177903 192.168.1.26 192.168.1.192 TCP 54 50015 > afs3-fileserver [ACK] Seq=8 Ack=2 Win=64399 Len=0
Я считаю, что это хорошо, хотя я не уверен. В любом случае, после этого происходит фактическая отправка. Соответствующая трассировка выглядит следующим образом. Время начала - 207,99211, что следует считать временем начала. Ожидается разница между этим и 7.177903:
2578 207.992115 192.168.1.192 192.168.1.26 Gryphon 1422 - Invalid -
2581 208.194336 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=1369 Win=64400 Len=0
2582 208.195880 192.168.1.192 192.168.1.26 TCP 1422 [TCP segment of a reassembled PDU]
2583 208.197035 192.168.1.192 192.168.1.26 TCP 1422 [TCP segment of a reassembled PDU]
2584 208.197134 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=4105 Win=64400 Len=0
2585 208.198712 192.168.1.192 192.168.1.26 TCP 1422 [TCP segment of a reassembled PDU]
2586 208.199867 192.168.1.192 192.168.1.26 TCP 1422 [TCP segment of a reassembled PDU]
2587 208.199965 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=6841 Win=64400 Len=0
2588 208.200927 192.168.1.192 192.168.1.26 TCP 1314 [TCP segment of a reassembled PDU]
2590 208.397469 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=8101 Win=63140 Len=0
Кажется, что в настоящее время я отправляю вещи быстрее, чем настольный ACKing. Трафик после трассировки выше показан в виде черных полос и выглядит так:
2591 208.399051 192.168.1.192 192.168.1.26 TCP 1422 [TCP Previous segment lost] [TCP segment of a reassembled PDU]
2592 208.399136 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2590#1] afs3-fileserver > patrolview [ACK] Seq=1 Ack=8101 Win=63140 Len=0
2593 208.400208 192.168.1.192 192.168.1.26 Gryphon 1422
2594 208.400285 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2590#2] afs3-fileserver > patrolview [ACK] Seq=1 Ack=8101 Win=63140 Len=0
2595 208.401361 192.168.1.192 192.168.1.26 Gryphon 1422 - Invalid -
2596 208.401445 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2590#3] afs3-fileserver > patrolview [ACK] Seq=1 Ack=8101 Win=63140 Len=0
2597 208.402425 192.168.1.192 192.168.1.26 Gryphon 1314
2598 208.402516 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2590#4] afs3-fileserver > patrolview [ACK] Seq=1 Ack=8101 Win=63140 Len=0
2599 208.403588 192.168.1.192 192.168.1.26 Gryphon 1422 [TCP Fast Retransmission] Command response
2600 208.403685 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=14833 Win=64400 Len=0
2605 209.992237 192.168.1.192 192.168.1.26 Gryphon 1422 - Invalid -
2607 210.200219 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=16201 Win=63032 Len=0
2608 210.201819 192.168.1.192 192.168.1.26 Gryphon 1422 [TCP Previous segment lost] - Invalid -
2609 210.201903 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2607#1] afs3-fileserver > patrolview [ACK] Seq=1 Ack=16201 Win=63032 Len=0
2609 210.201903 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2607#1] afs3-fileserver > patrolview [ACK] Seq=1 Ack=16201 Win=63032 Len=0
2611 210.203070 192.168.1.26 192.168.1.192 TCP 54 [TCP Dup ACK 2607#2] afs3-fileserver > patrolview [ACK] Seq=1 Ack=16201 Win=63032 Len=0
2955 345.001223 192.168.1.192 192.168.1.26 Gryphon 1422 [TCP Retransmission]
Теперь, после этого момента, есть огромная задержка, которую я не могу объяснить. Следующие пакеты поступают через 345 секунд, это разница в 135 секунд. (хотя в большинстве случаев это было немного меньше, но все еще слишком высоко) Это начинается следующим образом:
2955 345.001223 192.168.1.192 192.168.1.26 Gryphon 1422 [TCP Retransmission]
2958 345.001707 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=20305 Win=64400 Len=0
2959 345.003336 192.168.1.192 192.168.1.26 TCP 1422 [TCP segment of a reassembled PDU]
2960 345.004395 192.168.1.192 192.168.1.26 TCP 1314 [TCP segment of a reassembled PDU]
2961 345.004494 192.168.1.26 192.168.1.192 TCP 54 afs3-fileserver > patrolview [ACK] Seq=1 Ack=22933 Win=64400 Len=0
и т.п.
Позже аналогичные проблемы возникают, хотя упомянутая задержка короче. У меня вопрос: как я могу решить проблему медленной отправки с моей платформы и как мне настроить свои настройки lwIP, чтобы ожидать достойных / хороших результатов? Я хочу отправить данные на быстрой скорости. (моя сеть способна развивать скорость 100 Мбит / с, чем ближе, тем лучше) Я думаю, что в настоящее время я полностью испортил свои настройки, но я не уверен, как настроить их для своих нужд. Вот некоторые (надеюсь) соответствующие настройки из моего lwipopts.h
файл:
#define MEM_SIZE 65000
#define PBUF_POOL_SIZE 1024
#define IP_FRAG_USES_STATIC_BUF 0
#define TCP_WND 65535
#define TCP_MSS 1400
#define TCP_SND_BUF 65535
#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(1528)
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_SO_RCVTIMEO 1
1 ответ
Я столкнулся с похожими проблемами, используя beaglebone и следующие настройки
#define MEM_SIZE (1024 * 1024) /* 1MiB */
#define MEMP_NUM_PBUF 1024
#define MEMP_NUM_TCP_PCB 32
#define PBUF_POOL_SIZE 1024
#define TCP_MSS 1460
#define TCP_WND (4*TCP_MSS)
#define TCP_SND_BUF 65535
#define TCP_OVERSIZE TCP_MSS
#define TCP_SND_QUEUELEN 512
#define MEMP_NUM_TCP_SEG 512
Используя опрашиваемую функцию tcp_sent, я в основном проверил, сколько байтов у меня в буфере, и сразу же заполнил их в самой опрашиваемой функции другими выборками. Это было проверить все
Я был очень удивлен, что проволочная акула показала пакеты пакетов в течение примерно нескольких миллисекунд, а затем 700 мс ничего.
Глубоко в стеке я обнаружил, что это происходит именно в тот момент, когда отправлено 65535 байт (или примерно в этом направлении).
Все это было решено отключением проверки памяти
Посмотрите в своем lwipopts.h, случайно ли вы не определяете где-нибудь:
#define MEMP_SANITY_CHECK 1
Если это так, удалите эту строку или установите ее на ноль. Таким образом, моя производительность отправки пакетов не увеличилась (у меня все еще около 11 Мбит при стрельбе на максимальной скорости передачи данных), но общая пропускная способность значительно увеличилась, так как время между двумя отправленными пакетами теперь постоянное и занимает примерно 100 мкс.
Нужно сказать, что это все еще не решает проблему наличия только 11 Мбит на линии 100 Мбит, полностью выделенных только для этого оборудования.