din*_*ehr 5 cpu optimization caching x86-64 mesi
我有时会看到这样的优化代码:
if (matrix[t] != 0) {
matrix[t] = 0;
}
Run Code Online (Sandbox Code Playgroud)
与此代码相反:
matrix[t] = 0;
Run Code Online (Sandbox Code Playgroud)
我想这样编写代码是为了减少 CPU 中的内存带宽。对于典型的 CPU(当该值可能已经为 0 时),这是一个很好的优化吗?为什么?
这对于 MESI 状态意味着什么:如果我将相同的值写回缓存行(写入但不修改),是否会发生从共享到修改的状态转换?或者这对 CPU 来说太复杂而无法检测到吗?
典型的 CPU(或至少某些)是否针对这种情况进行了优化?
AFAIK,没有 x86 微体系结构尝试通过在仍处于共享MESI状态时读取并检查值是否匹配来将存储从存储缓冲区提交到 L1D。
它通常很少见,并且只值得为热共享变量提供额外的缓存访问周期,因此微体系结构默认情况下这样做是没有意义的。大多数存储不是共享变量,并且在存储缓冲区内它不知道哪些存储是共享变量。
if()在值得这样做的情况下(即有时对于共享变量),您必须使用问题中的代码自行完成。这正是该代码的用途,是的,它可以是一个胜利。
如果其他线程很可能比您上次写入的时间更晚读取共享变量,那么最好避免写入共享变量,因为它总是使所有其他副本无效以使本地 CPU 的行进入修改状态。
在某些情况下,加载+分支错误预测的成本可能高于节省的成本,尤其是在预测不佳的情况下。(推测性 RFO 甚至可能在检测到错误预测之前使其他副本无效。当然,推测性存储实际上无法提交到 L1D,但据我所知,所有权读取可能会发生。)
另一个例子,在自旋锁的重试循环中,您总是希望在纯负载 (+ pause) 上旋转,而不是在xchg。旋转xchg或lock cmpxchg将继续锤击该缓存行并延迟实际解锁它的代码。
英特尔的优化手册甚至在 TSX 章节中建议了这种优化,通过避免不必要的存储来减少访问共享变量的其他线程中的事务中止。
// Example 12-1
state = true; // updates every time
var |= flag;
vs.
if (state != true) state = true;
if (!(var & flag)) var |= flag;
Run Code Online (Sandbox Code Playgroud)
对于 TSX,交易中止的成本甚至比额外等待 MESI 还要高,因此值得的机会可能更高。
| 归档时间: |
|
| 查看次数: |
741 次 |
| 最近记录: |