|
1
18
有关清除缓存(尤其是在x86上)的相关问题的链接,请参阅上的第一个答案 WBINVD instruction usage . 不,使用纯ISO C++17无法可靠或高效地执行此操作 . 它不知道也不关心CPU缓存。你所能做的就是触摸大量的内存,这样所有其他的东西都会被逐出 1. ,但这不是你真正想要的。(当然,冲洗 全部的 根据定义,缓存效率低下……) CPU缓存管理函数/内部函数/asm指令是对C++语言的特定于实现的扩展。但除了内联asm之外,我所知道的任何C或C++实现都不能提供刷新的方法 全部的 缓存,而不是一系列地址。那是因为 不 这是一件正常的事情。
例如,在x86上,您要查找的asm指令是
我不认为有任何方法可以在x86上的用户空间(环3)中使用它。不像
但是,如果您正在用GNU C或C++编写内核(或在ring0中运行的独立程序),您可以使用
我能想到的唯一原因是,您可能希望进行某种实验,以了解特定CPU的内部结构是如何设计的。因此,具体操作细节至关重要。我甚至不想用一种便携/通用的方式来实现这一点。 或者在重新配置物理内存布局之前在内核中,例如,现在有了一个用于以太网卡的MMIO区域,而以前只有普通的DRAM。但在这种情况下,您的代码已经完全特定于arch。 通常,当出于正确性原因需要刷新缓存时 知道 哪个地址范围需要刷新 . e、 g.在使用DMA的体系结构上写入驱动程序时,缓存不一致,因此回写发生在DMA读取之前,而不会在DMA写入之前进行。(逐出部分对于DMA读取也很重要:您不需要旧的缓存值)。但是x86现在有缓存一致DMA,因为现代设计将内存控制器构建到CPU芯片中,因此系统流量可以在从PCIe到内存的过程中窥探L3。
在驱动程序之外,您需要担心缓存的主要情况是在具有非一致指令缓存的非x86体系结构上生成JIT代码。如果您(或JIT库)将一些机器代码写入
这就是gcc提供
尽管有名字,
当需要刷新某些缓存以确保正确性时,只需刷新一系列地址, 不 通过刷新所有缓存来降低系统速度。
出于性能原因,故意刷新缓存几乎没有意义,至少在x86上是这样
. 有时,您可以使用污染最小化预取来读取数据,而不会造成太多的缓存污染,或者使用NT存储来写缓存。但是做“正常”的事情然后
没有一条轻量级指令被设计为性能提示,就像
在x86上,您可以在用户空间中执行的唯一缓存刷新是
有一个Intel内部
有一个Linux系统调用包装器可移植地逐出一系列地址:
我认为Linux系统调用不会暴露
最近的x86扩展引入了更多的缓存控制指令,但仍然只能通过地址来控制特定的缓存线
. 用例用于
non-volatile memory attached directly to the CPU
例如
Intel Optane DC Persistent Memory
. 如果要提交到持久性存储而不使下一次读取变慢,可以使用
看见
https://danluu.com/clwb-pcommit/
,但请注意
无论如何,这是一种与现代CPU相关的缓存控制。无论您在做什么实验,都需要在x86上使用ring0和assembly。 脚注1:触及大量内存:纯ISO C++17
你
能够
可能会分配一个非常大的缓冲区
此外,请注意使用实际
做一些无法优化并涉及大量内存的事情(例如,带有
|
|
2
1
答案是
不
,没有标准的C++方法可以做到这一点(即使使用一些编译器内部函数)。
GCC
有
正如Johan所评论的,x86-64有一个特权指令来执行您想要的操作,但是
在Linux上,您可以(也许)使用 cacheflush(2) Linux特定的系统调用。我从未使用过它,也不知道它是否在x86-64上实现。 顺便说一句,你不应该在程序上推理,而应该在 processes . 每个都有自己的 virtual address space . 你的问题缺乏动机。如果您关心微基准测试,请注意,内核调度器可以在任意机器代码指令下重新调度线程或进程,并将其移动到其他一些核心(但请注意 processor affinity ).
不 optimizing compilers 正在重新排序和重新调度机器代码指令,并且经常混合与 不同的 C++语句。他们可以在编译时进行一些计算。了解更多有关 as-if rule . 参见CppCon 2017演讲:Matt Godbolt âWhat Has My Compiler Done for Me Lately? Unbolting the Compiler's Lidâ . |