尧图精选

Zynq千兆网口跑不满?用iPerf多线程测试彻底解决吞吐瓶颈

🕒 发布时间:2026/9/28 17:51:37 📁 来源:尧图网络
拿到一块Zynq开发板交叉编译好内核、跑通Linux接着就要验证网口性能。结果一条iperf -c 板卡IP下去速度卡在300多Mbps怎么调都上不去。第一反应往往是怀疑PHY芯片、怀疑DMA驱动、怀疑DDR带宽。但我用这类板卡调过很多次有个结论可以提前放在这里Zynq网口速率上不去十有八九不是硬件问题而是单线程测试根本没把CPU用满。板载ARM Cortex-A9本身处理TCP协议栈的能力有限单连接跑不出千兆很正常。这篇内容就是来彻底解决这件事的。我会从瓶颈模型讲起解释为什么单线程测不满然后给出5分钟内跑通iPerf多线程并发测试的完整操作再把我在Zynq上实测踩过、网上教程没写全的坑逐个拆开。最后如果多线程压测之后速率仍然不达标再给你一条从硬件到软件逐层定位的排查链路。接下来全部是实操向内容直接可以作为避坑指南来用。1. 先别急着怀疑硬件三种典型的网口“跑不满”场景常在FPGA和嵌入式Linux开发圈里看到类似的求助帖Zynq板卡通过PS侧GEMGigabit Ethernet MAC接出千兆网口跑TCP传输文件速度只有30~50MB/s于是把问题归到驱动、DMA描述符、PHY寄存器上面。这当然有可能是真故障但更常见的是测试方法本身就限制了结果。1.1 单线程TCP测试天生到不了线速Zynq-7020/7010这类SoCPS侧集成的是双核Cortex-A9主频通常是667MHz或800MHz。Linux网络协议栈的TCP收发路径要经过系统调用、Socket层、TCP/IP处理、软中断、DMA搬运任何一个环节成为瓶颈都会限制吞吐。实测中A9双核在单线程TCP下跑到300Mbps~500Mbps都算正常范围。单线程只有一个连接协议栈处理只集中在一个CPU路径上另一个核帮不上忙速度自然很难再往上走。很多前期调板的人在这个阶段就停止了排查直接下结论说“硬件跑不满千兆”这其实冤枉了板子。1.2 PCIe/USB转千兆网卡测试时的兼容性干扰另一个常见场景是PC端用了USB转千兆网卡或者老式PCIe网卡驱动本身就有性能瓶颈或者网卡不支持硬件校验和卸载、TSO/GSO等特性。PC把自己的瓶颈混入测试链路测出来的数据既不代表板卡上限也不代表PC上限。我自己测试时有个习惯优先用PC主板自带的板载Intel千兆网卡并且先单独测一下PC与PC之间的吞吐作为基准。PC到PC能跑到940Mbps再去测Zynq才说明瓶颈在板卡侧。1.3 iPerf版本和默认参数限制不少工程师下载iPerf后直接缺省参数开跑得到300Mbps后就很疑惑。仔细看版本Windows端装的是iPerf 3.x板卡上交叉编译的是iPerf 2.x两边协议握手直接失败或回退到低效模式又或者TCP窗口默认只有几十KB在RTT较大的局域网环境下根本不够用。这三种场景的共同点是问题并不在网络控制器本身而在于“怎么测”。下一篇我展开说多线程测试为何有效以及它背后的原理理解了这层逻辑之后你就知道该在什么场景下用多少个并发流。2. 多线程测试为什么能压满千兆先看懂Zynq网络瓶颈模型很多人在PC上跑iPerf多线程性能提升不明显就把同样的经验套到Zynq上发现效果也不大。那是因为PC端的CPU性能足够瓶颈往往在别处而Zynq这类嵌入式SoCCPU恰恰是最核心的短板。多线程测速能大幅拉升吞吐正是精准地打在了这块短板上。2.1 CPU协议栈处理路径是最大瓶颈Zynq上的Linux网络路径大致是这样网卡收到数据包后GEM控制器通过DMA把数据搬到内存然后触发中断CPU响应中断进入软中断处理网络协议栈经过IP层、TCP层最终把数据拷贝到用户态Socket缓冲区read()这样的系统调用再把它搬到iPerf进程的缓冲区里。这条路径里中断处理和内存拷贝都吃CPU。当只有一个TCP连接时所有工作都由当前核承担数据包到达越密集CPU被打满得越快吞吐自然上不去。A9核心虽然有双核但单连接情况下Linux不会自动把协议栈负载拆到两个核上另一个核基本空闲。2.2 多并发连接让两颗A9核都动起来iPerf的-P参数表示并行创建N个TCP连接。每个连接都是独立的Socket内核可以同时处理多个Socket上的收发。在多核CPU上网络软中断和Socket处理可以分散到不同的核上两个A9核都被驱动起来瓶颈就从CPU核数变为“CPU总处理能力”。这是嵌入式平台与PC平台最本质的区别。PC桌面处理器跑TCP协议栈时单核能力已经极强多线程带来的提升有限而A9单核能力弱并发多流相当于“众人拾柴”效果立竿见影。以我测过的Zynq板卡为例并发连接数实测TCP吞吐CPU占用特点1350~450 Mbps单核接近打满另一核空闲2650~750 Mbps双核均有负载核间调度频繁4850~930 Mbps双核负载较高接近协议栈处理极限8850~930 Mbps与4线程基本持平CPU已饱和从表格能看到4线程已经能把Zynq的千兆口压到接近上限8线程继续增加并发意义不大。后续做固化测试时我一般固定用4个并发连接。2.3 还要理解940Mbps这个“假上限”很多人看到千兆口跑出940Mbps觉得还没到1000Mbps仍不死心。这里要澄清1000Mbps是物理层线路速率但以太网帧本身有前导码、帧起始定界符、帧间隙这些物理层开销加上TCP/IP包头损耗TCP净荷的理论最大值大约就是940Mbps也就是接近118MB/s。判断Zynq网口是否跑满时要用940Mbps这个“千兆实际可用上限”作参照而不是1000Mbps。跑出900Mbps以上已经可以认为硬件和驱动没有明显问题了。2.4 TCP窗口大小同样影响结果并发连接数之外TCP窗口大小也是一个关键变量。窗口决定“对端发来数据后本端确认之前允许发送的数据量”它必须大于等于带宽时延积BDP才能占满链路。BDP 带宽 × 往返时延RTT局域网内RTT按0.5ms估算1000Mbps带宽对应的BDP约为62.5KB。看起来默认窗口几十KB也够用但实际路由器、交换机排队会产生额外延迟RTT被放大后默认窗口就不够了。因此我推荐在iPerf参数中显式设置-w 256K在Zynq这种平台上该参数能显著改善大流量时的小窗口限速问题。理解到这里接下来可以实际操作了。下面这部分就是那“5分钟”的完整路线。3. 五分钟跑通iPerf多线程测试交叉编译、参数语义、实测对比5分钟不是夸海口。前提是你已经交叉编译环境就绪、Zynq板卡Linux系统已启动、能通过串口或SSH访问板卡终端。这部分我按顺序给出操作步骤并逐一解释关键参数背后的意义。3.1 第一步交叉编译一个静态版iPerf放进板卡Zynq板卡上的Linux文件系统多半是精简版不一定自带宽带的包管理工具更常见的是我们直接把编译好的可执行文件用scp或tftp传到/root目录下运行。为了不再为动态库依赖头疼推荐编译静态版本。我用的是iPerf 2.x系列交叉编译命令如下假设交叉工具链前缀是arm-linux-gnueabihf-请根据你实际使用的工具链替换wget https://downloads.es.net/pub/iperf/iperf-2.1.9.tar.gz tar xvf iperf-2.1.9.tar.gz cd iperf-2.1.9 ./configure --hostarm-linux-gnueabihf \ CFLAGS-static -O2 \ LDFLAGS-static make -j$(nproc)编完后检查一下产物file src/iperf结果里应看到statically linked字样。如果输出仍是dynamically linked说明-static没生效需要检查CFLAGS和LDFLAGS是否被正确传入了 configure。这是新手最容易翻车的地方我后面避坑部分还会再讲。把可执行文件放到板卡上scp src/iperf root192.168.1.10:/root/ chmod x /root/iperf3.2 第二步按“谁做Server谁做Client”决定命令形态iPerf测试链路有方向性两种角色都建议测一遍因为Zynq的收方向和发方向性能不一定对称。场景APC向Zynq发送数据Zynq做ServerPC做Client这种场景验证的是“板卡作为网络接收端的吞吐能力”。板卡端先启动Server/root/iperf -s -p 5001 -i 1PC端启动Client创建4个并发TCP连接测试30秒每秒打印一次结果TCP窗口指定为256KBiperf -c 192.168.1.10 -P 4 -t 30 -i 1 -w 256K场景BZynq向PC发送数据Zynq做ClientPC做Server这种场景验证的是“板卡作为发送端的吞吐能力”。PC端启动Serveriperf -s -i 1板卡端启动Client/root/iperf -c 192.168.1.100 -P 4 -t 30 -i 1 -w 256K这两组顺序都要做。我见过某块板子接收方向能跑到920Mbps发送方向却只有600Mbps原因是发送方向DMA描述符数量配置不足或中断合并参数不合理。只测一个方向很容易漏掉这种不对称问题。3.3 第三步看懂输出并判断是否达标iPerf运行中每秒输出一行汇总信息格式如下[ ID] Interval Transfer Bandwidth [ 3] 0.0- 1.0 sec 28.6 MBytes 240 Mbits/sec [ 4] 0.0- 1.0 sec 29.2 MBytes 245 Mbits/sec [SUM] 0.0- 1.0 sec 114 MBytes 954 Mbits/sec要注意看最后一行[SUM]它才是所有并行流累加后的总带宽。很多新手只盯某个单流的数值看到200多Mbps就误以为没跑满其实总的已经接近950Mbps了。结合我上文的实测参考Zynq这块板子用4线程测速结果可以这样判断950Mbps左右硬件和驱动没有问题收工700~900Mbps仍有优化空间但已算正常范围可查中断绑定、DMA描述符500Mbps以下重点排查驱动配置、PHY协商、CPU调频、网线300Mbps以下考虑硬件异常或基础配置错误3.4 附一键巡检脚本我习惯把常用的测试组合写成一个shell脚本放在板卡上后续每次调整完驱动或DTS参数后直接跑一遍省去反复敲命令。脚本核心逻辑就是轮流执行收发两个方向的4线程测试#!/bin/sh HOST192.168.1.100 PORT5001 echo RX test: Zynq as Server /root/iperf -s -p $PORT -i 1 sleep 1 # 在PC端手动执行 iperf -c 板卡IP -P 4 -t 30 -i 1 -w 256K echo TX test: Zynq as Client /root/iperf -c $HOST -P 4 -t 30 -i 1 -w 256KPC端也可以做一个配套批处理避免来回切换窗口。这些脚本不复杂但在反复调参时非常省事。到这里正常流程已经能让你在5分钟内看到Zynq网口真实的吞吐能力。接下来这部分更关键是那些只让你“跑通”的教程不会讲的坑。4. 实测踩过的五个坑网上教程不会写全的那部分这部分内容全部来自我的实际经历很多问题的排查过程都挺费时间写出来是希望大家别重复踩。4.1 坑一板卡上是iPerf 2PC上是iPerf 3两边连不上这是一个典型到极点的坑。iPerf 2.x和3.x的通信协议不兼容2.x客户端连3.x服务端可能在启动阶段就直接退出也可能出现连接但收不到任何数据的情况。交叉编译时默认拿的是2.x源码而Windows上官网推荐的是3.x两边版本不一致测试直接失败。所以必须统一版本。建议板上用iPerf 2.xPC端也特意装一个iPerf 2.x版本Windows下的2.x版本绿色解压就能用不需要安装。如果确实想用3.x那么板卡交叉编译时也要选择3.x源码并注意3.x版本下-w等参数必须在客户端和服务端的监听套接字均设置时才完全生效更容易踩坑。因此我在Zynq上的首选是2.x。4.2 坑二交叉编译忘加-static部署到板卡后报找不到动态库zynq的根文件系统如果是buildroot或petalinux默认生成通常会包含一些动态库但不一定包含编译iPerf时链接的libm.so.6对应版本。曾有一次我把默认配置编出的iPerf丢到板上运行时直接提示找不到共享库文件最后又回到PC上重新静态编译一遍。静态编译时需要在configure阶段就打好参数./configure --hostarm-linux-gnueabihf \ CFLAGS-static -O2 \ LDFLAGS-static \ --disable-shared \ --enable-static--disable-shared和--enable-static是双保险防止configure脚本自行启用动态库。编译完成后务必用file确认或者直接readelf -d src/iperf | grep NEEDED看看是否有动态依赖。没有任何输出才说明是纯静态版。4.3 坑三只测了一个方向漏掉了收发性能不对称Zynq的GEM控制器在接收方向要处理更复杂的中断和DMA回写逻辑驱动里RX描述符数量、Ring Buffer深度、中断节流参数都会影响接收性能而发送方向相对简单就是DMA从内存取描述符然后交给MAC对外发送。两者性能确实可能不一致。我自己遇到过一块定制板收发同时打数据时吞吐劣化严重但单独测收、单独测发都正常。这种情况只有把双向测试都纳入验证流程才可能发现。常规性能验证必须包含三组数据PC向板卡发送、板卡向PC发送、双向同时传输。双向同时传输的测试可以用iperf -d参数也可以在两端同时各跑一个iPerf实例。4.4 坑四网线质量、交换机端口导致协商不到千兆这是排查环节最容易被忽略的外围因素。随便找一根只有4芯线芯的百兆网线插上去PHY自动协商后就停在100Mbps无论怎么压榨CPU吞吐都不可能超过100Mbps。还有部分老交换机端口强制百兆模式或开启了流控也会干扰测速结果。排查方法ethtool eth0关注Speed字段是否为1000Mb/sDuplex是否为Full。如果协商结果是100Mbps先替换网线和交换端口再看PHY的配置、DTS里phy-mode是否正确Zynq常见的是rgmii-id。直连PC测试时PC网卡也确认一下是否协商到千兆。尽量用超五类及以上规格的成品网线不要用自制压线不标准的线缆。4.5 坑五CPU频繁降频性能测试数值忽高忽低嵌入式Linux默认的CPU调频策略可能是ondemand或powersaveA9会在负载升高时动态调频甚至降到最低频率。网络数据流量大时CPU虽然繁忙但频率调节有滞后性导致测速结果呈现出周期性的“冲高—回落”现象。测试前建议临时切换到performance模式echo performance /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor echo performance /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor如果你的系统没有cpufreq节点说明Kernel配置里没开相关选项那就只能确认一下cat /proc/cpuinfo中BogoMIPS是否稳定。调为performance后再重跑一次多线程测试数值通常会更加平稳。除了调频还要确认板子没有跑额外的后台任务。常见占用CPU的是命令行提示符下的top或调试器、看门狗脚本、日志采集程序。测试前top看一眼CPU idle如果不是95%以上先把无关进程停掉。5. 多线程之后还是不满意按这套顺序逐层查瓶颈如果用了4个并发线程仍然只有500Mbps左右甚至更低那么问题确实需要认真排查。这里给一条从物理层到应用层的排查链路按顺序执行定位效率最高。5.1 第一层确认物理链路协商正常继续用ethtool eth0确认速率和双工模式。我的一个做法是连着执行三次间隔1秒看Speed是否稳定。若疑似物理层丢包可以先查看ifconfig eth0关注RX errors、RX dropped、TX errors、TX dropped字段。如果错误包数量持续增长多半是网线或PHY端接问题。此时也可以强制指定速率模式验证ethtool -s eth0 speed 1000 duplex full autoneg off在Zynq平台上有的PHY不支持自动协商到理想模式强制设置后反而能恢复正常可用作快速定位。但要注意DTS里phy-mode需要与实际PHY接口匹配否则强制设置也会失败。5.2 第二层确认驱动中断是否被CPU核心承接Zynq的双核A9在默认情况下网络中断可能全部落在CPU0上CPU1闲着依然形成单核瓶颈。多线程iPerf改善了一部分但如果中断还是扎堆在同一个核TCP处理路径的上限就受制于单核能力。查看中断分布cat /proc/interrupts找到GEM对应的中断号观察它在CPU0和CPU1上的计数。大部分时间都在CPU0就需要手动做中断亲和性设置echo 2 /proc/irq/中断号/smp_affinitysmp_affinity的2表示只允许CPU1处理3表示允许CPU0和CPU1。设为3后再观察两个核的中断计数是否开始分布。要注意强行把所有中断绑到单个核也不一定好更稳妥的是让系统在测试时自行均衡必要时可以关闭irqbalance服务再观察。5.3 第三层用UDP测试区分协议栈瓶颈和驱动瓶颈TCP测试结果受窗口、拥塞控制、确认机制等多方面因素影响有时不容易定位到具体层。这时可以切到UDP测试UDP没有复杂的拥塞控制更能反映“裸”网络能力。板卡作为Server/root/iperf -s -u -p 5001 -i 1PC作为Clientiperf -c 192.168.1.10 -u -b 1000M -P 1 -t 30 -i 1-b 1000M指示目标带宽为1000M。观察UDP接收端是否有大量包丢失。如果UDP在900Mbps以上且丢包很少说明驱动与DMA层没有大问题瓶颈多半在TCP协议栈路径如果UDP也掉线、丢包严重就要回头查驱动和DMA描述符数量。5.4 第四层调整DMA描述符与中断节流Zynq官方Xilinx Linux驱动中GEM驱动DMA描述符数量、TX/RX Ring Buffer深度对极端吞吐场景有影响。如果你板子跑的是PetaliNux或自己编译的Kernel可以在设备树里调整相关参数或者在内核驱动源码中加大描述符数量。中断节流方面GEM支持中断合并适当延迟中断上报可以降低CPU被打断的频率但过长的合并延迟又会增加单包时延。对纯吞吐测试而言中断合并通常能带来一定提升。这个参数的调整往往需要反复试建议一次只改一个变量并在改完后重跑同一个iPerf测试命令保证对比有效。5.5 第五层设置可接受的性能基线把上面几层都确认后Zynq的千兆网口吞吐到900Mbps左右就是合理的。如果板卡上还跑着业务进程实际可用带宽需要打折比如DDR带宽被内存拷贝大量占用、SD卡读写频繁都会抢占总线。带业务的板卡500~700Mbps可能就已经是符合预期的结果不必强求940Mbps。我在项目交付时都会把这些信息记录成一张性能基线表每一块板卡、每一版驱动都在同样的条件4线程并发、TCP窗口256K、千兆直连、performance模式下验证一遍并将结果归档。这样后续谁提交了“网口变慢”“吞吐下降”的缺陷单我先拉基线表对照能够快速判断是软件变更引入还是硬件损坏。5.6 最后补充一个常见误操作用错Device Tree里的 phy-mode排查过程中容易被忽略的还包括设备树节点中phy-mode这个属性。Zynq的GEM控制器与外部PHY的连接方式可能是rgmii、rgmii-idRGMII with internal delay也可能是gmii。如果配置成rgmii而实际PHY需要rgmii-id则时钟延迟不对虽能连通但性能严重下降还可能伴随偶发丢包。排查手段是查看PHY芯片型号去数据手册确认它和MAC之间是哪种接口模式然后对照设备树里的配置。这类问题非常隐蔽我见过一块板子因为phy-mode字符串少了个-id导致吞吐长时间徘徊在400Mbps左右但网络又不完全不通排查了一整天才定位到设备树配置。说回Zynq这个平台调试网口性能时必须把“CPU作为协议栈处理器”这个角色放在第一位去思考。多线程iPerf测试只是手段核心价值是快速判断网络瓶颈到底在哪一层。如果你按这篇的流程走一遍大概率能从“单线程300Mbps”直接跳到“4线程900Mbps以上”剩下的就是按基线标准收尾了。最后分享一个我的个人习惯每次调完驱动或设备树后都会拿那套固定脚本跑一组数据并把输出贴进项目的changelog里。这个操作不复杂但过几个版本之后回头看能省下大量“是否最近改动导致性能回退”的排查时间。测速这件事稳定可复现比单次跑得高重要得多。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →