c++ - 存储指令是否会阻止缓存未命中的后续指令?
问题描述
假设我们有一个具有两个内核(C0 和 C1)的处理器和一个从k
最初由 C0 拥有的地址开始的缓存线。如果 C1 在 line 的 8 字节插槽上发出存储指令k
,这会影响在 C1 上执行的以下指令的吞吐量吗?
英特尔优化手册有以下段落
当一条指令将数据写入内存位置 [...] 时,处理器会确保包含此内存位置的行位于其 L1d 缓存中 [...]。如果缓存行不存在,它会使用 RFO 请求从下一级获取 [...] RFO,并在指令退出后存储数据。因此,存储延迟通常不会影响存储指令本身
参考以下代码,
// core c0
foo();
line(k)->at(i)->store(kConstant, std::memory_order_release);
bar();
baz();
foo()
英特尔手册中的引用让我假设在上面的代码中,代码的执行看起来好像存储本质上是一个无操作,并且不会影响bar()
. 相反,对于以下代码,
// core c0
foo();
bar(line(k)->at(i)->load(std::memory_order_acquire));
baz();
结束foo()
和开始之间的延迟bar()
会受到负载的影响,因为以下代码将负载的结果作为依赖项。
这个问题主要与英特尔处理器(在 Broadwell 系列或更新的系列中)如何在上述情况下工作有关。此外,特别是对于看起来像上面的 C++ 代码如何被编译为这些处理器的汇编。
解决方案
一般来说,对于后续代码不会很快读取的存储,存储不会直接延迟任何现代乱序处理器(包括英特尔)上的后续代码。
例如:
foo()
*x = y;
bar()
如果foo()
不修改x
or y
,并且bar
不从 加载*x
,则存储是独立的,甚至可以在foo()
完成之前(甚至在它开始之前)开始bar()
执行,并且可以在存储提交到缓存之前执行,bar()
甚至可以执行 whilefoo()
正在运行等
虽然几乎没有直接影响,但这并不意味着没有间接影响,实际上存储可能会主导执行时间。
如果存储在缓存中未命中,它可能会在满足缓存未命中时占用核心资源。它通常还可以防止后续存储耗尽,这可能是一个瓶颈:如果存储缓冲区填满,前端将完全阻塞,新指令不再进入调度程序。
最后,一切都像往常一样取决于周围代码的细节。如果该序列重复运行foo()
并且bar()
很短,则与存储相关的未命中可能会主导运行时。毕竟,缓冲并不能隐藏无限数量的商店的成本。在某些时候,您会受到商店的内在吞吐量的约束。
推荐阅读
- html - 更改 CSS :before/:hover 以包含以前的 div
- c - 如何使结构内的指针指向另一个指针指向的相同字符串?
- google-apps-script - 清除第二天表单条目上的脚本错误
- postgresql - 是否可以连接到 postgresql 数据库并将 postgresql 表从 Databricks 笔记本加载到 sparkDataFrame
- ios - 您如何使用内容类型 application/x-www-form-urlencoded 提出 put 请求
- java - 如何根据土耳其时区获取 Calendar.getInstance()
- php - 如何比较 DST 与 Laravel / Carbon 更改时的日期
- javascript - 如何在使用 j 查询提交 MVC 表单之前初始化 Value?
- php - 如何在 php 中更正重复的 json 数组
- xml - 我在 laravel 中的站点地图 xml 类型中遇到一些错误