rustup 慢_Rust真的比C慢吗?进一步分析queen微测评

昨天,我在文章里分析了微测评的不可靠的问题,遗留了一点技术细节没有剖析清楚。评论区@王明哲提示了我可以用VTune工具,那我今天就来接着分析一下。

前情回顾

昨天的微测评中,我分别通过在queen.rs中程序开头添加NOP指令和queen.c中多次调用测试函数以及perf分析,证明了差异是由编译结果中被测代码的layout(相关代码在内存中的地址位置)导致的噪音。

今天就利用工具进一步分析layout影响了什么。

还是从加NOP开始

写个脚本,自动分别测试在queen.rs中添加1个、2个...N个NOP,看看对测试结果的影响有没有什么规律。

于是我得结果如下:

把它绘成一个曲线图:queen.rs测试耗时与添加的NOP个数的关系

同样的方法,我们在queen.c的main函数开头添加NOP来得到C语言版的曲线。queen.c测试耗时与添加的NOP个数的关系

可以看到Rust版的均值533和方差177相比C版还要好一些哦!(当然这个同样也不能作为评判语言性能的标准,CPU微架构层的优化太复杂微妙,不能用特例说明问题)

C和Rust两个版本的执行时间均关于插入NOP数以16为半周期大致呈周期性变化,那么这个周期16是什么鬼?看汇编代码发现编译器会自动将循环体对齐到16byte:加9个nop的汇编,Block 2是第一个循环体开始加10个NOP的汇编,Block 2是编译器插入的对齐NOP,原来的Block 2往后挪了16byte变成Block 3

得到线索:本例中,第一个循环体开头对齐到奇数个16byte会得到较好的性能。

用VTune跑跑看

昨天我们已经分析了和cache line对齐无关。Intel 提供了一个工具VTune用来分析app的性能,比perf更准确详尽。那我们VTune工具来跑跑看。取rust的快慢两个版本做对比实验,分别跑出来得到这样两个Summary报告:跑得较快的报告跑得较慢的报告

对比两份报告可以看到,两者的分支预测失败率都高(都还有优化空间),但差异是由红圈圈出的三项导致。涉及两个东西: DSB和MITE。

大致了解了一下这两个东西:intel现代CPU中会将程序的机器指令转换成更细粒度的微指令(uops),主要为了实现指令的乱序执行,MITE就是执行这个转换的引擎,就像一个编译器一样。

由于MITE比较费时费力,新一点的CPU又引入了DSB来缓存转换结果,类似于编译缓存,只不过这个缓存容量可能很小。

那么结合工具再来理解一下,工具中给出了一些注解:DSB Switches

Metric Description

Intel microarchitecture code name Sandy Bridge introduces a new decoded ICache. This cache, called the DSB (Decoded Stream Buffer), stores uOps that have already been decoded, avoiding many of the penalties of the legacy decode pipeline, called the MITE (Micro-instruction Translation Engine). However, when control flows out of the region cached in the DSB, the front-end incurs a penalty as uOp issue switches from the DSB to the MITE. This metric measures this penalty.

Possible Issues

A significant portion of cycles is spent switching from the DSB to the MITE. This may happen if a hot code region is too large to fit into the DSB.

Tips

Consider changing code layout (for example, via profile-guided optimization) to help your hot regions fit into the DSB.

Front-End Bandwidth

Metric Description

This metric represents a fraction of slots during which CPU was stalled due to front-end bandwidth issues, such as inefficiencies in the instruction decoders or code restrictions for caching in the DSB (decoded uOps cache). In such cases, the front-end typically delivers a non-optimal amount of uOps to the back-end.

前面summay里的三项差异的意思我就大致理解为:

DSB Switches: 慢者从DSB拿指令的命中率较低,更多地被切换到MITE现编译了。

Front-End Bandwidth MITE: 慢者花在MITE上的时间较多,MITE较忙。

Front-End Bandwidth DSB: 慢者花在从DSB取指令的时间较多(这个应该是和第一条呼应的?)。

总结下来就是慢的时候DSB命中率低了,更多时间花在了MITE上。

为啥命中率有区别呢?由于DSB缓存的是代码块,所以,这就要看我们比较热的那些块有没有对准到DSB的框框咯。

(5.5补充) DSB有如下限制条件, 不满足条件不能放到DSB中DSB的限制条件

其中最关键的就是32byte对齐,所以才会出现前面的16为半周期,某些热点块移一下落到32中间,再移一下落到边界上,如此反复。

小结

故结论依然是:这种微测评结果是错误的,差异和指令对齐相关,属于噪音,有人编译出C快,有人编译出Rust快,全靠运气看编译器把指令对齐到哪里,不能体现语言的差异。

以上分析基于i7 9700K进行,其它CPU可能不同,也可能有类似机制。关于DSB,我没找到更详细的资料,有误请轻拍。

-------

补充

那么,到底queen测评中原本想测试的数组边界检查有多大开销呢?

我们可以通过VTune查看每条汇编指令占用的时钟周期有多少个,反复查看,只有其中两处边界检查占用了cpu时钟周期:

边界检查总共占用7.2x10^6个时钟周期,而整个测评总共花费5.277x10^9个时钟周期,边界检查占比0.136%。这个占比可以说彻彻底底地被淹没在噪音(10%-20%)当中,几乎可以忽略不计。当然,这么计算也不严谨,但无论如何,当背景噪声远大于测量值的时候,一方面说明实验错误,另一方面也说明了被测指标(边界检查开销)的微不足道。实际工程中有多少场景会care这种远小于CPU噪音的开销呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值