【嵌入式】记录一次网络转串口透传性能提升的过程
目标:基于STM32F427,验证TCP协议下,波特率在2000000下,1网络转8串口的极限性能。网卡速率100Mbps。
裸测试:不启动串口,纯网络tcp,收到数据后接着send返回,经过测试发现单收速率能到40Mbps左右,收发回环方式单方向速率只能到25Mbps
1.直觉的错误 - 多任务
想当然的考虑到网络一个任务,串口处理一个任务,中间通过消息队列和内存池传递数据。
问题来了,网络接收到数据后就会压入消息队列,因为网速太快(裸接收能到40Mbps,8串口可劲的发也只有16Mpbs),任务消息队列资源很快耗尽,此时就会出现业务层丢包,这是不允许的。
如何阻塞网络任务?或者说如何对网络接收进行降速以匹配消息队列呢?
如果用select+recv的方式进行接收,那么可以根据消息队列大小、内存池大小,对recv要接收的数据长度进行动态指定。但这样的话select会一直返回,不停地进行判断,占用大量CPU时间,会间接导致串口收发性能降低。
并且消息队列的投放、获取也会占用部分CPU时间,为了做到性能极致,最终只保留一个任务即可!
2.新问题 - 还用select吗?
recv可以直接改为非阻塞接收,收到就立即进行串口处理即可。
3.LWIP - 各项参数- 调大!
调大这些个缓冲区(比如TCP_WIND/SEND_BUF/MEM_SIZE/PBUF相关大小等等)好处是啥?
简单说一个,比如调大后,recv就可以一次拿上更多的数据,减少recv拿数据的频次,提高了性能!
4.串口 - 轮询发送orDMA发送?
这里的轮询发送是说while(1)轮询8个串口的DR寄存器,有空闲就发送。DMA是用串口DMA进行发送。
不像是PC的CPU主频很高,由于MCU主频太低,轮询发送会有很多检查操作,占据大量CPU时间。当串口速率非常高的时候,这些检查耗时就会影响很大,改为DMA发送,无需检查太多东西,释放CPU进行更多的处理!
5.速率太快,没法打印?
由于要压榨性能极限,每个cpu指令都非常宝贵,加个打印可就了不得了,直接没法看。那怎么办?
【高速场景下,用IO调试!】
输出IO的高低,接示波器进行查看!可以看到各个部分的耗时、有没有执行!
6.一个发送还是一波发送
上面只说了从网络接收数据,如果从串口收到数据并投递到网络时,这里采用了DMA接收,并投递到该任务,中间加了一个队列。
当从队列取出数据进行发送时,如果一次取一个,性能10Mbps,一次取最多8个,性能15Mbps,有提升。
所以要根据实际情况,一波就发送多个,减少轮询的次数。
7.共享资源加锁?错!
内存池是中断和网络任务的共享资源,必须加锁,怎么加更快?
答:直接开关中断!
__disable_irq();__enable_irq();