关于Android和Linux千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
千兆以太网应该是我们imx6平台最漂亮的功能之一,它将给众多客户带来更加丰富多彩的梦想。 但最近很多人反映使用Android和Linux在性能上存在很大的差距。现在让我在此进行探索。 同样的硬件,同样的内核,性能却不同,为什么? 在linux下,其数据吞吐量可以达到400Mbps,在JB下,只能达到200Mbps。 从下面的信息我们可以看出它应该与丢帧有关。 root@android:/# busybox ifconfig eth0 eth0 链路封装:以太网 HWaddr 00:04:9F:02:6C:E1 inet地址:192.168.0.100广播:192.168.0.255掩码:255.255.255.0 inet6 地址:fe80::204:9fff:fe02:6ce1/64 范围:链接 上行广播运行多播 MTU:1500 度量:1 RX 数据包:7382672错误:71828 丢弃:789 超限:71828 帧:71828 TX 数据包:4147006 错误:0 丢弃:0 超限:0 载波:0 collisions:0 txqueuelen:1000 RX 字节数:2568845018(2.3 GiB)TX 字节数:284789020(271.5 MiB) 在TCP协议栈中,iperf测试用例涉及三个缓冲区:tcp_mem;tcp_rmem;tcp_wmem。 它们都由三个变量描述,这些变量对 iperf 测试结果有很大影响。 在Linux中,我为它们获取了一个快照: root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_mem 18240 24320 36480 root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_rmem 4096 87380 778240 root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 778240 在 Android 中,我也将它们与以下内容进行比较: root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_mem 9285 12380 18570 root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_rmem 4096 87380 396160 root@sabresd_6dq:/# cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 396160 tcp_mem 变量定义 TCP 堆栈在内核内存管理中的行为方式。第一个值告诉内核低阈值。 第二个值告诉内核从什么时候开始降低内存使用率。第三个告诉内核最多可以使用多少个内存页。 如果达到该值,TCP 流和数据包就会开始被丢弃,直到达到安全水平。 在 tcp_rmem 中,第一个值定义每个 TCP 连接的最小接收缓冲区,并且该缓冲区始终分配给 TCP 套接字。第二个值定义 默认接收缓冲区大小。第三个指定了可以为 TCP 套接字分配的最大接收缓冲区。 在 tcp_wmem 中,还给出了三个变量来描述每个 TCP 套接字的 TCP 发送缓冲区。 我们可以在内核代码中检查这些值是如何产生的。在 kernel_imx/net/ipv4/sysctl_net_ipv4.c 中有一个算法+450。 限制= nr_free_buffer_pages() / 8; limit = max(limit, 128UL); sysctl_tcp_mem[0] = 限制 / 4 * 3; sysctl_tcp_mem[1] = 限制; sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2; /* 将每个插槽的限制设置为不超过压力阈值的 1/128 */ 限制 = ((无符号长整型)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7); max_wshare = min(4UL*1024*1024,限制); max_rshare = min(6UL*1024*1024, limit); sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; sysctl_tcp_wmem[1] = 16*1024; sysctl_tcp_wmem[2] = max(64*1024,max_wshare); sysctl_tcp_rmem[0] = SK_MEM_QUANTUM; sysctl_tcp_rmem[1] = 87380; sysctl_tcp_rmem[2] = max(87380,max_rshare); 从上面的算法中,我们可以看到 tcp_mem、tcp_wmem[2]、tcp_rmem[2] 都与 nr_free_buffer_pages() 相关,nr_free_buffer_pages() 代表 ZONE_DMA 和 ZONE_NORMAL 内可分配的可用 RAM 数量。 所以到这里,我们就能找到Android和Linux之间性能差距的根本原因了。运行不同的操作系统时,可用 RAM 之间存在很大差距。 事实上,在android中,Google已经引入了一种通过属性来调整这些值的机制。 现在我们使用默认的AOSP值,您可以在device/fsl/imx6/etc/init.rc中引用它们。对于wifi和以太网,它们都使用net.tcp.buffersize.wifi。 # 定义各种网络的 TCP 缓冲区大小 # 读取最小值、读取初始值、读取最大值、写入最小值、写入初始值、写入最大值 setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208 setprop net.tcp.buffersize.wifi524288,1048576,2097152,262144,524288,1048576 setprop net.tcp.buffersize.lte524288,1048576,2097152,262144,524288,1048576 setprop net.tcp.buffersize.umts4094,87380,110208,4096,16384,110208 setprop net.tcp.buffersize.hspa4094,87380,262144,4096,16384,262144 setprop net.tcp.buffersize.hsupa4094,87380,262144,4096,16384,262144 setprop net.tcp.buffersize.hsdpa4094,87380,262144,4096,16384,262144 setprop net.tcp.buffersize.hspap4094,87380,1220608,4096,16384,1220608 setprop net.tcp.buffersize.edge4093,26280,35040,4096,16384,35040 setprop net.tcp.buffersize.gprs4092,8760,11680,4096,8760,11680 setprop net.tcp.buffersize.evdo4094,87380,262144,4096,16384,262144 我尝试改变上述值,但不幸的是没有得到明显的改善。嗨,为什么? 那么另一个话题,tcp_mem 和 tcp_rmem 如何在内核中协同工作?在 android 中,我们只有办法调整 tcp_rmem 或 tcp_wmem 设置,而没有办法调整 tc_mem。 以“iperf -c”为例,tcp_rmem将根据千兆以太网时钟的频率进行填充。然后它将 根据tcp_mem的大小重新打包,如果tcp_mem较小,则会触发更多次,如果超过最大值 将会触发丢帧。然后将通过 TCP 启动重新传输。最后,性能就会下降。这就像使用千兆上网但用的是垃圾笔记本一样。 您仍然无法享受千兆以太网的良好性能。 为什么内核在 ipv4 中这样计算 tcp_mem?也许他们考虑的是单一高带宽和多连接之间的平衡。 你可以想象如果我们将 tcp_mem 更改为使用一个很大的值,它可能会导致主板由于内存分配不足而拒绝连接 在 tcp 初始化中。在这里我将给出几种提高我们的Android以太网性能的方法。 在电路板设计阶段扩大内存大小。 我已经通过在我们的 SabreAuto 板上测试再次检查了这一点,该板的内存为 2G,其下载速度可以达到 270 Mbps,而通过 Sabresd 则可达 50Mbps。 尽量使用老版本的android,如果能用ICS,可以放弃JB4.3。与较新的 Android 版本相比,旧版本占用的内存更少,并且会留下更多的可用内存。使用 ICS,我们可以达到 380 Mbps 的下载速度,而在 JB4.3 中,只能达到 210 Mbps。 如果您在非常重要的情况下使用 sabresd 的千兆以太网,那么如果您可以抛出其他内存消耗器(如 GPU),则可以平衡它。我已经检查过,如果我们禁用 GPU,JB4.3 中的性能可以达到 340 Mbps,提高约 50%。 改变tcp_mem算法,扩大其最大值阈值。就像您可以将上面的“sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2”更改为“sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 3”。您可以看到不再出现丢帧现象。或者您也可以参考如何:网络/TCP/UDP 调整来对其进行硬编码。但正如其作者所说,不建议用于支持多个用户或多个连接。因为它可能导致主板由于内存分配不足而拒绝连接。 通过 android 中的以下补丁调整 tcp_rmem 和 tcp_wmem。您将获得双向 320Mbps。但是如果您使用 ifconfig 工具设置静态 ip,您将无法设置这些参数。对于AOSP的框架现在只支持DHCP。对于这种情况,您可以在进行测试之前在控制台中手动回显这些参数。 Gerrit 代码审查 Gerrit 代码审查 更改内核的调度策略配置。 禁用 CONFIG_FAIR_GROUP_SCHED 并且仅启用 CONFIG_RT_GROUP_SCHED 会带来一些增强。 经过上述更改,我已经使用 android4.3GA 在 Sabresd RevC1 上进行了测试,双向速率均可达到390~400Mbps。 回复:关于Android和Linux之间的千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
我也想让客户关注这个主题,以便他们可以分享他们的结果。 顺祝商祺! —马赫什 回复:关于Android和Linux之间的千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Hi Jianzheng, 您能否将此文档留在此审核区域(而非您的私人空间),直到审核过程完成?当文档在自己的空间中,并且没有被限制查看时,社区中的每个人都可以看到该文档。在将文档移至公共社区之前,我们希望从中删除所有审核意见。 谢谢! 授予 回复:关于Android和Linux之间的千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
您能否尝试像我在本文中提供的补丁一样更改tcp_rmem 和 tcp_wmem 的大小? 回复:关于Android和Linux之间的千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Hi, 我们正在使用 Android ICS(3.0.35 内核)开发 i.MX6Q,并且有以下疑问。 1) 您提到,通过使用 Android ICS,您已经实现了 380 Mbps 的下载速度(来自主板的 iperf -c)。我想知道它是否稳定(差异很小)?或者下载时速度是否会出现波动(200~400Mbps范围内)? 2)如果波动结果范围是 200~400Mbps,您知道如何解决这种不稳定性吗? 谢谢! 阿吉斯·PV 回复:关于Android和Linux之间的千兆以太网性能差距 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
我建议您在文档评论中“@提及”您的审阅者(如本文所示),并要求他们成为您的指定审阅者,并将他们引导至此暂存区域的主页以获取审阅者的说明。基本上,他们所要做的就是审查文档,向您提供一些反馈,然后在您做出必要的更改后,他们会重新审查并提交“我同意”的评论。相当简单。
View full article