所以我们的任务是编译一些代码(我们应该把它当作黑盒子),使用不同的intel编译器优化标志(-O1和-O3)以及矢量化标志(-xhost和-no-vec)并观察以下变化:
执行这些优化之后,考虑到编译器为了提高效率而对代码所做的所有更改,我们注意到了执行时间的下降,这是预期的。但是,我们也注意到FPO的数量有所下降,虽然我们知道它是一件好事,但我们不确定它为什么会发生。此外,我们注意到(并且无法解释)L2缓存未命中率的增加(随着优化级别的增加而增加),但缓存访问没有显着增加,并且L3级别几乎没有变化。
根本没有使用矢量化或优化产生了L2缓存未命中率的最佳结果,我们想知道你们是否可以给我们一些见解,以及我们可以用来支持的文档,文献和资源加深我们对这个主题的了解。
谢谢。
编辑:使用的编译器选项是:
更新
虽然整体L2缓存访问量略有下降,但实际未命中率却大幅增加。
使用-0O -no-vec
使用中的挂钟时间:13,957,075
使用-xhost
使用中的挂钟时间:4,465,243
答案 0 :(得分:2)
减少浮点数的数量:
通过优化,编译器可以提升循环,熔丝常数,预计算表达式等常用计算。
增加缓存未命中率:
如果编译器使用矢量化,并且每次都加载一个完整的矢量宽度数据,那么它将总共使用更少的内存负载。但是每当它以预测器没有预料到的方式访问高速缓存行时,它仍然会导致高速缓存未命中。一起,你的负载较少,但触摸的高速缓存行数相同,所以未命中率可能更高。
答案 1 :(得分:2)
对于较少的浮点操作,EOF的答案有一个很好的解释:-ffast-math
样式组合操作,所以我只回答其他部分。
这个问题没有关于使用什么CPU微体系结构的信息,但至少它被标记为intel。
在Intel CPU上,有一些逻辑可以预取到L1,还有更复杂的逻辑可以预取到L2(来自L3或主存储器)。每个核心都有自己的L2,但缓存层次结构的较低级别是共享的,因此它是放置主预取逻辑的明显位置。
如果您的读取速度低于内存带宽限制,则您的负载将达到L2,因为硬件预取器已将这些线路读入L2。 如果预取无法跟上,您将获得L2缓存未命中。
更少的更宽的负载而不是更多的标量负载也意味着缺少%将导致更差的矢量。 (EOF的答案已经提到了这一点)。然而,这种效果并不能解释L2未命中绝对数量的增加,只有(部分)未命中%变化。但是,在查看数据时要记住这一点仍然很重要。
来自英特尔的优化指南(x86标签wiki中的链接),第2.3.5.4节:数据预取:
数据预取到L2和最后一级缓存
Streamer :此预取程序监视来自L1缓存的读取请求,用于升序和降序地址序列....当转发或 检测到后向请求流,预取了预期的高速缓存行。预取缓存 行必须在同一个4K页面中。
- 流传输器可以在每次L2查找时发出两个预取请求。流光可以达到20 加载请求之前的行。
- 动态调整每个核心的未完成请求数。如果没有多少 出色的请求,流光预告进一步提前。如果有很多优秀的 要求它仅向有限责任公司提供预取,并且要求不远。
- 当缓存行远远超前时,它只预取到最后一级缓存而不是L2。这个 方法避免在L2缓存中替换有用的缓存行。
- 检测并维护多达32个数据访问流。对于每个4K字节页面,您可以进行维护 可以维持一个前向和一个后向流。
这是来自Sandybridge部分,但Haswell和Skylake部分没有详细介绍预取的变化。他们说"改进了预取",但可能它是相同的基本设计,只是更好的启发式和/或更好地调整现有的启发式,以及类似的东西。
感谢@HansPassant:他对这个问题的评论使我想到了预备不跟上。