在x86上独占访问L1缓存行?

Con*_*ery 4 performance x86 assembly low-level cpu-cache

如果一个64字节的缓冲区被大量读/写,那么它很可能会被保存在L1中; 但有没有办法强迫这种行为?

同样,给一个核心独占访问这64个字节,并告诉它不要将数据与其他核心和内存控制器同步,这样这些64个字节总是存在于一个核心的L1中,无论CPU是否认为它经常被使用.

Pet*_*des 6

不,x86不允许你这样做.您可以使用clfushopt或(在即将到来的CPU上)强制逐出,只需回写而不用逐出clwb,但您不能在缓存中固定一行或禁用一致性.


您可以将整个CPU(或单核?)置于缓存作为RAM(也称为无填充)模式以禁用与内存控制器的同步,并禁用写回数据. Cache-as-Ram(无填充模式)可执行代码.在配置内存控制器之前,它通常由BIOS /固件在早期启动时使用.它不是基于每行的,并且几乎肯定在这里没有实际用处.有趣的事实:离开此模式是其中一个用例invd,它会丢弃缓存数据而不会回写,而不是wbinvd.

我不确定无填充模式是否可以防止从L1d驱逐到L3或其他任何情况; 或者如果在驱逐时只丢弃数据.因此,您只需要避免访问超过7个其他缓存行,这些缓存行是您在L1d中关注的缓存行,或者是L2/L3的等效缓存行.


能够强制一个核心无限期地挂在L1d线上而不响应MESI请求将其写回/共享它会使其他核心容易受到锁定,如果他们曾经触及该线路.很明显,如果存在这样的功能,则需要内核模式.(并且使用硬件虚拟化,需要管理程序权限.)它还可以阻止硬件DMA(因为现代x86具有缓存一致性DMA).

因此,支持这样的功能将需要CPU的许多部分来处理无限延迟,其中当前可能存在一些上限,如果存在这样的事情,则可能比PCIe超时短.(我不写驱动程序或构建真正的硬件,只是猜测这个).

正如@fuz指出的,相干性违章指令(xdcbt)中的溶液试图在PowerPC(在Xbox 360 CPU) ,与从指令的误推测执行灾难性的后果.所以很难实现.


你通常不需要这个.

如果经常使用该线路,LRU更换将保持热.如果它经常以足够的间隔从L1d中丢失,那么在最近的设计中(英特尔自Nehalem以来)它可能会在L2中保持热点,这也是核心和私有的,并且非常快.除了Skylake-AVX512之外,英特尔在CPU上的包容性L3意味着留在L1d也意味着留在L3.

所有这些意味着,对于一个核心大量使用的线路,任何类型的频率都不太可能完全缓存未命中DRAM.因此吞吐量应该不是问题. 我想你可能想要这个实时延迟,其中一个函数调用的最坏情况运行时间很重要.在代码的其他部分从缓存行读取虚拟可能有助于保持热.

但是,如果来自L3缓存中其他核心的压力导致该线路从L3中被驱逐,则具有包含L3的Intel CPU也必须强制驱逐仍然具有热点的内部缓存.IDK是否有任何机制让L3知道线路在核心的L1d中被大量使用,因为这不会产生任何L3流量.

我不知道这在实际代码中是一个很大的问题.L3是高度关联的(如16或24方式),因此在你被逐出之前需要进行大量的冲突.L3还使用更复杂的索引函数(如真正的散列函数,而不仅仅是采用连续的位范围模数).在IvyBridge及更高版本中,它还使用自适应替换策略来减少驱逐触及大量不经常重复使用的数据. http://blog.stuffedcow.net/2013/01/ivb-cache-replacement/.

另请参阅intel core i7处理器中使用的缓存映射技术?


@AlexisWilke指出,对于某些用例 ,你可以使用向量寄存器而不是一行缓存.使用ymm寄存器作为"类似内存"的存储位置.您可以在全球范围内专门为此目的使用一些向量注册表.要在gcc生成的代码中获取此代码,可以使用-ffixed-ymm8或将其声明为易失性全局寄存器变量.(如何通知GCC不使用特定的注册表)

使用ALU指令或存储转发来向/从向量reg获取数据将为您提供有保证的延迟,而不会出现数据缓存未命中.但代码缓存未命中仍然是极低延迟的问题.