1 2 3 4 5 6 7 8 9 10 11 | void * simple_memcpy(void *dst, const void *src, size_t n) { const uint8_t *_src = src; uint8_t *_dst = dst; size_t i; for (i = 0; i < n; ++i) _dst[i] = _src[i]; return dst; } |
3. 分支预测
2. Load/Store地址对齐
3. 集中顺序访问
4. 适当使用non-temporal访存执令
5. 适当使用String指令来加速较大的拷贝
另一种常见的方法是通过对现有代码进行运行时采样分析,得出理论最佳性能,并分析现有代码的缺陷,思考是否存在改进方法。当然,这需要大量的经验和分析,即是用人工代替人工智能。一个DPDK 16.11中的真实案例:花了四周时间进行采样和分析,最后将三行代码的位置进行了移动,得到了1.7倍的性能。这是暴力破解法很难完成的,因为搜索空间实在太大。不过这种看似高端的方法也存在较大的风险,极有可能分析了四周然后不了了之。
至于如何进行采样分析,如perf、vTune等都是非常有效的性能分析工具,其重点不在于工具多样,而在于知道需要什么数据。
此外,通过计算某段memcpy的CPU周期数来评估性能也是不可取的。例如,DPDK中Vhost enqueuer/dequeue函数,不能简单地通过rdtsc来标记memcpy占用了多少个时钟周期,从而判断memcpy的性能。因为目前的CPU都有着非常复杂的流水线,支持预取和乱序执行,这就造成rdtsc测量小粒度时间间隔时误差非常大,虽然加入序列化指令可以进行强制同步,但是这改变了指令流执行顺序并降低了程序性能,违背了性能测试的初衷。同时,经过编译器高度优化的代码,其指令相对于编程语言来说也是乱序的,如果强制顺序编译则会影响性能,其结果也不具有参考价值。此外,一段指令流的执行时间除流水线的理论执行时间外,还包括数据访问带来的延时,通过改变程序的行为很容易让一段代码看起来执行时间更短,而实际上只是将某些数据访问延时转提前或延后而已。这些错综复杂的因素让看似简单的memcpy性能评估变得似乎毫无头绪。
因此,任何优化工作都应该用最终的性能指标来作为评估依据。例如针对OvS在Cloud中的应用,其中的Vhost收发函数大量使用了memcpy,那么针对这个特定的场景,应当以最终的包转发速率作为性能评估标准。
下图展示了一个接近实际应用场景的例子:首先测试基于DPDK 17.02的OvS-DPDK的包转发性能,再通过使用glibc所提供的memcpy替换DPDK Vhost中rte_memcpy得到对比数据。测试结果显示,仅通过使用rte_memcpy加速整个程序中的Vhost收发部分就能提供最大约22%的总带宽提升。
· 虚拟机中使用DPDK testpmd的MAC-forwarding
· OvS-DPDK版本: Commit f56f0b73b67226a18f97be2198c0952dad534f1c
· DPDK版本:17.02
· GCC/GLIBC版本:6.2.1/2.23
· Linux:4.7.5-200.fc24.x86_64
· CPU:Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz
OvS-DPDK编译和启动命令如下:
make ‘CFLAGS=-g -Ofast -march=native’
./ovs-vsctl –no-wait set Open_vSwitch . other_config:dpdk-init=true
./ovs-vsctl –no-wait set Open_vSwitch . other_config:dpdk-socket-mem=”1024,1024″
./ovs-vsctl add-br ovsbr0 — set bridge ovsbr0 datapath_type=netdev
./ovs-vsctl add-port ovsbr0 vhost-user1 — set Interface vhost-user1 type=dpdkvhostuser
./ovs-vsctl add-port ovsbr0 dpdk0 — set Interface dpdk0 type=dpdk options:dpdk-devargs=0000:06:00.0
./ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0x10000
./ovs-ofctl del-flows ovsbr0
./ovs-ofctl add-flow ovsbr0 in_port=1,action=output:2
./ovs-ofctl add-flow ovsbr0 in_port=2,action=output:1
虚拟机中使用DPDK testpmd进行转发,命令如下:
set fwd mac
start
原文:DPDK开源社区