本文由 RT-Thread 论坛用户 @出出啊原创公布:https://club.rt-thread.org/as…
前言
很久之前就开始整顿上面的优化项列表了,然而有很多问题钻研不深,一时不敢冒失推出。
前不久,有人在论坛上发问,过后我给的答案比当初少,然而当初列出来的这些也不能保障是全副,当前再做补充吧。
lwip 协定栈、sal socket 形象层应用了很多全局数组变量当作线程栈,能够批改成从内存堆动静申请的内存。
有些性能和个性在嵌入式设施里是用不到的,能够先去掉。
还有的是可有可无的个性,如果想用,也存在优化空间,能够本人实现。
以下阐明不限于 lwip,sal 局部也有波及。
裁剪详解
sal 可裁剪优化项
SAL_INTERNET_CHECK
: 网络检测,应用到了 workqueue。检测原理就是尝试连贯 “link.rt-thread.org::8101″,发送检测数据。
这个或者能够去掉检测,或者换成自家服务器。#define SAL_SOCKETS_NUM 4
: 这个可能是反对创立 socket 的最大数量。RT_USING_NETDEV
: 网络接口设施,没有终端操作的状况下能够优化掉。其中,NETDEV_USING_IFCONFIG
NETDEV_USING_PING
NETDEV_USING_NETSTAT
NETDEV_USING_AUTO_DEFAULT
别离能够独自增删。NETDEV_IPV6
: 目前反对还不遍及的吧,能够关掉,如果须要才开启。
lwip 可裁剪优化项
RT_LWIP_IGMP
组播须要用到的,不必组播可能能够去掉RT_LWIP_ICMP
ping 命令应用的协定,没有 ping 也不须要这个协定。RT_LWIP_DNS
局域网不须要这个,或者说,间接应用 ip 地址进行连贯而不是应用 url 链接地址,能够不应用 dns。RT_LWIP_TCP_WND
tcp 接管窗口,这个应该是申请内存大小。能够适当减小。不定义就是 1460 x 2 字节RT_LWIP_TCP_SND_BUF
tcp 发送缓存,同上,不定义就是 1460 x 2 字节-
LWIP_NO_TX_THREAD
和LWIP_NO_RX_THREAD
eth 线程,发送一个,接管一个。以下是几个相干宏定义,如果不定义堆栈大小,默认应用 1024#define RT_LWIP_ETHTHREAD_PRIORITY 12 #define RT_LWIP_ETHTHREAD_STACKSIZE 1024 #define RT_LWIP_ETHTHREAD_MBOX_SIZE 8 #define LWIP_NO_TX_THREAD #define LWIP_NO_RX_THREAD
源码里,这部分还有很大优化空间,具体见下文详解。
LWIP_NETIF_STATUS_CALLBACK
和前边的 SAL_INTERNET_CHECK 无关,这里设置网络连接回调。能够告诉应用层连贯上 INTERNET 了。LWIP_NETIF_LINK_CALLBACK
网卡连贯状态,仅示意物理连贯接入网络,有可能是和电脑直连,或者交换机、路由器等等。SO_REUSE
端口复用,这个在组播,而且是 UDP 协定才有用。不须要就定义成 0LWIP_SO_SNDTIMEO
LWIP_SO_RCVTIMEO
LWIP_SO_RCVBUF
这三个,如果 rtconf.h 里没有定义,lwipopts.h 会定义,所以不须要就定义成 0。
其中 LWIP_SO_RCVBUF 接管缓冲,波及到接管缓冲下限。少数状况下不会有影响,只有网络数据多的时候才可能达到这个缓存下限。RT_LWIP_USING_PING
这个和后面的 NETDEV_USING_PING RT_LWIP_ICMP 无关。RT_LWIP_STATS
这是一组 stat 的总开关,具体细节查看 lwipopts.h 文件内的定义。或者勾销 RT_LWIP_STATS 定义,敞开所有 stat 项,或者独自批改 lwipopts.h 文件中某些 stat 定义。- 批改 eth_rx_thread 和 eth_tx_thread,启用 RT_USING_HEAP 后,增加动态创建线程。这两个线程被初始化在 INIT_PREV_EXPORT 阶段。片上内存堆和片外边疆堆初始化注册都在 INIT_BOARD_EXPORT 阶段,能够申请应用动态内存。
erx etx 两个线程
以 etx 为例。ethernetif_linkoutput
函数次要操作如下:
if (rt_mb_send(ð_tx_thread_mb, (rt_uint32_t) &msg) == RT_EOK)
{
/* waiting for ack */
rt_sem_take(&(enetif->tx_ack), RT_WAITING_FOREVER);
}
发送了一个邮箱,而后期待一个信号量。这个信号量从哪儿来?看上面的 etx 线程入口函数。
static void eth_tx_thread_entry(void* parameter)
{
struct eth_tx_msg* msg;
while (1)
{if (rt_mb_recv(ð_tx_thread_mb, (rt_ubase_t *)&msg, RT_WAITING_FOREVER) == RT_EOK)
{
struct eth_device* enetif;
RT_ASSERT(msg->netif != RT_NULL);
RT_ASSERT(msg->buf != RT_NULL);
enetif = (struct eth_device*)msg->netif->state;
if (enetif != RT_NULL)
{
/* call driver's interface */
if (enetif->eth_tx(&(enetif->parent), msg->buf) != RT_EOK)
{/* transmit eth packet failed */}
}
/* send ACK */
rt_sem_release(&(enetif->tx_ack));
}
}
}
etx 期待 ethernetif_linkoutput
的邮件音讯,而后调用 eth 驱动接口函数,实现后开释信号量给 ethernetif_linkoutput
一个应答。
从这里看,用上这个线程,须要额定减少两次 ipc 音讯。
去掉 etx 之后呢?ethernetif_linkoutput
变成上面的样子。
static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
{
struct eth_device* enetif;
RT_ASSERT(netif != RT_NULL);
enetif = (struct eth_device*)netif->state;
if (enetif->eth_tx(&(enetif->parent), p) != RT_EOK)
{return ERR_IF;}
return ERR_OK;
}
与应用 etx 线程惟一不同的是:应用线程时,发送数据操作 eth 驱动都在 etx 线程里进行的;如果去掉,就有可能多个利用线程同时发送数据,呈现多个线程竞争 eth 驱动资源的景象。然而,这个能够通过优化应用层业务逻辑进行躲避。
更多对于不应用 etx 和 erx 线程的批改,请移步我的 gitee 仓库。
本系列提到的所有代码更改曾经提交到 gitee,欢送大家测试
https://gitee.com/thewon/rt_t…