这似乎是一个奇怪的问题..
假设缓存行的大小为 64 字节。此外,假设 L1、L2、L3 具有相同的缓存行大小(this https://stackoverflow.com/a/15333156/8385554帖子说英特尔酷睿 i7 就是这种情况)。
有两个对象A
, B
在内存上,其(物理)地址是N字节间隔。为了简单起见,我们假设A
位于缓存边界上,即其地址是64的整数倍。
1) If N
A由CPU获取,B
也会被读入缓存。因此,如果B
需要,并且缓存行尚未被驱逐,CPU 取指B
在很短的时间内。每个人都很高兴。
2) If N
>> 64(即远大于 64),当A
由CPU获取,B
不与一起读入缓存行A
。所以我们说“CPU不喜欢四处追逐指针”,这是避免堆分配的基于节点的数据结构的原因之一,例如std::list
.
我的问题 is, if N
> 64 但仍然很小,比如说N
= 70,换句话说,A
and B
不适合一个缓存行,但相距不太远,当A
由CPU加载,进行提取B
所花费的时钟周期数与以下情况时所花费的时钟周期数相同:N
比64大很多吗?
改写 - 当A
已加载,让t表示获取所花费的时间B
, is t(N=70)远小于或几乎等于,t(N=9999999)?
我问这个问题是因为我怀疑t(N=70)远小于t(N=9999999),因为CPU缓存是等级制度.
如果有定量研究就更好了。
至少有三个因素可以使 A 丢失后更快地获取 B。首先,处理器可以推测性地获取下一个块(独立于任何基于步幅的预取引擎,这将取决于在时间和位置上彼此靠近地遇到的两次未命中以确定步幅;单位步幅预取不需要确定步幅值[它是一个]并且可以在第一次错过之后开始)。由于这种预取会消耗内存带宽和片上存储,因此它通常具有节流机制(可以简单到具有适度大小的预取缓冲区,并且仅在内存接口足够空闲时才进行高度推测性预取)。
其次,由于 DRAM 被组织成行,并且更改行(在单个存储体内)会增加延迟,因此如果 B 与 A 位于同一 DRAM 行中,则对 B 的访问可能会避免行预充电的延迟(以关闭先前打开的行) )并激活(打开新行)。 (这也可以提高内存带宽利用率。)
第三,如果B与A位于同一地址转换页中,则可以避免TLB。 (在许多设计中,分层页表遍历在附近区域也更快,因为可以缓存分页结构。例如,在 x86-64 中,如果 B 与 A 位于同一 2MiB 区域中,则 TLB 未命中可能只需执行一次内存访问因为页目录可能仍被缓存;此外,如果 B 的转换与 A 的转换位于同一 64 字节缓存行中,并且 A 的 TLB 未命中是最近发生的,则缓存行可能仍然存在。)
在某些情况下,我们还可以通过将可能丢失的对象以固定的、有序的步幅排列在一起来利用基于步幅的预取引擎。这似乎是一个相当困难且有限的上下文优化。
一种明显的跨步方式可以increase延迟是通过引入冲突未命中来实现的。大多数缓存使用简单的模二幂索引,且关联性有限,因此二步长幂(或到同一缓存集的其他映射)可能会将不成比例的数据量放置在有限数量的集合中。一旦超过关联性,就会发生冲突遗漏。 (已提出倾斜关联性和非二次幂模索引来减少此问题,但这些技术尚未得到广泛采用。)
(顺便说一句,指针追踪特别慢的原因不仅仅是空间局部性低,而是在对 A 的访问完成之后才能开始对 B 的访问,因为存在数据依赖性,即无法获取 B 的延迟与获取 A 的延迟重叠。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)