Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: lwIP PPP netif и Ethernet netif HW/SW checksum
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
eisufu
Создаю два интерфейса - один Ethernet (STM32F4x7 Ethernet controller настроен на hardware checksum), другой - PPP over serial. lwIP в lwipopts.h имеет настройки того, как будет считаться контрольная сумма: аппаратно или программно. Конечно, для PPP железо не считает контрольную сумму, интерфейс-то — "виртуальный". Попробовал следующее: везде в коде lwIP, где встречаются CHECKSUM_GEN_* (IP, TCP, UDP, ICMP) добавить код
Код
#if CHECKSUM_GEN_*
  <code>
#else
if ((netif->flags | NETIF_FLAG_POINTTOPOINT) != 0) {
  тот же самый <code>
}
#endif

но сгодилось это лишь для ICMP, TCP уже такое не позволит, так как в функции, содержащие код:
Код
#if CHECKSUM_GEN_*
  <code>
#endif
не передаётся netif *, для которого формируется пакет TCP. Да и вообще пришёл к выводу, что контрольную сумму надо считать централизованно для PPP (на камне есть периферия, которая быстро считает CRC), а для остальных netif - в зависимости от дефайнов CHECKSUM_GEN_*, зависящих от CHECKSUM_BY_HARDWARE.
Масса исходников — сходу не могу понять, где это "узкое место" где проходят все пакеты для каждого из IP, TCP, UDP, ICMP. Каково красивое решение?
scifi
Насколько я понимаю, надо эмулировать поведение аппаратного генератора контрольной суммы. Если я не ошибаюсь, все PPP пакеты проходят через pppifOutput(). Там нужно делать детектирование заголовка (IP, TCP, UDP, ICMP), вычисление и подстановку контрольной суммы. Довольно неприятное занятие, учитывая, что пакет может состоять из цепочки pbuf.
eisufu
Получается, что стоит отказаться от аппаратного расчёта контрольной суммы для Ethernet интерфейса.
scifi
Цитата(eisufu @ Jul 23 2012, 10:26) *
Получается, что стоит отказаться от аппаратного расчёта контрольной суммы для Ethernet интерфейса.

Так проще всего, естественно.
Кстати, чтобы получить заметную выгоду от аппаратного генератора контрольной суммы, нужно иметь ну очень быстрый поток данных. В большинстве случаев скорости бывают достаточно умеренными.
eisufu
Просто в эту железку (потом будет STM32F417) ещё SSL и OPC UA надо будет запихнуть как-то и быть может ещё что-то. Думаю, что уже стоит начинать экономить ресурсы.
scifi
Цитата(eisufu @ Jul 23 2012, 11:12) *
Просто в эту железку (потом будет STM32F417) ещё SSL и OPC UA надо будет запихнуть как-то и быть может ещё что-то. Думаю, что уже стоит начинать экономить ресурсы.

На расчёте контрольной суммы точно экономить не нужно. Один только SSL съест процессорного времени на порядки больше. Экономьте там, где это реально нужно. Иначе все усилия уйдут на экономию, а выхлоп будет нулевой.
eisufu
У железки аппаратная поддержка SSL.
Померю загрузку процессора под ping -f на Ethernet-интерфейсе с и без аппаратного ускорения.
scifi
Цитата(eisufu @ Jul 23 2012, 11:48) *
Померю загрузку процессора под ping -f на Ethernet-интерфейсе с и без аппаратного ускорения.

