作为this question的后续内容,我想知道哪些真实世界的cpu(如果有的话)具有显式该高速缓存/写入主存的指令。在什么情况下使用这些指令?
这些平台上的编译器是否需要为 volatile 写发出这些指令(即在某些语言中具有可见性保证的写入)?
我隐约知道的一个例子是Playstation 3中使用的IBM's Cell processor,据说它有不连贯的缓存,必须由软件手动刷新。
作为this question的后续内容,我想知道哪些真实世界的cpu(如果有的话)具有显式该高速缓存/写入主存的指令。在什么情况下使用这些指令?
这些平台上的编译器是否需要为 volatile 写发出这些指令(即在某些语言中具有可见性保证的写入)?
我隐约知道的一个例子是Playstation 3中使用的IBM's Cell processor,据说它有不连贯的缓存,必须由软件手动刷新。
1条答案
按热度按时间ih99xse11#
armarmv8的数据库
ARMv 8有一组精心设计的
dc
和ic
指令,分别用于管理数据和指令缓存。它们的确切描述比“刷新L2数据缓存”等更复杂,因为ARMv 8有一个抽象的缓存模型,该模型基于缓存可能彼此偏离的“点”。可以通过虚拟地址或通过显式级别/集合/路地址使高速缓存行无效或写回(“清除”)。所以你有像
dc civac
,数据缓存清理和无效的虚拟地址一致性点的指令。在ARMv 8架构参考手册(第D7.4节)中,该高速缓存模型的完整定义约占30页,另外约60页用于描述实际的缓存维护指令(C5.3)。
大多数这些与应用程序员无关,实际上,许多形式的
ic/dc
指令都是特权的,无论如何都不能由应用程序执行。ARMv 8内存模型保证数据缓存在“内部共享域”中是一致的,其中包括可能运行程序线程的所有核心,因此不需要显式的缓存管理指令来与其他线程共享变量。(当您需要确保以特定顺序加载和存储 * 提交 * 到一致性缓存时,您仍然需要像ldar/stlr/dmb
这样的内存屏障,例如获取,释放或顺序一致性。影响应用程序编程的一个方面是,与x86不同,指令和数据缓存既不统一,也不一致。因此,当您写入稍后将作为指令执行的数据时,例如当加载二进制或JIT编译时,您确实需要显式地将相关行从数据缓存清理到“统一点”,然后使它们从指令缓存中无效,最后执行同步屏障(
isb
)以刷新已从缓存中预取的任何指令。有关更多详细信息,请参见在ARM上同步JIT/自修改代码的缓存。内存Map的I/O寄存器应该在内核设置的页表中标记为“设备内存”,这会自动免除它们的缓存和重新排序,因此您不需要显式的缓存刷新或屏障来访问它们;普通的负载和储备就足够了。某些系统可能需要DMA的显式缓存管理。
C/C编译器不会发出任何缓存维护指令(也不会发出屏障)用于
volatile
读取和写入。您所得到的是通常的保证,即volatile
读/写只执行一条加载/存储指令。如上所述,这对于内存MapI/O访问应该足够了,这是C/C中volatile
的主要合法用途。如果您正在执行的其他操作实际上需要缓存维护,则必须自己插入这些指令。对于上面描述的JIT情况,gcc/clang提供了__builtin_clear_caches()
。其他语言如C#/Java对
volatile
有不同的语义,更像是C_Atomic
或C++std::atomic
。在这种情况下,您将获得内存屏障,但仍然没有缓存维护。