对应路线图:Phase 2 (Day 50-91) | DPDK 24.11.6 LTS | 内核对照 v6.6
工具出处:source/dperf-main/(压测)+ perf 工具链(P0-05 所学)
上一篇:P2-06 实现(下)状态机与 RTO | 下一篇:P3-01 OVS-DPDK 数据面
一句话定位
调优不是玄学,是闭环:perf top 找热点 → 火焰图看调用链 → perf c2c 查伪共享 → 批量化改代码 → dperf 压测验证。每轮只改一个变量。本文是 P2 收尾的方法论 + dperf 实操手册;14.88 Mpps(10G 64 字节线速)是阶段目标,实测数据随调优进度补进 perf-data/P2/07/。
压测工具:dperf 的真实用法
dperf(source/dperf-main/)是百度开源的 DPDK 流量发生器。它的入口流程(src/main.c:56-86)很短:
int main(int argc, char **argv)
{
// ...
if (config_parse(argc, argv, &g_config) < 0) { // main.c:60
return 1;
}
// ...
if (dpdk_init(&g_config, argv[0]) < 0) { // main.c:76
printf("dpdk init fail\n");
return 1;
}
dpdk_run(lcore_main, NULL); // main.c:81
// ...
}命令行只认 -c/--conf 配置文件(config.c:1730)。README 给了一个非常有用的参考系(README.md 实测,100G E810 双口):单核 16.8 Mpps、6 核 105.2 Mpps、12 核 204.6 Mpps;HTTP CPS 单核 400 万。这意味着在 10G 网卡上"单核线速"(14.88 Mpps)是 dperf 远没到极限的工况——压测工具必须比被测对象强,先确认这一点。
flood 压测的真实配置(test/performance/tx-pps/flood-1.conf,全文):
mode client
cpu 0
slow_start 30
tx_burst 128
launch_num 10
payload_size 1
duration 10d
protocol udp
flood
cc 16k
cps 1k
keepalive 1ms
#port pci addr gateway
port 0000:5e:00.1 6.6.234.4 6.6.234.1
# addr_start num
client 6.6.234.4 1
# addr_start num
server 6.6.213.4 1
# port_start num
listen 80 1注意 tx_burst 128:dperf 自己就用大 burst,验证了"批量化是第一优先级"(对照 P1-05 的 ixgbe RDT 攒批与 dpdk_module.c:375 的 tx_burst)。
方法论四步(每步配一条真实命令)
① perf top 找热点:perf top -C 2 -d 1 钉住数据面 lcore 2,看谁烧 CPU。常见三兄弟:rte_eth_rx_burst(说明收包是瓶颈,查 batch 与 mempool cache)、查表函数(说明 hash 太散,见 P2-05)、memcpy(说明拷包太多,该改零拷贝)。
② 火焰图看调用链:perf record -g -F 999 -- ./app + FlameGraph 脚本出 SVG。找"宽度异常"的调用路径——比如状态机 handler 里藏着日志/断言(mTCP 的 TRACE_* 宏链),宽度即成本。
③ perf c2c 查伪共享:perf c2c record + perf c2c report --stats。HitM 高的相邻字段就是伪共享——P1-03 的 RTE_CACHE_GUARD(rte_ring_core.h:116 附近)就是为这类问题准备的。多核下伪共享的杀伤力大于任何算法优化。
④ 批量化改代码:burst 放大(32→128)、ACK 攒批(对照 mTCP ACK_OPT_AGGREGATE,tcp_in.c:924)、批量查表(rte_hash_lookup_bulk_data,rte_hash.h:559)、批量 free mbuf(dpdk_module.c:444-447 的 free 循环是反面教材——rte_pktmbuf_free 有批量版 rte_pktmbuf_free_bulk,热路径少一次循环开销)。每次只改一个,改完回到 ⑤。
⑤ dperf 验证:./dperf -c test/performance/tx-pps/flood-1.conf(对端跑 server 配置),每秒输出长这样(README.md 节选):
seconds 22 cpuUsage 52
pktRx 3,001,058 pktTx 3,001,025 bitsRx 2,272,799,040 bitsTx 1,920,657,600 dropTx 0
ierrors 0 oerrors 0 imissed 0三个数字看三件事:pktRx 是否达到 14.88M × 秒数、dropTx 是否非零(发送侧丢包)、imissed 是否非零(网卡丢包,通常是 burst 太短或 CPU 被抢占)。三者全绿才算数。
为什么目标定 14.88 Mpps
10G 线速小包:10^10 bit/s ÷ (64+12+8) byte ÷ 8 bit = 14,880,952 pps。P1-05 的结论是"内核单核百万级 PPS,DPDK 单核可达线速",P2 的目标就是亲手把这个结论复现到 libmtcp-v3 的 RX 路径上。参考系:dperf README 在 100G 上单核 16.8 Mpps(README.md PPS 表),说明 DPDK 单核收包能力在 10G 上留有 10 倍余量——我们的瓶颈只会在自己的代码里。
🐧 内核对照
同一套 perf 工具看内核侧:perf top -C <软中断核> 会看到 tcp_v4_rcv(tcp_ipv4.c:1999)、__inet_lookup_established(:1803)等——软中断预算(budget)把单核 PPS 锁在百万级,这是 P0-07/P1-05 已经验证过的基线。调优 DPDK 路径时,同一份数据也可以丢进内核对照表:同样的热点,两种解法。
面试 3 问
- perf c2c 报告里 HitM 高说明什么? → 两个核心反复无效化对方的同一 cache line(伪共享);解法是把热点字段拆分到独立 cache line(P1-03 的 RTE_CACHE_GUARD 范式)。
- 为什么压测工具(dperf)必须比被测对象强? → 否则瓶颈在工具上,测出来的曲线是工具的曲线;dperf 单核 16.8 Mpps(README.md)远超 10G 线速 14.88 Mpps,才有资格压测 10G 数据面。
- burst 从 32 加到 128 为什么通常能提速? → 均摊每次 burst 的固定成本(函数调用、描述符回写、寄存器访问);P1-05 的 RDT 攒批(ixgbe_rxtx.c:1965 附近)与 dperf
tx_burst 128是同一原理。
🔧 动手实验
流程:① 建 libmtcp-v3 的 RX-only 最小程序(P2-04/05 的骨架),先跑通 flood 收发;② 按四步法逐轮调优,每轮记录 perf top 采样 + dperf 输出到 perf-data/P2/07/(命名 round-N-*.txt);③ 达到或逼近 14.88 Mpps 后,把同机型上内核 iperf3 的 PPS 基线补进对照表。未达标时的检查清单按 ①②③④ 顺序走一遍,不要在没数据的情况下改代码。
评论 (0)