Объективные данные - это хорошо. Я всегда за то, чтобы не бросаться в оптимизацию, пока нет объективных данных о том, что она реально нужна.
Однако, ping - не очень честный тест. В lwip контрольная сумма для ICMP echo вычисляется как небольшая корректировка суммы входящего пакета. Честнее было бы генерить поток данных (UDP, например) и смотреть загрузку процессора.
eisufu
Сделал диспетчер задач (собственно, оформил FreeRTOS-овский как надо). Если фладить так:
Код
cat /dev/random | nc -u 172.16.0.100 22222
, даже не на открытый порт (например 22221), то падает (через 3-4 секунды с момента старта железки, когда флад идёт, либо во время работы железки, с момента запуска скрипта). Посмотрел в Wireshark — порядка 10к пакетов в секунду отправляется с машины (фреймы по 1514 байт).
Задача udp выгдялит так:
CODE
static
void udpTestTask(void * pvParameters) {
while (inet_setup == 0) {
vTaskDelay(1000 / portTICK_RATE_MS);
}
printf("udpTestTask started\r\n");
struct netconn * conn;
struct netbuf * buf;
err_t err;
(void)err;
conn = netconn_new(NETCONN_UDP);
netconn_bind(conn, IP_ADDR_ANY, 22222);
for (;;) {
err = netconn_recv(conn, &buf);
printf("rcvd length = %u\r\n", buf->p->tot_len);
netbuf_delete(buf);
}
}

lwIP настроен так:
CODE
/**
******************************************************************************
* @file lwipopts.h
* @author MCD Application Team
* @version V1.0.0
* @date 31-October-2011
* @brief lwIP Options Configuration.
* This file is based on Utilities\lwip_v1.3.2\src\include\lwip\opt.h
* and contains the lwIP configuration for the STM32F4x7 demonstration.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/

#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__

/**
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
* critical regions during buffer allocation, deallocation and memory
* allocation and deallocation.
*/
#define SYS_LIGHTWEIGHT_PROT 1

#define ETHARP_TRUST_IP_MAC 0
#define IP_REASSEMBLY 1
#define IP_FRAG 0
#define ARP_QUEUEING 0

/**
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
* use lwIP facilities.
*/
#define NO_SYS 0

/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#define MEM_ALIGNMENT 4

/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE (4*1024)

/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#define MEMP_NUM_PBUF 8
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 2
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 2
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 5
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#define MEMP_NUM_TCP_SEG 16
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#define MEMP_NUM_SYS_TIMEOUT 7


/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE 24

/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE 512


/* ---------- TCP options ---------- */
#define LWIP_TCP 1
#define TCP_TTL 255

/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ 1

/* TCP Maximum segment size. */
#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */

/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF (5*TCP_MSS)

/* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */

#define TCP_SND_QUEUELEN (2* TCP_SND_BUF/TCP_MSS)

/* TCP receive window. */
#define TCP_WND (2*TCP_MSS)


/* ---------- ICMP options ---------- */
#define LWIP_ICMP 1


/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
#define LWIP_DHCP 1


/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255


/* ---------- Statistics options ---------- */
#define LWIP_STATS 0
#define LWIP_PROVIDE_ERRNO 1


/*
--------------------------------------
---------- Checksum options ----------
--------------------------------------
*/

/*
The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
- To use this feature let the following define uncommented.
- To disable it and process by CPU comment the the checksum.
*/
#define CHECKSUM_BY_HARDWARE


#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 0
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 0
/* CHECKSUM_GEN_ICMP==0: Generate checksums by hardware for outgoing ICMP packets.*/
#define CHECKSUM_GEN_ICMP 0
#else
/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 1
/* CHECKSUM_GEN_ICMP==1: Check checksums in software for outgoing ICMP packets.*/
#define CHECKSUM_GEN_ICMP 1
#endif


/*
----------------------------------------------
---------- Sequential layer options ----------
----------------------------------------------
*/
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN 1

/*
------------------------------------
---------- Socket options ----------
------------------------------------
*/
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#define LWIP_SOCKET 0

/*
-----------------------------------
---------- DEBUG options ----------
-----------------------------------
*/

#define LWIP_DEBUG 1


/*
---------------------------------
---------- OS options ----------
---------------------------------
*/

#define LWIP_DNS 1
#define LWIP_ARP 1

/*#define IP_FORWARD 0*/

//#define MEM_LIBC_MALLOC 1

#define TCPIP_THREAD_STACKSIZE configMINIMAL_STACK_SIZE
#define TCPIP_MBOX_SIZE 5
#define DEFAULT_UDP_RECVMBOX_SIZE 2024
#define DEFAULT_TCP_RECVMBOX_SIZE 2024
#define DEFAULT_ACCEPTMBOX_SIZE 2024
#define DEFAULT_THREAD_STACKSIZE configMINIMAL_STACK_SIZE
#define TCPIP_THREAD_PRIO (configMAX_PRIORITIES - 3)

