Mik*_*ike 13 c intel cpu-architecture linux-kernel cpu-cache
我们正在尝试使用Intel CLFLUSH指令在用户空间中刷新Linux中进程的缓存内容.
我们创建了一个非常简单的C程序,它首先访问一个大型数组,然后调用CLFLUSH来刷新整个数组的虚拟地址空间.我们测量CLFLUSH刷新整个阵列所需的延迟.程序中阵列的大小是一个输入,我们将输入从1MB变为40MB,步长为2MB.
根据我们的理解,CLFLUSH应该刷新缓存中的内容.所以我们期望看到整个阵列的刷新延迟首先在阵列大小方面线性增加,然后在阵列大小大于20MB(这是我们程序的LLC的大小)之后延迟应该停止增加.
然而,实验结果非常令人惊讶,如图所示.数组大小超过20MB后,延迟不会停止增加.
我们想知道如果地址不在缓存中,CLFLUSH是否可能在CLFLUSH将地址刷出缓存之前引入地址?我们还试图在英特尔软件开发人员手册中搜索,但没有找到任何解释,如果地址不在缓存中,CLFLUSH会做什么.
以下是我们用于绘制图形的数据.第一列是以KB为单位的数组大小,第二列是以秒为单位刷新整个数组的延迟.
任何建议/建议都不仅仅是值得赞赏的.
[改性]
以前的代码是不必要的.尽管CLFLUSH具有相似的性能,但它可以更容易地在用户空间中完成.所以我删除了凌乱的代码以避免混淆.
SCENARIO=Read Only
1024,.00158601000000000000
3072,.00299244000000000000
5120,.00464945000000000000
7168,.00630479000000000000
9216,.00796194000000000000
11264,.00961576000000000000
13312,.01126760000000000000
15360,.01300500000000000000
17408,.01480760000000000000
19456,.01696180000000000000
21504,.01968410000000000000
23552,.02300760000000000000
25600,.02634970000000000000
27648,.02990350000000000000
29696,.03403090000000000000
31744,.03749210000000000000
33792,.04092470000000000000
35840,.04438390000000000000
37888,.04780050000000000000
39936,.05163220000000000000
SCENARIO=Read and Write
1024,.00200558000000000000
3072,.00488687000000000000
5120,.00775943000000000000
7168,.01064760000000000000
9216,.01352920000000000000
11264,.01641430000000000000
13312,.01929260000000000000
15360,.02217750000000000000
17408,.02516330000000000000
19456,.02837180000000000000
21504,.03183180000000000000
23552,.03509240000000000000
25600,.03845220000000000000
27648,.04178440000000000000
29696,.04519920000000000000
31744,.04858340000000000000
33792,.05197220000000000000
35840,.05526950000000000000
37888,.05865630000000000000
39936,.06202170000000000000
Run Code Online (Sandbox Code Playgroud)
你想看一下Skylake的新优化指南,英特尔推出了另一个名为clflush_opt的clflush版本,它的版本很弱,并且在你的场景中表现更好.
请参阅此处的7.5.7节 - http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
通常,CLFLUSHOPT吞吐量高于CLFLUSH,因为如上所述和第7.5.6节中所述,CLFLUSHOPT针对较小的内存流量进行排序.CLFLUSHOPT的吞吐量也会有所不同.使用CLFLUSHOPT时,刷新修改的缓存行将比在非修改状态下刷新缓存行的成本更高.CLFLUSHOPT将提供优于CLFLUSH的性能优势,适用于任何相关状态的缓存行.CLFLUSHOPT更适合冲洗大缓冲区(例如大于许多KB),适用于CLFLUSH.在单线程应用中,使用CLFLUSHOPT的冲洗缓冲液可能比使用带有Skylake微架构的CLFLUSH高出9倍.
该部分还解释了刷新修改数据的速度较慢,这显然来自回写惩罚.
至于延迟增加,您是否正在测量超过地址范围所需的总时间并逐条扫描?在这种情况下,即使通过LLC大小,您也会线性地依赖于数组大小.即使行不存在,clflush也必须由执行引擎和内存单元处理,并查找每行的整个缓存层次结构,即使它不存在.
这并没有解释只读图中的膝盖,但确实解释了为什么它没有稳定.
我没有在本地测试以查看热缓存和冷缓存之间的区别,但我确实遇到了以下性能数字clflush:
该AIDA64指令延迟/吞吐量基准测试库列出了单插槽Haswell-E CPU(i7-5820K),其clflush吞吐量为每99.08个周期一个.它没有说明是否重复相同的地址,或者是什么.
因此,clflush即使不需要做任何工作,也不会有任何自由.它仍然是一个微编码指令,没有经过大量优化,因为它通常不是CPU工作量的一个重要部分.
Skylake正准备改变,支持连接到内存控制器的持久内存:在Skylake(i5-6400T)上,测量的吞吐量是:
clflush:每~66.42个圈子一个 clflushopt:每~56.33个圈一个clflushopt当某些线路实际上是需要刷新的脏缓存时,也许更多的是胜利,也许当L3忙于其他核心做同样的事情时.或者他们可能只是希望在对吞吐量做出更大改进之前,尽快使用弱订购版本来获取软件.在这种情况下它快〜15%,这也不错.