- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在x86-64
平台上,CLFLUSH
汇编指令允许刷新与给定地址相对应的缓存行。除了刷新与特定地址相关的缓存之外,还有一种方法可以刷新整个缓存(与正在执行的程序相关的缓存或整个缓存),例如通过使其充满虚拟内容(或任何其他内容)我不会意识到的其他方法):
void flush_cache()
{
// Contents
}
最佳答案
有关与清除缓存有关的问题的链接(尤其是在x86上),请参阅WBINVD instruction usage上的第一个答案。
不,使用纯ISO C++ 17 无法可靠或有效地执行此操作。它不知道也不关心CPU缓存。您可能要做的最好的事情就是触摸大量内存,这样其他所有东西最终都会被驱逐1,但这并不是您真正想要的。 (当然,根据定义,刷新所有缓存效率不高...)
CPU缓存管理功能/内在函数/asm指令是C++语言特定于实现的扩展。但是除了内联汇编之外,我所知道的C或C++实现都没有提供刷新所有缓存(而不是地址范围)的方法。那是因为这不是正常的事情。
例如,在x86上,您要查找的asm指令为wbinvd
。 它在驱逐之前写回所有脏行,这与invd
(它会丢弃高速缓存而不写回useful when leaving cache-as-RAM mode)不同。因此,从理论上讲wbinvd
没有体系结构作用,只有微体系结构,但是它是如此之慢以至于它是一种特权指令。正如Intel's insn ref manual entry for wbinvd
指出的那样,这将增加中断等待时间,因为它本身是不可中断的,可能必须等待8 MiB或更多的脏L3缓存被刷新。也就是说,与大多数时序效果不同,将中断延迟这么长时间可以视为一种架构效果。在多核系统上,它也很复杂,因为它必须刷新所有核的缓存。
我认为无法在x86的用户空间(第3环)中使用它。与cli
/sti
和in
/out
不同,它不是由IO特权级别启用的(您可以在Linux上使用 iopl()
system call进行设置)。因此,wbinvd
仅在实际在环0(即内核代码)中运行时有效。参见Privileged Instructions and CPU Ring Levels。
但是,如果您正在用GNU C或C++编写内核(或在ring0中运行的独立程序),则可以使用asm("wbinvd" ::: "memory");
。在运行实际DOS的计算机上,普通程序在实模式下运行(没有任何低特权级别;所有内容实际上都是内核)。那是运行微基准测试的另一种方式,该微基准测试需要运行特权指令来避免wbinvd
的内核<->用户空间转换开销,并且还具有在OS下运行的便利,因此您可以使用文件系统。不过,将微基准标记放入Linux内核模块可能比从USB内存棒等启动FreeDOS容易。特别是如果您想控制涡轮频率的东西。
我能想到的,您可能想要这样做的唯一原因是为了进行某种实验,以弄清楚特定CPU的内部结构是如何设计的。因此,确切的操作细节至关重要。我什至不想要一种便携式/通用的方法来做到这一点。
或者在重新配置物理内存布局之前,例如在内核中。因此,现在有一个用于以太网卡的MMIO区域,该区域以前是普通的DRAM。但是在那种情况下,您的代码已经完全是特定于拱的。
通常,出于正确性原因,您希望/需要刷新缓存时,您知道哪个地址范围需要刷新。例如在具有不具有缓存一致性的DMA的体系结构上编写驱动程序时,写回操作会在DMA读取之前发生,并且不会逐步进行DMA写操作。 (逐出部分对于DMA读取也很重要:您不希望使用旧的缓存值)。但是x86如今已经具有与缓存相关的DMA,因为现代设计将内存 Controller 内置到CPU芯片中,因此系统流量可以在从PCIe到内存的途中窥探L3。
在驱动程序之外,您需要担心缓存的主要情况是在具有非一致性指令缓存的非x86架构上使用JIT代码生成。如果您(或JIT库)将一些机器代码写入char[]
缓冲区并将其强制转换为函数指针,则ARM之类的体系结构无法保证代码提取将“看到”新写入的数据。
这就是为什么gcc提供 __builtin__clear_cache
的原因。它不一定刷新任何东西,只是确保以代码形式执行该内存是安全的。 x86具有与数据高速缓存一致的指令高速缓存,并支持self-modifying code,而无需任何特殊的同步指令。请参见godbolt for x86 and AArch64,并注意__builtin__clear_cache
对于x86编译为零指令,但对周围的代码有影响:没有它,gcc可以在将其转换为函数指针并调用之前优化将存储移至缓冲区。 (它没有意识到数据已被用作代码,因此认为它们已死存储并消除了它们。)
尽管名称,__builtin__clear_cache
与wbinvd
完全无关。它需要一个地址范围(如args),因此不会刷新并使整个缓存无效。它还不使用clflush
,clflushopt
或clwb
从缓存中实际写回(或可选地逐出)数据。
当需要刷新某些高速缓存以确保正确性时,您只想刷新一定范围的地址,而不希望通过刷新所有缓存来减慢系统速度。
出于性能原因,至少在x86 上故意刷新缓存几乎是没有道理的。有时,您可以使用污染最小化的预取来读取数据而不会造成太多的缓存污染,或者使用NT存储区来写缓存。但是,在正常情况下,最后一次触摸某些内存后再执行“常规”操作,然后执行clflushopt
通常是不值得的。就像存储一样,它必须一直遍历整个内存层次结构,以确保在任何地方都能找到并刷新该行的任何副本。
没有像_mm_prefetch
相反的轻量级指令设计为性能提示。
您可以在x86上的用户空间中执行的唯一缓存刷新操作是clflush
/clflushopt
。 (或者使用NT存储,如果存储行之前很热,它们也会驱逐该缓存行)。或者当然是针对已知的L1d大小和关联性创建冲突驱逐,例如以4kiB的倍数写入多行,所有这些行都映射到32k/8路L1d中的同一集合。
有一个用于 _mm_clflush(void const *p)][6]
的Intel内在[clflush
包装器(另一个是 clflushopt
),但它们只能按(虚拟)地址刷新缓存行。您可以遍历您的进程已映射的所有页面中的所有缓存行...(但是那只能刷新您自己的内存,而不能刷新正在缓存内核数据的缓存行,例如您的进程的内核堆栈或其task_struct
,与您刷新所有内容相比,第一个系统调用仍然会更快。
有一个Linux系统调用包装器可移植地逐出一系列地址: cacheflush(char *addr, int nbytes, int flags)
。如果x86完全支持x86上的实现,则大概在循环中使用clflush
或clflushopt
。手册页说它首先出现在MIPS Linux中,但是
如今,Linux在其他一些操作系统上提供了cacheflush()系统调用
架构,但有不同的论点。”
我认为没有Linux系统调用可以公开wbinvd
和,但是您可以编写一个内核模块来添加一个模块。
最近的x86扩展引入了更多的缓存控制指令,但仍然只能通过地址来控制特定的缓存行。用例适用于non-volatile memory attached directly to the CPU,例如Intel Optane DC Persistent Memory。如果要提交持久性存储而不会使下一个读取变慢,则可以使用 clwb
。但是请注意,clwb
不能保证避免驱逐,只是允许这样做。它可能与may be the case on SKX一样与clflushopt
运行。
请参阅https://danluu.com/clwb-pcommit/,但请注意,不需要pcommit
:Intel决定在发布任何需要它的芯片之前简化ISA,因此clwb
或clflushopt
+ sfence
就足够了。参见https://software.intel.com/en-us/blogs/2016/09/12/deprecate-pcommit-instruction。
无论如何,这是一种与现代CPU相关的缓存控制。无论您正在进行什么实验,都需要ring0并在x86上进行组装。
脚注1:占用大量内存:纯ISO C++ 17
您可能会分配一个非常大的缓冲区,然后对其进行memset
(这样,这些写入将使用该数据污染所有(数据)缓存),然后取消映射。如果delete
或free
实际上立即将内存返回给操作系统,那么它将不再是您进程的地址空间的一部分,因此其他数据中只有少数高速缓存行仍然很热:可能是一两行堆栈(假设您正在使用C++实现,该实现使用堆栈,并且在OS下运行程序...)。当然,这只会污染数据缓存,而不污染指令缓存,并且正如Basile指出的那样,某些级别的缓存是每个内核专用的,并且OS可以在CPU之间迁移进程。
另外,请注意,使用实际的memset
或std::fill
函数调用或为此优化的循环可以优化为使用绕过缓存或减少污染的商店。而且我还隐式地假设您的代码在具有写分配缓存的CPU上运行,而不是在存储未命中时直写(因为所有现代CPU都是以这种方式设计的)。
进行一些无法优化并占用大量内存的操作(例如使用long
数组而不是位图的主筛)会更可靠,但当然仍然依赖于缓存污染来驱逐其他数据。仅仅读取大量数据也不可靠。一些CPU实现了自适应替换策略,以减少顺序访问带来的污染,因此,希望在大型阵列上循环不会驱逐大量有用数据。例如。 the L3 cache in Intel IvyBridge and later执行此操作。
关于c++ - 有没有办法刷新与程序相关的整个CPU缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48527189/
我阅读了有关 JSR 107 缓存 (JCache) 的内容。 我很困惑:据我所知,每个 CPU 都管理其缓存内存(无需操作系统的任何帮助)。 那么,为什么我们需要 Java 缓存处理程序? (如果C
好吧,我是 jQuery 的新手。我一直在这里和那里搞乱一点点并习惯它。我终于明白了(它并不像某些人想象的那么难)。因此,鉴于此链接:http://jqueryui.com/sortable/#dis
我正在使用 Struts 2 和 Hibernate。我有一个简单的表,其中包含一个日期字段,用于存储有关何时发生特定操作的信息。这个日期值显示在我的 jsp 中。 我遇到的问题是hibernate更
我有点不确定这里发生了什么,但是我试图解释正在发生的事情,也许一旦我弄清楚我到底在问什么,就可能写一个更好的问题。 我刚刚安装了Varnish,对于我的请求时间来说似乎很棒。这是一个Magneto 2
解决 Project Euler 的问题后,我在论坛中发现了以下 Haskell 代码: fillRow115 minLength = cache where cache = ((map fill
我正试图找到一种方法来为我网络上的每台计算机缓存或存储某些 python 包。我看过以下解决方案: pypicache但它不再被积极开发,作者推荐 devpi,请参见此处:https://bitbuc
我想到的一个问题是可以从一开始就缓存网络套接字吗?在我的拓扑中,我在通过双 ISP 连接连接到互联网的 HAProxy 服务器后面有 2 个 Apache 服务器(带有 Google PageSpee
我很难说出不同缓存区域 (OS) 之间的区别。我想简要解释一下磁盘\缓冲区\交换\页面缓存。他们住在哪里?它们之间的主要区别是什么? 据我了解,页面缓存是主内存的一部分,用于存储从 I/O 设备获取的
1.题目 请你为最不经常使用(LFU)缓存算法设计并实现数据结构。 实现 LFUCache 类: LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象 in
1.题目 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: ① LRUCache(int capacity) 以正整数作为容量 capacity
我想在访问该 View 时关闭某些页面的缓存。它适用于简单查询模型对象的页面。 好像什么时候 'django.middleware.cache.FetchFromCacheMiddleware', 启
documents为 ExePackage element state Cache属性的目的是 Whether to cache the package. The default is "yes".
我知道 docker 用图层存储每个图像。如果我在一台开发服务器上有多个用户,并且每个人都在运行相同的 Dockerfile,但将镜像存储为 user1_myapp . user2 将其存储为 use
在 Codeigniter 中没有出现缓存问题几年后,我发现了一个问题。我在其他地方看到过该问题,但没有适合我的解决方案。 例如,如果我在 View 中更改一些纯 html 文本并上传新文件并按 F5
我在 Janusgraph 文档中阅读了有关 Janusgraph Cache 的内容。关于事务缓存,我几乎没有怀疑。我在我的应用程序中使用嵌入式 janusgrah 服务器。 如果我只对例如进行读取
我想知道是否有来自终端的任何命令可以用来匹配 Android Studio 中执行文件>使缓存无效/重新启动的使用。 谢谢! 最佳答案 According to a JetBrains employe
我想制作一个 python 装饰器来内存函数。例如,如果 @memoization_decorator def add(a, b, negative=False): print "Com
我经常在 jQuery 事件处理程序中使用 $(this) 并且从不缓存它。如果我愿意的话 var $this = $(this); 并且将使用变量而不是构造函数,我的代码会获得任何显着的额外性能吗?
是的,我要说实话,我不知道varnish vcl,我可以解决一些基本问题,但是我不太清楚,这就是为什么我遇到问题了。 我正在尝试通过http请求设置缓存禁止,但是该请求不能通过DNS而是通过 Varn
在 WP 站点上加载约 4000 个并发用户时遇到此问题。 这是我的配置: F5 负载均衡器 ---> Varnish 4,8 核,32 Gb RAM ---> 9 个后端,4 个核,每个 16 RA
我是一名优秀的程序员,十分优秀!