Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Самый быстрый и самый маленький TCP-стек.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3
Rst7
Итак, по просьбам трудящихся выкладываю порт своего стека на LPC1768, выдранный из текущего проекта, над которым щас тружусь.

Нажмите для просмотра прикрепленного файла

Собирается IAR'ом 6.20.3 (вроде крайний на текущий момент), за подправить для GCC - даже не просите.

В качестве PHY используется KSZ8041TL, что, в общем, не принципиально - править, если что, файл emac.c

Тактовая проца в проекте - 100МГц, кварц - 20МГц, менять - функция InitPLL в файле hardware_init.c

Так же для генерации 50МГц REFCLK используется сам процессор через модуль CLKOUT. Кому не надо, в файле hardware_init.c необходимо убрать
CODE
  //Нужно если 50МГц для RMII генерируется процом
  PINSEL3 |= (0x01UL<<22); //CLKOUT on P1.27
  CLKOUTCFG=0x00000110; //CLKOUT 100MHz/2=50MHz used for RMII


Стек поддерживает TCP (и серверные, и клиентские сокеты), ICMP. Очень не долго прикрутить UDP. Поддерживается Fast Retransmit на передачу. На прием - сделаю чуть позже (если, конечно, понадобится).

Архитектура стека - callback по событиям из низкоприоритетного прерывания (используется модуль RIT как таймер, необходимый для TCP и заодно происходит Wakeup этого потока при поступлении пакетов - через прерывание от EMAC, которые должно быть высокоприоритетным (но при этом очень короткое, TODO - управление Flow Control)). Сам стек - network.c.

По умолчанию IP-адрес - 192.168.0.100.

Есть вебинтерфейс, даже с поддержкой ajax - можно поставить галочку Update Graphics и повеселиться (естественно, с браузером, который понимает HTML5 - Опера, Хром, Тормозилла - все годится). Кнопки "<<" и ">>" тоже можно понажимать. Для создания и отображения этих данных копать show_data.c и HTMLsource/http_root_level3.

Еще там случайно md5-авторизация в вебсервере сделана wink.gif

Нажмите для просмотра прикрепленного файла

Эмулятор EEPROM в проекте не прикручен, так что на страничке конфигурации настройки стека не сохраняются. Когда у себя в проекте прикручу, сюда сделаю порт.