#define TCP_DEBUG LWIP_DBG_ON

#define LWIP_COMPAT_MUTEX 1
#define LWIP_SO_SNDTIMEO 0
#define LWIP_SO_RCVTIMEO 1
#define PPP_SUPPORT 1
#define PPPOE_SUPPORT 0
#define PPPOS_SUPPORT 1
#define PAP_SUPPORT 1
#define CHAP_SUPPORT 1
#define VJ_SUPPORT 1
#define MD5_SUPPORT 1
#define PPP_THREAD_PRIO (configMAX_PRIORITIES - 2)
#define PPP_THREAD_STACKSIZE configMINIMAL_STACK_SIZE
#define PPP_DEBUG LWIP_DBG_ON

#endif /* __LWIPOPTS_H__ */

/******************* © COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

Что ж ей не хватает? Порекомендуйте пожалуйста.
Вот лог:
CODE
0
memory gap = 44952
task count = 7

udpTestTask 0 0%
IDLE 0 0%
counterTask 0 0%
blinkTask 0 0%
Eth_if 12 12%
tcpip_thread 15 15%
Tmr Svc 11 11%

udpTestTask started
1
memory gap = 44952
task count = 7

counterTask 431 <1%
IDLE 760839 76%
tcpip_thread 102363 10%
blinkTask 15 <1%
Eth_if 133518 13%
Tmr Svc 24 <1%
udpTestTask 93 <1%

2
memory gap = 44952
task count = 7

counterTask 987 <1%
IDLE 1215548 61%
tcpip_thread 336998 16%
blinkTask 22 <1%
Eth_if 437917 21%
Tmr Svc 24 <1%
udpTestTask 93 <1%

3
memory gap = 44952
task count = 7

counterTask 1560 <1%
IDLE 1679672 56%
tcpip_thread 568709 19%
blinkTask 29 <1%
Eth_if 735892 24%
Tmr Svc 24 <1%
udpTestTask 93 <1%

4
memory gap = 44952
task count = 7
assertion failed

Выдаёт задачка:
CODE
static
void counterTask(void * pvParameters) {
(void) pvParameters;
for (int i = 0;; ++i) {
printf("%d\r\n", i);
printf("memory gap = %u\r\n", xPortGetFreeHeapSize());
printf("task count = %u\r\n", uxTaskGetNumberOfTasks());
static signed char taskInfoBuf[48 * 8];
vTaskGetRunTimeStats(taskInfoBuf + 0);
printf("%s\r\n", taskInfoBuf);
vTaskDelay(1000 / portTICK_RATE_MS);
if (i == INT_MAX) {
i = 0;
}
}
}


Мало того, что не отвечает на все пакеты, так ещё и assertion failed без пояснений =(.

*во FreeRTOS используется heap_3.c
scifi
Цитата(eisufu @ Jul 23 2012, 15:47) *
Мало того, что не отвечает на все пакеты, так ещё и assertion failed без пояснений =(.

Дык радоваться надо, что assertion failed! С этого места и надо начинать копать: какое условие нарушилось и почему. Постепенно станете экспертом по lwip и будете такие баги отлавливать за 5 минут :-)
eisufu
Ладно). Что-то я видать совсем обнаглел. Буду погружаться с головой...
eisufu
Утверждение не выполнялось в pbuf_free — нельзя передавать NULL аргументом, а вызывалась pbuf_free из ethernetif.c:ethernetif_input, которая изменена в соответствии с :
CODE
void ethernetif_input( void * pvParameters )
{
struct pbuf *p;

for( ;; )
{

if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
GET_NEXT_FRAGMENT:
p = low_level_input( s_pxNetIf );
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
if (p != NULL) {
pbuf_free(p);
p = NULL;
}
}
else
{
xSemaphoreTake(s_xSemaphore, 0);
goto GET_NEXT_FRAGMENT;
}
}
}
}

от себя добавил только строку "if (p != NULL) {" стабильно держит напор скрипта (Lua):
CODE
local socket = require('socket')

local client
client, err = socket.udp()
if err then
error(err)
end
local rport = 22222
local raddress = "172.16.0.100"
_, err = client:setpeername(raddress, rport)
if err then
error(err)
end
local MAX_PAYLOAD_SIZE = 1472
local payload = string.rep('@', MAX_PAYLOAD_SIZE)
local n = 0
while true do
_, err = client:send(payload) -- never blocks
if err then
print(err)
else
n = n + 1
print(string.format('%d', n))
end
end

кстати
Код
cat /dev/random | nc -u 172.16.0.100 22222

не работает как надо, так как UDP датаграммы с payload больше 1472 - фрагментируются (и не успевают собраться). Нагрузка на процессор была ~54%. Теперь выдаёт >>90% c CHECKSUM_BY_HARDWARE:
Код
udpTestTask             2530110         7%
counterTask             26552           <1%
IDLE            1871340         5%
blinkTask               319             <1%
tcpip_thread            13769936                38%
Eth_if          17729671                49%
Tmr Svc         24              <1%
scifi
Цитата(eisufu @ Jul 24 2012, 09:57) *
Утверждение не выполнялось в pbuf_free — нельзя передавать NULL аргументом, а вызывалась pbuf_free из ethernetif.c:ethernetif_input, которая изменена в соответствии с ...

Как и следовало ожидать: накосячил пейсатель драйвера. Кто автор? Пошлите ему лучики благодарности.
Кстати, весьма вероятно, что этот драйвер - не более чем демонстрация, и серьёзно не тестировался. Легко могут быть и другие баги.

Update:
Кстати, я недавно написал свой драйвер для STM32 Ethernet MAC и uIP. Получилось всего 200 строк. Для lwip должно быть аналогично. Возможно, проще отказаться от чужого драйвера и сделать свой.
eisufu
иметь бы опыт или требования, наводящие на правильный путь, а то бы и пример сгодился альтернативный имеющемуся?)

* "в соответствии с :" — это я про st.com

тестирую запрос-ответ:
CODE
local socket = require('socket')

local client
client, err = socket.udp()
if err then
error(err)
end
local lport = 22222
local laddress = "172.16.0.1"
_, err = client:setsockname(laddress, lport)
if err then
error(err)
end
local rport = 22222
local raddress = "172.16.0.100"
_, err = client:setpeername(raddress, rport)
if err then
error(err)
end
local MAX_PAYLOAD_SIZE = 1472
--local payload = string.rep('@', MAX_PAYLOAD_SIZE)
local payload = ''
for i = 1, MAX_PAYLOAD_SIZE do
payload = payload .. string.char(math.random(0, 0xFF))
end
local n = 0
while true do
--[[
--stalls
local payload = ''
for i = 1, MAX_PAYLOAD_SIZE do
payload = payload .. string.char(math.random(0, 0xFF))
end
]]
_, err = client:send(payload) -- never blocks
if err then
print(err)
else
n = n + 1
print(string.format('send # = %d', n))
end
dgram, err = client:receive()
if dgram then
print(string.format('rcvd size = %d', #dgram))
else
print(err)
end
end

железка выдаёт в обменах/с (возвращает pbuf, который приняла без изменений):
CODE
664.010620
663.129944
664.451843
664.231140
664.010620
663.790222
663.790222
664.231140
663.570007
663.570007
662.471008
662.690552
662.690552
663.790222
664.010620
663.790222
664.010620
664.231140
663.349915
663.570007
663.129944
663.129944
663.349915
664.010620
663.349915
663.570007
663.129944
663.349915
663.790222
664.010620
663.570007
659.630615
661.157043
664.451843
663.570007
663.129944
663.790222
664.451843
663.129944
663.570007
664.231140
664.451843

что-то около 8Mbit/s в каждую сторону. Для железки 168МГц — сносно?

1.3мс реакция (в Wireshark-е смотрел). У компа - 0.2мс рекация.

Код
658.544617 0
658.111206 0
658.544617 0
658.544617 0
656.598816 0
655.307983 0
656.383301 0
654.878845 0
657.030212 0
656.383301 0
658.761536 0
— с закомментированной CHECKSUM_BY_HARDWARE в lwipopts.h
Разница в 1%~. Действительно разницы нет HW или SW checksum.
scifi
По скорости ничего не смогу посоветовать, так как мне разгонять стек никогда не приходилось.
Посмотрел на код драйвера: это какой-то ад. 2700 строк там, где и в 270 можно уложиться.
Прикладываю свой драйвер для uIP. Пара пояснений:
- Для приёма статически выделен набор буферов (32 штуки по 256 байт). В lwip принято выделять их динамически из специального пула. Соответственно, код будет несколько сложнее, так как будет учитывать возможность исчерпания памяти. Дело в том, что в lwip принятые пакеты будут сидеть в этих буферах до тех пор, пока приложение, обрабатывающее принятые данные, не освободит эти буферы. Я делал драйвер для ColdFire, где это как раз реализовано.
- Принятый пакет копируется из вышеупомянутых буферов в единый буфер пакета (есть такой в uIP). В lwip буферы с принятыми данными передаются наверх без копирования (zero-copy receive). Опять же, можете подсмотреть в драйвере для ColdFire.
- Отправка сделана из единого буфера пакета. Если использовать такой подход в lwip, то нужно иметь статически выделенный буфер и перед отправкой копировать туда содержимое пакета из цепочки pbuf. На самом деле можно сделать zero-copy transmit (должно работать быстрее, но это несколько сложнее).
- Драйвер ждёт окончания отправки пакета. При интенсивном обмене так можно потерять кучу процессорного времени. Можно реализовать схему без ожидания, но это несколько сложнее.
- Как всё это хозяйство подружить с ОСью (семафоры и т.д.), я не знаю, так как мне это не было нужно.
eisufu
Спасибо
VslavX
Цитата(eisufu @ Jul 24 2012, 12:36) *
что-то около 8Mbit/s в каждую сторону. Для железки 168МГц — сносно?

Маловато будет. Сегодня закончил разработку драйвера для EMAC STM32Fxxx, с опциональной/отключаемой поддержкой аппаратных сумм - сам драйвер более 4 тыс строк, с использованием RTOS. На F207@120МГц результаты такие (поток в одну сторону, iperf-ом мерялось):
С отключенными суммами (скорость указана в "полезных" байтах TCP-соединения, теоретический предел порядка 96 мбит/сек):
- прием от PC - 95.7 мбит/сек, загрузка процессора 77 процентов (23 в IDLE остается еще)
- передача на PC - 87.8 мб, загрузка процессора 59 процентов (41 в IDLE)
С включенными аппаратными суммами:
- прием от PC - 95.7 мбит/сек, загрузка процессора 55 процентов (45 в IDLE)
- передача на PC - 88.4 мб, загрузка процессора 51 процентов (49 в IDLE)

Цитата(eisufu @ Jul 24 2012, 12:36) *
Разница в 1%~. Действительно разницы нет HW или SW checksum.

Как показывают приведенные цифры - заметная разница вылазит только на относительно больших скоростях. Ваши потоки на порядок меньше, соответственно и разница тоже на порядок меньше (22 процента разделить на 10 - пару процентов и выходит). Справедливости ради надо заметить, что я обломался с написанием обработки специфических ошибок DMA передатчика и в обоих случаях (с суммами и без) контроллер работает в режиме Store-And-Forward, этим я объясняю недостижение передатчиком теоретического максимума в 96 мбит/сек.
Rst7
QUOTE (VslavX @ Jul 24 2012, 21:52) *
Маловато будет. Сегодня закончил разработку драйвера для EMAC STM32Fxxx, с опциональной/отключаемой поддержкой аппаратных сумм - сам драйвер более 4 тыс строк, с использованием RTOS. На F207@120МГц результаты такие (поток в одну сторону, iperf-ом мерялось):
С отключенными суммами (скорость указана в "полезных" байтах TCP-соединения, теоретический предел порядка 96 мбит/сек):
- прием от PC - 95.7 мбит/сек, загрузка процессора 77 процентов (23 в IDLE остается еще)
- передача на PC - 87.8 мб, загрузка процессора 59 процентов (41 в IDLE)
С включенными аппаратными суммами:
- прием от PC - 95.7 мбит/сек, загрузка процессора 55 процентов (45 в IDLE)
- передача на PC - 88.4 мб, загрузка процессора 51 процентов (49 в IDLE)


Я смотрю, зацепил я Вас в той теме со стеком. Цифры у Вас явно выше тогдашних, поздравляю sm.gif
scifi
Цитата(VslavX @ Jul 24 2012, 22:52) *
Сегодня закончил разработку драйвера для EMAC STM32Fxxx, с опциональной/отключаемой поддержкой аппаратных сумм - сам драйвер более 4 тыс строк, с использованием RTOS.

Что иллюстрирует следующую мысль: чтобы выжать из железа все соки, надо попыхтеть. Если эти 100 Мбит на практике не нужны, то лучше направить свою энергию в более конструктивное русло.
VslavX
Цитата(Rst7 @ Jul 24 2012, 22:00) *
Я смотрю, зацепил я Вас в той теме со стеком. Цифры у Вас явно выше тогдашних, поздравляю sm.gif

Ну не то чтобы зацепили, но критично на свой код посмотреть заставили sm.gif



Цитата(scifi @ Jul 24 2012, 22:04) *
Если эти 100 Мбит на практике не нужны, то лучше направить свою энергию в более конструктивное русло.

TCP/IP стек - это универсальный кубик, его можно применить в любом проекте, не ограничивая себя теми,
где "эти 100 Мбит на практике не нужны". Например этот же "кубик" у меня стоит в проекте где и гигабита маловато.
Rst7
QUOTE
но критично на свой код посмотреть заставили


Уже польза.
eisufu
Цитата(VslavX @ Jul 25 2012, 00:52) *
iperf-ом мерялось

Сложно серверную сторону на железе поднять?

стек вы реализовывали или готовый использовали?
VslavX
Цитата(eisufu @ Jul 25 2012, 07:35) *
Сложно серверную сторону на железе поднять?

Несложно, клиентскую тоже несложно. Если нужен сервер - то ждете соединение (listen), принимаете его (accept) и на новом TCP соединении просто осуществляете прием с отбрасыванием всех поступивших данных (естественно на уровне приложения, а не стека), при желании измеряете текущую скорость на стороне сервера, когда соединение закрывается - цикл можно повторить. Никаких специальных данных в потоке iperf не требует.

Цитата(eisufu @ Jul 25 2012, 07:35) *
стек вы реализовывали или готовый использовали?

Реализовывал свой, ничего из готового на тот момент не устраивало.
eisufu
Цитата(VslavX @ Jul 25 2012, 10:43) *
Реализовывал свой, ничего из готового на тот момент не устраивало.

Какие протоколы? Какие сложно реализовать?
VslavX
Цитата(eisufu @ Jul 25 2012, 08:52) *
Какие протоколы? Какие сложно реализовать?

Сложность понятие относительное, зависит от того какие опции протоколов нужны и от общей архитектуры. Если нужны только ARP/IP/ICMP/UDP без особых наворотов (без IP-опций, без фрагментирования, не заморачиваясь с фичами типа zero-copy) то можно даже не напрягаться и взять уже что-то готовое. Но мне был нужен минимальный комплект ARP/IP/ICMP/UDP/TCP/DHCP/AutoIP/DNS/HTTP/SSDP, да в разные проекты, да на долгую перспективу, да endainess-portable, да на работе вытерпели (читать - дали время, повезло мне) - поэтому решил сделать свой.
На 2008-ой год, когда писалась основная часть, изучал многие готовые стеки (uIP, lwIP, Niche, ka90, tinet, OpenTCP) . На мой взгляд самый внятный это lwIP. Поэтому если свой стек нет возможности писать - то я бы остановился на lwIP, тем более что его в последнее время развивать стали.
eisufu
Цитата(VslavX @ Jul 25 2012, 13:46) *
решил сделать свой

Уверен: великолепный опыт. Но думаю хотя бы PPP реализовывать самому - сложное занятие, так что выбираю lwIP.
Интересно, каким образом близкие к 100Mbit/s выжимали из STM32F4x7 из lwIP... Кто-нибудь может поделиться опытом? Очень интересно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.