I have spent hours googling on this. As usual one digs up a vast number of forum and usenet posts, mostly with no clear conclusions. Some people are trying to optimise
two session performance. I realise there is no optimal config, but there can be really bad ones and I want to make sure I don't have one of those.
This project was set up by someone else. It uses the ST port of LWIP and FreeRTOS.
What I am after is the case of optimising a
single connection. Multiple sessions should still work but perhaps slowly; that's fine. The constraints are
- minimising memory usage (currently ETH is a total of ~30k and I would like to shave 10k off that).
- the ETH RX is
polled from an RTOS task, at say 100Hz, not interrupt-driven (done for simplicity, and protection from an accidental or deliberate DOS situation), so maybe we need more RX buffers than usual, although 1 MTU at 100Hz is pretty respectable?
LWIP seems to use memory from two pools, defined in lwipopts.h:
- MEM_SIZE (a static block in which LWIP runs some sort of private heap; this was 10k but by inspection of how much of it gets actually used, is now 5k)
- other stuff like TCP_MSS, TCP_SND_BUF, etc and these end up elsewhere
There is also pbuf_pool_size (8x512) and others which take up 7.5k. This may be where the "other stuff" above gets allocated from.
Finally ethernetif.c has packet buffers which take up 12520 bytes but that seems separate from LWIP; there is a module called ETHIF which connects the ST ETH hardware to LWIP.
There is a lot of nontrivial stuff in this. For example I would have expected all packet buffers to be MTU size (1500) and smaller ones will be just wasted, but the code joins together smaller buffers so it still works (3 x 500 byte = 1500) and the 500 byte ones give better performance for smaller packets because you have more buffers.
I also wonder how much data copying goes on. I know the low level ETH stuff uses a dedicated DMA controller, but it looks like there is data copying (using memcpy) higher up, which ought to be done with DMA.
At the risk of creating a post which nobody responds to
I am posting my existing lwipopts.h file below
/**
******************************************************************************
* @file LwIP/LwIP_HTTP_Server_Netconn_RTOS/Inc/lwipopts.h
* @author MCD Application Team
* @brief lwIP Options Configuration.
******************************************************************************
*
*
* 7/7/22 PH MEM_SIZE set to 5k (was 10k). Only ~1.5k is used. ram_heap is 0x20002930.
*
*
*
*
*
*
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/**
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
* use lwIP facilities.
*/
#define NO_SYS 0
/* STM32CubeMX Specific Parameters (not defined in opt.h) ---------------------*/
/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/
/*----- WITH_RTOS enabled (Since FREERTOS is set) -----*/
#define WITH_RTOS 1
/*----- WITH_MBEDTLS enabled (Since MBEDTLS and FREERTOS are set) -----*/
#define WITH_MBEDTLS 1
//NC: Need for sending PING messages by keepalive
#define LWIP_RAW 1
#define DEFAULT_RAW_RECVMBOX_SIZE 4
/*-----------------------------------------------------------------------------*/
/* LwIP Stack Parameters (modified compared to initialization value in opt.h) -*/
/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/
/*----- Value in opt.h for LWIP_DNS: 0 -----*/
#define LWIP_DNS 1
/* ---------- 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. */
// This is used mainly for RAM PBUFs.
#define MEM_SIZE (5*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 5 //10
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 10 //6
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
// This controls how much of the mem_size area gets filled up with http etc packets.
#define MEMP_NUM_TCP_PCB 5 //10
/* 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 8
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#define MEMP_NUM_SYS_TIMEOUT 10
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE 8
/* 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 0
/* 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 (4*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 1
/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255
/* ---------- Statistics options ---------- */
#define LWIP_STATS 0
/* ---------- link callback options ---------- */
/* LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface
* whenever the link changes (i.e., link down)
*/
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_TCPIP_CORE_LOCKING 0
Many thanks in advance for any tips.