На порту 2000 висит отдаватель файла со случайными числами размером 100 мегабайт - это для теста скорости. В папочке GetData лежит проект забирателя для большого брата (собирать C++ Builder'ом).

Ну вот теперь, собственно, за скорость. По TCP - 90Мбит/с.
Нажмите для просмотра прикрепленного файла

На этом, кстати, предлагаю закончить спор о максимально достижимой скорости по TCP.

Ну размеры вообще не угадываются - 3.7кБ собственно стек, вебсервер - 3.5кБ. Ах да, там еще странички пакуются, но это осталось с версии для AVR, можно честно выбросить.

Собственно, примеры использования можно смотреть в rx_tcp_dump.c (тупой отправлятель данных) и http_server.c (веб-сервер, там берегите мозг).

Ну и на посошок - лицензии. От это все - GPL, так что пользуйтесь.

На все вопросы постараюсь ответить тут.

Добавлено 29 июня 2011г:
http://electronix.ru/forum/index.php?s=&am...st&p=956930 - ревизия 1315.

Добавлено 30 июля 2011г:
http://electronix.ru/forum/index.php?s=&am...st&p=957213 - ревизия 1318.
andrewlekar
Эмуляцию EEPROM уже хочется глянуть. У меня своя есть, но довольно сложная реализация и сектора не очень эффективно используются.
Rst7
QUOTE
Эмуляцию EEPROM уже хочется глянуть.


А что, собственно стек не интересен?
prottoss
А че он самый быстрый то? С чем сравнивалось?
У мя тоже есть свой стек rolleyes.gif правда в LPC я не силен sm.gif Но есть SAM7X... Как нить измерю сантиметры
Rst7
QUOTE
А че он самый быстрый то? С чем сравнивалось?


А Вы замечали, что у нас на форуме в каждом обсуждении, касаемом TCP-стеков имеется несколько обязательных фраз про то, что TCP - это очень медленно и т.д.? И обычно выше 30мбит никто не поднимается в заявках wink.gif

prottoss
Цитата(Rst7 @ Jul 27 2011, 18:40) *
А Вы замечали, что у нас на форуме в каждом обсуждении, касаемом TCP-стеков имеется несколько обязательных фраз про то, что TCP - это очень медленно и т.д.? И обычно выше 30мбит никто не поднимается в заявках wink.gif
Да есть тут пара-тройка юююзвонов, но я не об этом. Я о том, с чем сравнивалось - почему он "самый быстрый" sm.gif Кстати, на счет самого маленького тоже надо проверить...

А сколько занимает памяти TCP-сокет кстати? И сколько стек использует стека? sm.gif
Rst7
QUOTE
А сколько занимает памяти TCP-сокет кстати?


49 байт, если мне не изменяет память.

QUOTE
И сколько стек использует стека?


Немного. 40 байт стека в основном коде плюс немного в процедурах (не более 16 байт). Callback-и, например, в http-сервере - 48 байт суммарно. Правда, есть еще md5, тот добавляет 56 байт.

QUOTE
Я о том, с чем сравнивалось - почему он "самый быстрый"


Пока ни с чем, исключительно по общей тенденции реплик по форуму. Мне лень ковыряться в других стеках и доводить их до ума - дабы можно было адекватно сравнить. Давайте с Вашим померяемся sm.gif
prottoss
Цитата(Rst7 @ Jul 27 2011, 19:07) *
Давайте с Вашим померяемся sm.gif
Хорошо. Постараюсь причесать до понедельника. После отпуска ни как не могу настроиться на нормальный лад sm.gif
Rst7
QUOTE
Хорошо. Постараюсь причесать до понедельника.


Так а по-простому? Прикрутите к подходящему Вашему проекту тестовый сокет, в который скормится метров 100 рандома и вуаля. Я такой использую:
CODE
  r=r*1103515245+12345;


Софтик для теста можете у меня из архива взять.
prottoss
Цитата(Rst7 @ Jul 27 2011, 19:24) *
Так а по-простому?
Сейчас попробую. Просто проект пылится уже более двух лет. По моему под 4 ИАР еще. Так что сегодня и по быстрому не обещаю.
scifi
Интересная штука. Эх, причесать бы код и абстрагировать от железа - получился бы полезный для многих проект. А с документацией ещё полезнее было бы...
Кстати, для разбора заголовков HTTP есть интересная библиотека: HTTP parser. Чтобы не изобретать свой велосипед.
prottoss
Цитата(scifi @ Jul 27 2011, 20:01) *
Эх, причесать бы код
Да sm.gif автору без обид - я тож об этом подумал - куча-мала sm.gif
Rst7
QUOTE
Эх, причесать бы код и абстрагировать от железа


От железа к железу оно в полпинка переносится. Изначально это был проект под AVR, который с рукопашным эзернетом был. Порт по времени занял два дня.

А код там нечего причесывать. Он сделан из соображений оптимальности и портабельности под разные архитектуры без потери этой самой оптимальности. Кому читабельность - тому масса проектов в сети, вполне читабельно, только работает так себе wink.gif

А вот документацию, конечно, надо делать. Только где взять время sad.gif
zltigo
QUOTE (scifi @ Jul 27 2011, 16:01) *
Эх, причесать бы код и абстрагировать от железа - получился бы полезный для многих проект.

Я пока исходники вообще не смотрел, но к "оторвать от железа" сразу отношусь плохо - этих оторванных от железа, использующих от возможностей железа 0 целых хрен десятых уже понаписано немеряно. На данный момент максимальную ценность представляют решения которые наконец-то показывают, как максимально эффективно работать с конкретным железом и какой эффект от этого получается. Судя по скорости работы с конкретным железом этот стек интегрирован хорошо. И именно в этом его положительный пример.
Rst7
QUOTE
Судя по скорости работы с конкретным железом этот стек интегрирован хорошо.


Честно говоря, не сильно я там особенности железа использую. Есть что покрутить (в частности, есть тонкости в передатчике), но исключительно ради снижения CPU load. Будет свободное время - займусь. Пока на очереди - Flow Control.
VslavX
Цитата(prottoss @ Jul 27 2011, 15:33) *
А че он самый быстрый то? С чем сравнивалось?
У мя тоже есть свой стек rolleyes.gif правда в LPC я не силен sm.gif Но есть SAM7X... Как нить измерю сантиметры

А вот я, кстати, не отказался бы померяться сантиметрами sm.gif
Может быть, обсудим методику тестирования производительности TCP и я напишу ответное тестовое приложение (под Win32) и выложу тут исходники? Авторы стеков напишут ответку на своих платформах и сразу будет видно - у кого скока см МБ/сек. Или может готовое приложение есть? Я смотрел на ntttcp, но MS деталей этого теста, увы, не раскрывает.
PS. Если просто по TCP слать в discard, то мой стек на LPC17@100 дает чуть более 4Мбайт/сек, но хотелось бы таки более осмысленного теста.
PPS. exe-шники для at200 и getdata, имхо, в архиве лишние, а вот исходники embpack - не помешали бы, ну и библиотек (типа cc3260.dll) к нему не хватает.
Rst7
QUOTE
Может быть, обсудим методику тестирования производительности TCP и я напишу ответное тестовое приложение (под Win32)


Я не знаю, что там обсуждать. Я просто в своей тестовой софтине принимаю из сокета и пишу в файл (ибо на самом деле моя тестовая софтина для получения данных с АЦП была). Сто метров с замером времени - вполне адекватный тест. Следующая серия тестов - накатываем dummy net, втыкаем очередь-задержку (можно небольшую, пара миллисекунд вполне для отсева пионерских поделок) и наслаждаемся sm.gif

QUOTE
а вот исходники embpack - не помешали бы, ну и библиотек (типа cc3260.dll) к нему не хватает.


Положу, пардон, совсем забыл.
prottoss
Цитата(Rst7 @ Jul 27 2011, 20:27) *
Так - поднял свой пыльный стек sm.gif Теперь пытаюсь вникнуть в приложение на билдере. Сразу скажу, что сетевые приложения под Win32 не программировал, по этому туго. Чего там оно просит?

Код
if ((he=gethostbyname("nikee_cm3.tst"))==NULL)
        {
                ShowMessage("Error: gethostbyname failed!");
                return;
        }

Можно на пальцах? Другим тоже, думаю, интересно будет.
Сокет, я так понимаю, сервером открывать?
Rst7
QUOTE
Чего там оно просит?


В windows/drivers/etc/hosts добавьте запись nikee_cm3.tst с нужным Вам IP-адресом.

Да, сокет на младшем брате должен быть серверный.
blackfin
Цитата(VslavX @ Jul 27 2011, 18:54) *
А вот я, кстати, не отказался бы померяться сантиметрами sm.gif
Может быть, обсудим методику тестирования производительности TCP и я напишу ответное тестовое приложение (под Win32) и выложу тут исходники? Авторы стеков напишут ответку на своих платформах и сразу будет видно - у кого скока см МБ/сек.

Можно, например, Ethereal'ом протестировать..

Но для полноты картины хорошо бы три-четыре сокета открыть:
Нажмите для просмотра прикрепленного файла
VslavX
Цитата(blackfin @ Jul 27 2011, 18:36) *
Можно, например, Ethereal'ом протестировать..

Можно, но там нужно долго в цифры втыкать - например, смотрю - показывает что два пакета по 1460 байт принимаются с интервалом 7 мкс, хотя на скорости 100Мбпс это ну никак. Потом подумал - оно ж у меня в гигабитный свитч воткнуто, тот мог такое учудить, вполне... Не-а, даже на гигабите в 7 мкс не укладывается sm.gif. У меня "продвинутый" свитч - он порт-мирроринг позволяет (только так можно помониторить свой девайс, например, к NAS-у подключенным), так на зеркальном порту тайминги вообще уезжают.

В-общем, со своего тестика тоже отряхнул пыль, прикрутил новый блочный режим TCP, который с тех времен появился, потестил - 5.8Мбайт/сек в дискард оно бросает. Анализ траффика показывает что банально недостаточные размеры буферов TCP-сокета в моем стеке не дают разогнаться (также реализован механизм предотвращения заторов, но он тут даже нормально накопить статистики не успевает sm.gif). Банально - кидаем 4К в буфер сокета TCP, оно отдает три пакета по 1460+1460+остаток и ждет ACK. Пока ACK нету - буфер полный, новые данные приложение в сокет не пишет - некуда, все стоит. Пришел ACK, буфер почистился - кидаем новые 4К данных, они тут же снова улетают - и опять ждем ACK. Вот так оно кусочками и дергается. Если выкинуть промежуточный свич (там он еще и на зеркальный порт кидает траффик) то пинг уменьшиться, и скорость еще может на пару-тройку процентов вырасти.

Надо сказать, что отправка данных по TCP у меня организована слегка неоптимально - есть копирование с одновременным подсчетом контрольной суммы TCP. Я вот жду LPC18xx - у него EMAC продвинутый, IP/TCP суммы умеет аппаратно считать, под это дело буду также учится делать отправку данных без копирования - по ссылке.
blackfin
Цитата(VslavX @ Jul 27 2011, 21:08) *
Я вот жду LPC18xx - у него EMAC продвинутый, IP/TCP суммы умеет аппаратно считать...

Да ладно, не переживайте..

TCP уже не модно: Cisco to cut 6,500 jobs, sell plant.
Rst7
QUOTE
Я вот жду LPC18xx - у него EMAC продвинутый, IP/TCP суммы умеет аппаратно считать, под это дело буду также учится делать отправку данных без копирования - по ссылке.


Однако я обхожусь без сей аппаратной приблуды. А скорость в два раза выше wink.gif
Rst7
QUOTE
Можно, например, Ethereal'ом протестировать..

Но для полноты картины хорошо бы три-четыре сокета открыть:


Только еще бы выделить чистый траффик по полезной нагрузке, ибо как-то в общую сумму складывать ACK'и и вообще служебную ересь нехорошо. Банальное чтение данных из сокета на большом брате и измерение времени - самое то.
VslavX
Цитата(Rst7 @ Jul 27 2011, 21:24) *
Однако я обхожусь без сей аппаратной приблуды. А скорость в два раза выше wink.gif

Ну, допустим, не в два, а чуть больше чем в полтора wink.gif. А сейчас я поигрался конфигурацией, отключил отладку - и получилось чуть более 70Мбит/сек - 16Мбайт ушло за 1910 мс. При этом потребовалось 31К кода и 16К оперативки. Так что спорить что Ваш стек самый быстрый и маленький - не буду sm.gif.
Вопрос такой - я правильно понял, что источник данных кладет данные прямо в сетевой буфер эзернета в колбек-процедуре. А если требуется повторная отправка, то вызывается событие REGENERATE? Тогда получается что приложение должно само решать вопросы хранения данных у себя до подтверждения их получения удаленной стороной со стороны TCP. То есть - в-общем случае, стек буферов данных у себя не имеет, а просто сваливает проблему на приложение, отсюда и расход памяти собственно в стеке маленький.


Цитата(blackfin @ Jul 27 2011, 20:16) *
Да ладно, не переживайте..

Да я не переживаю wink.gif. Rst7, конечно, выкатил свой очередной шедевр, но он как болид F1 - ездит быстро, но это машинка не на каждый день чтобы на работу добираться.

Цитата(blackfin @ Jul 27 2011, 20:16) *
TCP уже не модно: Cisco to cut 6,500 jobs, sell plant.

Ага, Циска от непрофильного ширпотребного производства избавляется и собирается как раз на "немодном TCP" сосредоточиться (на сетевом оборудовании).
Rst7
QUOTE
Ну, допустим, не в два, а чуть больше чем в полтора


Имеем заявленные мной 90мбит/с = 11Мбайт/с (примерно). А Вы заявляли о 5.8Мбайт/с. 11/5.8=1.9. "Маша - это Маша, а два раза - это два раза" (ЦЭ) biggrin.gif

QUOTE
А сейчас я поигрался конфигурацией, отключил отладку - и получилось чуть более 70Мбит/сек - 16Мбайт ушло за 1910 мс.


А теперь предлагаю вставить dummy net с задержкой пакетов на 2-3мс wink.gif

QUOTE
Вопрос такой - я правильно понял, что источник данных кладет данные прямо в сетевой буфер эзернета в колбек-процедуре. А если требуется повторная отправка, то вызывается событие REGENERATE?


Да, и смысл в этом самый глубокий. Незачем навешивать лишних буферов. Само приложение куда лучше стека знает, как работать с генератором тех данных, которые будут передаваться в сокет. Да, это усложняет написание кода, но увеличивает быстродействие. И в общем зачете уменьшает количество требуемого ОЗУ.

Я уже как-то писал об этом, повторюсь:
QUOTE
У меня в стеке есть три callback'а для режима передачи

SEND - сгенерить новых данных для передачи (не более стольки-то) и вернуть количество сгенеренных данных.
REGENERATE - откатиться на точку последнего подтверждения
ACK - переместить точку последнего подтверждения на сколько-то байт.

CODE
char *out;
char *ack;

SEND(p,max)
{
   len=max;
   memcpy(p,out,len);
   out+=len;
   return len;
}

REGENERATE(p,max)
{
   len=max;
   memcpy(p,ack,len);
   out=ack;
   return len;
}

ACK(len)
{
   ack+=len;
}


В начале out и ack указывают на начало буфера передачи.

На самом деле в реальности там нет memcpy. Это псевдокод для иллюстрации. На самом деле там какой-то циклический буфер, или железка, или еще чего - например, http-сервер в виде машины состояний, который непосредственно печатает в p, а ack и out для него - не более чем состояние.
halfdoom
Цитата(Rst7 @ Jul 27 2011, 13:57) *
Ну вот теперь, собственно, за скорость. По TCP - 90Мбит/с.

Неплохо, у нас тут народ пилил что-то опенсорсное, так выше 68Мбит/c забраться не удалось. Про размеры кода вообще молчу sm.gif.
blackfin
Цитата(Rst7 @ Jul 28 2011, 00:34) *
Только еще бы выделить чистый траффик по полезной нагрузке, ибо как-то в общую сумму складывать ACK'и и вообще служебную ересь нехорошо.

Их никто и не складывает. Данные идут в одном направлении, а ACK'и - в другом.
Измерение скорости в Ethereal'е нужно начинать уже после того как на PC запущено тестовое приложение и созданы сокеты. Это исключает "служебную ересь", связанную с открытием сокетов.
andrewlekar
Цитата
А что, собственно стек не интересен?

Не особо. Мне только обработка прерывания EMAC интересна.
VslavX
Цитата(Rst7 @ Jul 28 2011, 00:28) *
Имеем заявленные мной 90мбит/с = 11Мбайт/с (примерно). А Вы заявляли о 5.8Мбайт/с. 11/5.8=1.9. "Маша - это Маша, а два раза - это два раза" (ЦЭ) biggrin.gif

Сейчас Маша осталась Машей (с внутристековой буферизацией), но при этом 70Мбит/с biggrin.gif.

Цитата(Rst7 @ Jul 28 2011, 00:28) *
А теперь предлагаю вставить dummy net с задержкой пакетов на 2-3мс

Хотите сказать что у Вас скорость не упадет? В случае генерации псевдослучайных данных - вполне может быть, и неудивительно - тут буфера нет. А вот если передавать что-то осмысленно-реальное, то буфер все равно появится - в приложении. И как только емкость канала превысит размер этого буфера - скорость упадет как миленькая. Пример - передача файла с MMC карточки. Можно читать данные с карты в колбеке - но это некамильфо, операция долгая, мало того что делать прийдется ее в прерывании, так еще и все другие сокеты встанут, приемный буфер сети переполнится (flow control нуна доделывать wink.gif) и так далее. Поэтому буферизация тут будет нужна без вариантов.

Цитата(Rst7 @ Jul 28 2011, 00:28) *
Да, и смысл в этом самый глубокий. Незачем навешивать лишних буферов.
Само приложение куда лучше стека знает, как работать с генератором тех данных, которые будут передаваться в сокет. Да, это усложняет написание кода, но увеличивает быстродействие.

Смотря какое приложение. Если относительно простое - то такой подход справляется. А если приложение относительно сложное - то ну его нафиг - добавлять в него еше тисипишные заморочки типа "ну не шмогла, давай повторим". А если надо наложить поверх такого TCP другой протокол со своими фреймами, типа PPTP или iSCSI, то без буферизации тут вешалка.

В-общем, реализация на колбеках любопытная, но вся работа по буферизации свалена на приложение. Если буферизация приложению не нужна - все выглядит интересно, но если приложение делает хоть шаг в сторону, то "вечер перестает быть томным" ©. Режим работы TCP с колбеками несложно добавить и в мой стек, сижу вот думаю, что оно реально может дать на моих задачах - пока выгода неочевидна.
Rst7
QUOTE
Их никто и не складывает. Данные идут в одном направлении, а ACK'и - в другом.


Кстати, по фильтру не заметно. Ибо нет фильтрации. Так что оба направления считаются. Да и Ethereal тут показывает общий траффик - служебная информация (заголовки ETH, IP, TCP) - тоже в сумме.

Это и приводит к числу (Avg. MBit/s), больше 100мбит/с - что естественно, невозможно.

QUOTE
Пример - передача файла с MMC карточки.


А оно-то хоть заявленную скорость даст? Какая ФС используется? Сколько собственно в этой ФС буферов?

QUOTE
Можно читать данные с карты в колбеке - но это некамильфо, операция долгая, мало того что делать прийдется ее в прерывании


Делать ее придется не в самом приоритетном прерывании, так что не беда.

QUOTE
так еще и все другие сокеты встанут, приемный буфер сети переполнится (flow control нуна доделывать ) и так далее. Поэтому буферизация тут будет нужна без вариантов.


Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

QUOTE
А если надо наложить поверх такого TCP другой протокол со своими фреймами, типа PPTP или iSCSI, то без буферизации тут вешалка.


PPTP - это дело такое, там основной траффик GRE/IP, на рассматриваемый случай не ложится, а доп. TCP соединение для управления - ну просто замечательно укладывается на систему с колбеками - там машина состояний, все дела.

iSCSI - тоже песня, блоки с устройства читать. На колбеках как два пальца.
VslavX
Цитата(Rst7 @ Jul 28 2011, 09:39) *
А оно-то хоть заявленную скорость даст? Какая ФС используется? Сколько собственно в этой ФС буферов?
...
Делать ее придется не в самом приоритетном прерывании, так что не беда.

Не в скорости дело, а в том что нельзя надолго заниматься своими делами в колбеке. И не всегда это "надолго" связано с тем что устройство медленное. OK, другой пример. Возьмем Web сервер, только ресурсы его положим не в программную флеш (допустим ресурсы большие, или флешки для программы и так не хватает), а во внешний чип, скажем AT45, подключенную по SPI. И добавим еще одну задачу - какой-нить логгер, который просто собирает свои данные и записывает в эту AT45. Объем AT45 разделим в каком-нить соотношении между логгером и ресурсами Web. И получается что аппаратура SPI+AT45 разделяется между двумя задачами, нужна синхронизация, и вот из-за этой самой синхронизации сетевой колбек банально может надолго задуматься. Конечно, можно сделать "закат солнца вручную" - придумать свою какую-то модель синхронизации, например не ждать в колбеке данные а сразу выходить без посылки и прочее. Но тут кто за что борется - Вы за чистую скорость в отдельно взятом проекте, а я, например, за максимальное наследование кода в кучке разнородных проектов.

Цитата(Rst7 @ Jul 28 2011, 09:39) *
Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

Конечно можно - с помошью буферизации wink.gif. Или есть какие-то другие идеи?
Подход на колбеках мной рассматривался неоднократно, в итоге я от него таки отказался - именно из-за возможной блокировки в колбеке вследствие синхронизации или просто длительной операции. Тот вариант который у меня сейчас есть на прием колбекам несильно уступает (данные вообще нигде не копируются), а по передаче - есть одно копирование (мб и избавлюсь со временем - сделаю реферальную отсылку, но тут выигрыш будет заметным именно при аппаратном полсчете сумм).

Цитата(Rst7 @ Jul 28 2011, 09:39) *
PPTP - это дело такое, там основной траффик GRE/IP, на рассматриваемый случай не ложится, а доп. TCP соединение для управления - ну просто замечательно укладывается на систему с колбеками - там машина состояний, все дела.

А кому нужно управляющее соединение без канала данных? Я сейчас как раз PPTP обдумываю (для девайсов с GPRS весьма и весьма нужен туннель), без буфера ну никак не получится.

Цитата(Rst7 @ Jul 28 2011, 09:39) *
iSCSI - тоже песня, блоки с устройства читать. На колбеках как два пальца.

Угу, щаз biggrin.gif. У меня есть искази инициатор, исказевые PDU без промежуточной буферизации ретрансмиттить будет просто нереально.

Ну в целом, имхо, у Вас получилось удачно - для многих несложных устройств вполне будет работать. Хорошо бы причесать код (по железкам файлы разнести - PHY отдельно, EMAC отдельно, чтобы порты делать), написать документацию (не слишком объемную притом) и придумать хорошее название (типа "Тисипец ™" sm.gif) - многим вполне может быть интересно.
Rst7
Подумал про передачу данных, например, с MMC. Да, для пущего профита желательно в стеке разделить этапы приготовления к передаче нового сегмента и собственно генерацию данных для передачи. Тогда, при необходимости передачи новых данных callback на приготовление запускает чтение с MMC и вываливает с прерывания. Когда от MMC приходит готовность, опять происходит wakeup стека и непосредственно чтение по SPI (ну или 4хбитному интерфейсу) происходит уже в буфер передачи.

Когда дело дойдет до ФС в проекте - сделаю.

QUOTE
А кому нужно управляющее соединение без канала данных?


Так канал данных не через TCP организован. Посему мы его тут не рассматриваем.

QUOTE
Угу, щаз . У меня есть искази инициатор, исказевые PDU без промежуточной буферизации ретрансмиттить будет просто нереально.


Я, конечно, внимательно на досуге покурю соответствующий RFC ради спортивного интереса, но, думаю, Вы преувеличиваете. Если у Вас блочное устройство как источник данных - в любом случае нет проблем с откатом.

QUOTE
Возьмем Web сервер, только ресурсы его положим не в программную флеш (допустим ресурсы большие, или флешки для программы и так не хватает), а во внешний чип, скажем AT45


См. чуть выше, описал идею и метод, пока Вы писали свой пост.

QUOTE
Хорошо бы причесать код (по железкам файлы разнести - PHY отдельно, EMAC отдельно, чтобы порты делать)


Ну для этого нужно разбить примерно пополам файл emac.c. Только смысл? Ибо там того кода с гулькин куй и все прозрачно.

Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.
VslavX
Цитата(Rst7 @ Jul 28 2011, 10:39) *
прерывания. Когда от MMC приходит готовность, опять происходит wakeup стека и непосредственно чтение по SPI (ну или 4хбитному интерфейсу) происходит уже в буфер передачи.

Угу, а если стек занят (ну по другому сокету что-то отдает или удаленный хост задумался, пакет пропал и тд) и этот wakeup задерживается? Причем в общем случае он так нехило на секунды задержаться может. При этом ресурс MMC+SPI заблокирован и никто им больше пользоваться в этот момент не может (ну там логгер чего писнуть хочет).

Еще интересно как тут с приемом. В нормальном стеке с внутренней буферизацией всегда можно четко вычислить свое окно и передать его удаленному хосту. А тут если по колбеку всегда выггребание непонятно как TCP-шный хендшейк себя вести будет. Или таки есть внутренни приемный буфер у сокета?



Цитата(Rst7 @ Jul 28 2011, 10:48) *
Так канал данных не через TCP организован. Посему мы его тут не рассматриваем.

Ага, это я упустил - не дошел до инкапсуляции еще.

Цитата(Rst7 @ Jul 28 2011, 10:48) *
Я, конечно, внимательно на досуге покурю соответствующий RFC ради спортивного интереса, но, думаю, Вы преувеличиваете. Если у Вас блочное устройство как источник данных - в любом случае нет проблем с откатом.

Искази это не только блочные устройства, это транспорт вообще для скази. В случае блочных устройств проблем с откатом до данным нету, но будут проблемы с заголовками, их там достаточно много и разнообразные. И этот поток формируется не из одного источника а из кучи - у каждой выполняемой команды свои нужды. Так что без буфера восстановить такой поток очень непросто.

Цитата(Rst7 @ Jul 28 2011, 10:48) *
Ну для этого нужно разбить примерно пополам файл emac.c. Только смысл? Ибо там того кода с гулькин куй и все прозрачно.
Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.

Вечером прокомментирую - мне щаз убегать нужно, сорри.
prottoss
Цитата(Rst7 @ Jul 27 2011, 19:24) *
Так а по-простому? Прикрутите к подходящему Вашему проекту тестовый сокет, в который скормится метров 100 рандома и вуаля. Я такой использую:
Код
  r=r*1103515245+12345;

Софтик для теста можете у меня из архива взять.
Вчера таки поправил проект под ИАР 5, правда TCP заработал только в полном DEBUG-е. Получил примерно 3500-4500 кбит/с при разных замерах sad.gif. РС с платкой соединен через 4-х портовый модем. А Вы тестировали точка-точка? Сегодня попробую разобраться, че там компилятор в TCP выкидывает. Платформа AT91SAM7X256 + DM9161. Компилировал в ARM-режиме.

Наверное у Вас реально самый быстрый стек sm.gif a14.gif cheers.gif

Цитата(VslavX @ Jul 28 2011, 13:36) *
Цитата
Встанут остальные сокеты - это да, это реальное ограничение. Хотя, конечно, его можно обойти.

Конечно можно - с помошью буферизации wink.gif . Или есть какие-то другие идеи?
Можно, используя RTOS и вместо колбеков флаги. Относительно легко переделывается.
Rst7
QUOTE
Угу, а если стек занят (ну по другому сокету что-то отдает или удаленный хост задумался, пакет пропал и тд) и этот wakeup задерживается? Причем в общем случае он так нехило на секунды задержаться может. При этом ресурс MMC+SPI заблокирован и никто им больше пользоваться в этот момент не может (ну там логгер чего писнуть хочет).


Почему? Задержка будет максимум на время приготовления или обработки пакета. Конечно, надо всегда минимизировать время обработки данных.

QUOTE
Еще интересно как тут с приемом. В нормальном стеке с внутренней буферизацией всегда можно четко вычислить свое окно и передать его удаленному хосту.


И тут всегда можно вычислить. А иногда - например, для разбора HTTP-запросов, оно и нафиг не нужно, все делается на лету.

В общем, при такой архитектуре принципиально иным должно быть построение остального кода. Только тогда будут скорости. Хотя, в общем-то и в обычных bsd-style дизайнах нельзя забывать о том, что, например, очень нежелательно кормить, скажем, функцию send по одному байту. Понятное дело, что есть буферизация, но накладные расходы на вызов будут просто феерические.

А с другой стороны сама по себе bsd-style архитектура не позволяет работать с zero-copy. А zero-copy - это не только в самом стеке, но и еще и в генераторе/приемнике данных. Т.е. проблему скорости надо решать в комплексе.

QUOTE
А Вы тестировали точка-точка?


Свич торчит 16типортовый между девайсом и большим братом.

QUOTE
Можно, используя RTOS и вместо колбеков флаги. Относительно легко переделывается.


Там все-же сложнее ситуация. И опять-же, повторюсь, решать ее надо в комплексе. Обработчик медленный и печальный - уносите его в низкоприоритетную задачу/прерывание (я просто разноприоритетными прерываниями как неким аналогом RTOS пользуюсь), разбивайте его на подзадачи, возможно - добавляйте ему необходимые буфера.
AlexandrY
Цитата(Rst7 @ Jul 27 2011, 13:57) *
Итак, по просьбам трудящихся выкладываю порт своего стека на LPC1768, выдранный из текущего проекта, над которым щас тружусь.


Никаких шансов что это самый быстрый стек.
Еще года 3-и назад выкладывал результаты работы микриумовского стека.
Там без проблем было сделать 98 Mbit/s на 90 MГц процессоре, причем в среде RTOS!

Посмотрел ваш код и вижу вы даже не пытались оптимизировать расчет IP и TCP CRC, нет попыток оптимизировать пересылки в памяти.
Много мест где в программном цикле ожидаются сигналы.
Т.е. на RTOS код не портируется, а попытка исполнения одновременно с вашим TCP стеком других быстрых асинхронных задач, например с той же скоростью обслуживать USB приведет к полной деградации одной из задач.

Кстати называть ваш код "стеком" принципиально не верно. Как раз стек протоколов там не реализован ибо все уровни сведены в одну процедуру.
Т.е. нет элементов стека которые можно было бы несколько раз накладывать друг на друга получая тоннели или менять медиасреду.


Rst7
QUOTE
и вижу вы даже не пытались оптимизировать расчет IP и TCP CRC


Это не так накладно, как кажется. Даже сейчас там чуть менее чем 2 такта на байт, т.е. на полновесный пакет имеем ~30мкс. Конечно, эту оптимизацию можно провести, но это копейки.

QUOTE
нет попыток оптимизировать пересылки в памяти


Там нет больших пересылок. Нечего оптимизировать.

QUOTE
Много мест где в программном цикле ожидаются сигналы.


Это место там одно - ожидание освобождения передатчика. Про это я упоминал, и да, оно поддается оптимизации.

QUOTE
Т.е. на RTOS код не портируется


Не вижу проблем, кстати, с портом под RTOS

QUOTE
а попытка исполнения одновременно с вашим TCP стеком других быстрых асинхронных задач, например с той же скоростью обслуживать USB приведет к полной деградации одной из задач.


Смысл этого комментария мне неясен. Если две задачи в сумме дают CPU load более 100%, то естественно, что вместе они будут давать меньшую производительность каждая.

QUOTE
Кстати называть ваш код "стеком" принципиально не верно.


Не согласен. Стек - он не потому что он в исходнике иерархичен, а от того, что иерархично обрабатывает протоколы.

QUOTE
Т.е. нет элементов стека которые можно было бы несколько раз накладывать друг на друга получая тоннели или менять медиасреду.


Именно это и приводит к потери производительности.
VslavX
Цитата(Rst7 @ Jul 28 2011, 11:14) *
Почему? Задержка будет максимум на время приготовления или обработки пакета. Конечно, надо всегда минимизировать время обработки данных.

Ну я понял Вас так - что когда надо читать данные с MMC в сокет, то вызывается колбек, на MMC посылается команда чтения сектора, и управление возвращается в стек. Потом некто в фоне прокручивает протокол MMC по SPI и по готовности снова пытаеся начать передачу в сокет. То есть - SPI занят, MMC готова давать данные, осталось только получить передающий буфер сети. А тут засада - идет передача по другому сокету, например, и все - аппаратный ресурс SPI+MMC тупо простаивает, потому как нет буфера. C MMC есть еще засада - SDHC карты отдают сектора только целиком, поэтому если REGENERATE будет невыравнен (а он в 99% невыравнен) по границе сектора, то возникает оверхед. В-общем, это я к тому что без буфера можно сделать, но коряво оно будет.

Цитата(Rst7 @ Jul 28 2011, 11:14) *
И тут всегда можно вычислить. А иногда - например, для разбора HTTP-запросов, оно и нафиг не нужно, все делается на лету.

А как тут вычислишь - если приложение всегда забирает данные, и ackno тупо инкрементитцо перед rx колбеком. А если приложение не может забрать данные - допустим пишет оно их в MMC, и темп поступления данных по сети выше темпа записи? Где тут "дульный компенсатор" который регулирует поток входящих данных?

Цитата(Rst7 @ Jul 28 2011, 11:14) *
А с другой стороны сама по себе bsd-style архитектура не позволяет работать с zero-copy. А zero-copy - это не только в самом стеке, но и еще и в генераторе/приемнике данных. Т.е. проблему скорости надо решать в комплексе.

А zero-copy вполне можно и без колбеков сделать - на прием в моей реализации это есть и сейчас, то есть сетевые буфера которые записал EMAC вполне можно отдать приложению в таком же виде, причем такой блочный интерфейс одновременно сосуществует и работает с bsd-style вызовами, эта архитектурная проблема решается без напряга. На передачу по UDP тоже сделан zero-copy - буфер аллоцируется сразу у нужного сетевого драйвера, при этом готовятся все нужные заголовки нижних уровней - с учетом физики, фрагментации и прочего. Но по TCP вот засада - именно из-за ретрансмитта, поэтому пока есть одно копирование. Вы из этой проблемы выскочили при помощи REGENERATE, но не всем такое катит.

Цитата(Rst7 @ Jul 28 2011, 11:14) *
Выносить в отдельный файл работу с EMAC в собственно стеке считаю вредным и бесполезным.

Эту работу можно вынести в отдельные .c/.h файлы так, что генерируемый код останется почти таким же самым - то есть основная идея "сплавить стек в единый кусок" wink.gif не пострадает, а вот портируемость и читабельность сильно возрастет. Соответственно ценен будет для большего количества людей.

Rst7
Кстати, о максимальной пропускной способности.

Имеем максимальный пакет 1518 байт с полезной TCP-нагрузкой 1460 байт. Плюс 96 бит IFG. Итого максимальная скорость в битах в секунду по полезной нагрузке равна 95424836. И те, кто заявляет больше (например - 98 у AlexandrY wink.gif ) привирают.

QUOTE
Ну я понял Вас так - что когда надо читать данные с MMC в сокет, то вызывается колбек, на MMC посылается команда чтения сектора, и управление возвращается в стек. Потом некто в фоне прокручивает протокол MMC по SPI и по готовности снова пытаеся начать передачу в сокет. То есть - SPI занят, MMC готова давать данные, осталось только получить передающий буфер сети. А тут засада - идет передача по другому сокету, например, и все - аппаратный ресурс SPI+MMC тупо простаивает, потому как нет буфера.


Буфер появится как только освободится предыдущий. А точнее, предыдущий передается, текущий - создается. Так что никаких задержек не будет. Если, конечно, вторая задача вменяема и не генерирует данные секундами.

QUOTE
C MMC есть еще засада - SDHC карты отдают сектора только целиком, поэтому если REGENERATE будет невыравнен (а он в 99% невыравнен) по границе сектора


Это надуманная проблема. Свести выравнивание к границе сектора - цена одного пакета. Так что никакого геморроя.

QUOTE
Где тут "дульный компенсатор" который регулирует поток входящих данных?


Крутите окно заранее. В принципе, можно и небольшой буфер использовать, только без фанатизма. Вообще грамотный выбор окна и MTU - залог успеха при ограниченных объемах ОЗУ.

Кстати, а дайте-ка описание SDHC протокола карт, попробую сделать пример реализации - все одно в хозяйстве пригодится.

QUOTE
Эту работу можно вынести в отдельные .c/.h файлы так, что генерируемый код останется почти таким же самым - то есть основная идея "сплавить стек в единый кусок" не пострадает, а вот портируемость и читабельность сильно возрастет. Соответственно ценен будет для большего количества людей.


Я попробую. Хотя, честно говоря, особо не вижу смысла. Стек сей - не для бездумного ^C^V в свой проект. Сначала надо подумать, потом сделать.
AlexandrY
Цитата(Rst7 @ Jul 28 2011, 13:30) *
Именно это и приводит к потери производительности.


Я думаю это на самом деле повышает производительность.
Ваш текст пересыщен прыганьями по двойным указателям.
Потому как в процессе обработки вы работает с разнородными разнесенными структурами.

В настоящей стековой архитектуре обработка на каждом этапе идет на близких данных, эффективнее используется кэш или буфер данных.
Потом менеджеры net буферов не делают монолитный пакет в линейной области памяти, пакет рассредоточен по нескольким буферам с выровненными границами.
А передача делается цепочечным DMA.

Но вообще если вы не смогли достичь физического максимума скорости значит вы нагрузили проц на все 100%.
Т.е. любая дополнительная реальная задача резко уменьшит производительность вашего "стека" и не факт что линейно.

Правильнее было бы действительно продемонстрировать скорость при одновременной работе TCP и файловой системы.
А так это коня в вакууме напоминает.

VslavX
Цитата(Rst7 @ Jul 28 2011, 14:27) *
Буфер появится как только освободится предыдущий. А точнее, предыдущий передается, текущий - создается. Так что никаких задержек не будет. Если, конечно, вторая задача вменяема и не генерирует данные секундами.

Буфер-то в стеке появится, но будет отдан другому сокету, например. И пока это другой сокет не прекратит передачу - MMC будет стоять.

Цитата(Rst7 @ Jul 28 2011, 14:27) *
Крутите окно заранее. В принципе, можно и небольшой буфер использовать, только без фанатизма. Вообще грамотный выбор окна и MTU - залог успеха при ограниченных объемах ОЗУ.

Что значит крутить окно заранее? Это вообще не задача приложения - крутить окно. Вы на примере, пожалуйста, прокомментируйте - нужно писать входящий поток из сокета в MMC, просто - последовательно по секторам, без всякой файловой системы. Как это предполагается сделать и где тут "крутить окно"? Скорость ММС ну пусть будет 512байт/мс. А сети - пусть 10Кбайт/мс.

Цитата(Rst7 @ Jul 28 2011, 14:27) *
Это надуманная проблема. Свести выравнивание к границе сектора - цена одного пакета. Так что никакого геморроя.

Это не надуманная проблема, это следствие необходимости удовлетворять REGENERATE по произвольной границе при отсутствии буфера. И допустим, слать выравнено по границе сектора еще можно (вообще дикость, ну и мы ж за пропускную бьемся, да? 1460 - наше фсе sm.gif), а как это вы заставите удаленный хост подтверждать прием четко по границе сектора? То есть - в любой момент может прийти REGENERATE типа "а дайте-ка мне вот 5 байт из этого сектора и далее".

Цитата(Rst7 @ Jul 28 2011, 14:27) *
Кстати, а дайте-ка описание SDHC протокола карт, попробую сделать пример реализации - все одно в хозяйстве пригодится.

В закромах есть.

Цитата(Rst7 @ Jul 28 2011, 14:27) *
Я попробую. Хотя, честно говоря, особо не вижу смысла. Стек сей - не для бездумного ^C^V в свой проект. Сначала надо подумать, потом сделать.

Это Ваша оценка ценности этого модуля. Еще паре-тройке-десятке человек на форуме интересно обсудить теоретические вопросы. А "трудящимся", по "просьбе" которых это выложено, ценны именно читабельность и портабельность.


Цитата(AlexandrY @ Jul 28 2011, 15:51) *
В настоящей стековой архитектуре обработка на каждом этапе идет на близких данных, эффективнее используется кэш или буфер данных.

Тут вроде бы проблем с таким нету - и данные заголовка влезут в кеш и сам код обработчика тоже влезет в кеш (насчет вот колбеков вопрос открыт, правда). Но хранить MAC-адрес удаленного хоста в TCP-сокете - это готично biggrin.gif. А если нету вообще снизу MAC-адреса (кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?), например PPP вместо эзернета? А если несколько интерфейсов, один с эзернетом, другой с PPP, куда бедному TCP-сокету податься? biggrin.gif
Rst7
QUOTE
Что значит крутить окно заранее? Это вообще не задача приложения - крутить окно.


То и значит. Приложение знает, чего происходит у него, а у сферического стека в вакууме один способ - буферизация. В условиях недостатка ОЗУ в микроконтроллерных применениях это единственный способ - смычка города с деревней более глубокое взаимодействие приложения и стека.

QUOTE
Как это предполагается сделать и где тут "крутить окно"? Скорость ММС ну пусть будет 512байт/мс. А сети - пусть 10Кбайт/мс.


Для таких скоростей проще выставить окно в 512 байт и закрыть вопрос. Получили пакет - запустили запись. По готовности - отправили Window Update. Все. Если хочется достичь теоретической производительности в данном случае - надо сделать буфер на один сектор. Это все при условии минимального Round Trip Time.

QUOTE
(кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?),


Все в порядке. Хотя и необычно реализовано.
VslavX
Цитата(Rst7 @ Jul 28 2011, 16:33) *
Для таких скоростей проще выставить окно в 512 байт и закрыть вопрос. Получили пакет - запустили запись.

Угу, и еще залезли в s->win и сделали его нулевым, потому как вдруг уйдет ACK с новым ACKNO и удаленный хост вышлет новые данные. Готична.
Цитата(Rst7 @ Jul 28 2011, 16:33) *
То и значит. Приложение знает, чего происходит у него, а у сферического стека в вакууме один способ - буферизация.

Угу, и еще достаточно много случаев когда приложение от буферизации никуда не денется, и все равно будет решать эту проблему. Попутно оно еще будет решать кучу проблем протокола типа "прикрутить окно" и требовать проверки-отладки при изменении сетевого окружения - конфигурации активных сокетов, скорости линка, смены среды передачи и т.д. Н-е-е-е-т, ну его нафиг - написание таких приложений.
halfdoom
Цитата(VslavX @ Jul 28 2011, 16:03) *
Но хранить MAC-адрес удаленного хоста в TCP-сокете - это готично biggrin.gif. А если нету вообще снизу MAC-адреса (кстати, а как тут с примитивной маршрутизацией - хотя бы на gw, есть такое?), например PPP вместо эзернета? А если несколько интерфейсов, один с эзернетом, другой с PPP, куда бедному TCP-сокету податься? biggrin.gif

Возможно я не прав, но реализация протокола от Rst7 заточена под вполне конкретное применение. Это позволяет выжать максимум скорости для данной реализации. Отсюда и MAC, и коллбэки, и не совсем четко разнесенная по уровням обработка. Но если устройство соответствует ТЗ, то это абсолютно не важно.
Rst7
QUOTE
Угу, и еще залезли в s->win и сделали его нулевым, потому как вдруг уйдет ACK с новым ACKNO и удаленный хост вышлет новые данные. Готична.


А как еще? Именно так. Только бояться не надо, ничего сложного.
VslavX
Цитата(halfdoom @ Jul 28 2011, 17:24) *
Возможно я не прав, но реализация протокола от Rst7 заточена под вполне конкретное применение. Это позволяет выжать максимум скорости для данной реализации. Отсюда и MAC, и коллбэки, и не совсем четко разнесенная по уровням обработка. Но если устройство соответствует ТЗ, то это абсолютно не важно.

А никто и не спорит - именно "заточенная" реализация, при соблюдении ряда условий и ограничений вполне имеет право на жизнь. А обсуждение - оно на то, если кто будет применять - чтобы сразу осознавал, на что подписывается.


Цитата(Rst7 @ Jul 28 2011, 17:25) *
А как еще? Именно так. Только бояться не надо, ничего сложного.

Угу, для Вас несложно, для меня несложно, а для человека, незнакомого с протоколом TCP - вполне себе может быть проблемой.
Rst7
QUOTE
а для человека, незнакомого с протоколом TCP - вполне себе может быть проблемой.


Так надо тогда профессию сменить на грузчика. А нам, профессионалам, денег будет больше.

QUOTE
Возможно я не прав, но реализация протокола от Rst7 заточена под вполне конкретное применение. Это позволяет выжать максимум скорости для данной реализации.


Именно. Более того, оптимальный стек с ppp-транспортом должен строиться по другим принципам.

Более того, все забывают о том, что ресурсов в притык. Если флеша еще хватает с головой, то с ОЗУ - крепкие напряги. А ведь TCP-стек в устройстве - это не конечная цель, а всего лишь некая подсистема для обеспечения работы основного функционала. И она должна быть экономичной по ресурсам.
blackfin
Цитата(Rst7 @ Jul 28 2011, 18:52) *
Более того, все забывают о том, что ресурсов в притык. Если флеша еще хватает с головой, то с ОЗУ - крепкие напряги.

Ага, вот тут и встает наш Главный холиварный Вопрос: "Что делать, - каждый раз заново переписывать кривой уникальный TCP/IP-стек под каждый новомодный нанопроцессор, или доплатить денег, и купить более подходящий по ресурсам микропроцессор, в который без лишних телодвижений влезет нормальный, полнофункциональный, скоростной TCP/IP-стек + RTOS + Ваше_Любимое_Приложение?"
Rst7
QUOTE
Ага, вот тут и встает наш Главный холиварный Вопрос


Да порочный это подход. Если следовать таким рассуждениям, то вообще нельзя использовать EMAC в контроллерах класса рассматриваемого.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.