如果你在上一篇文章中做了硬件调查,你可能会想知道英特尔最新的主流架构在哪里。冰湖失踪了!
好消息是:就在这里,…。而且很有趣。我们将直接进入上次对Skylake客户端所做的相同分析。如果您还没有读过第一篇文章,您可能想从那里开始,因为我们将引用那里介绍的概念,而不会在这里重新解释它们。
像往常一样,您可以跳到调查结果的一口大小版本的摘要。
让我们首先看一下总体性能:像我们对每个微体系结构所做的那样,面对填充0和填充1。请记住,填充0用零填充区域,而填充1用值1填充区域(作为4字节整数)。
所有这些测试都运行在3.5 GHz。该芯片的最大单核涡轮增压频率为3.7 GHz,但由于AVX-512时钟效应和其他内核偶尔会激活,因此很难在此频率下持续运行。3.5 GHz是一个很好的折衷方案,可以保持芯片在相同频率下运行,同时保持接近理想的涡轮增压。禁用turbo不是一个好的选择,因为该芯片在没有turbo的情况下运行在1.1 GHz,这会在使用uncore和RAM时引入很大的失真。
图7a图7b这两个有几个关键区别。首先,图7a在L1区域的右半部分发生了这种奇怪的事情:有两个明显且不同的性能级别可见,每个级别大约有一半的样本。
第二件事是,虽然这两个曲线图在L3和RAM区域都显示了一些零优化效果,但图7b中的影响要大得多:
那么这两个地块有什么不同呢?第一个是用-march=local编译的,第二个是用-march=icelake-client编译的。
因为我是在Ice Lake客户端系统上编译这段代码,所以我认为它们会做同样的事情,但由于某些原因,它们不会这样做。主要区别是-march=ative会生成如下所示的512位指令(对于主循环):
。l4:vmovdqu32[rax],zmm0添加rax,512 vmovdqu32[rax-448],zmm0 vmovdqu32[rax-384],zmm0 vmovdqu32[rax-320],zmm0 vmovdqu32[rax-256],zmm0 vmovdqu32[rax-192],zmm0 vmovdqu32[rax-128],zmm0。L4。
。l4:vmovdqu32[rax],ymm0 vmovdqu32[rax+32],ymm0 vmovdqu32[rax+64],ymm0 vmovdqu32[rax+96],ymm0 vmovdqu32[rax+128],ymm0 vmovdqu32[rax+160],ymm0 vmovdqu32[rax+192],ymm0 vmovdqu32[rax+192]。L4。
大多数编译器默认使用256位指令,即使对于支持AVX-512的目标也是如此(原因:降频,所以这里奇怪的是-march=原生版本。所有早期的x86测试都使用256位指令。
观察到图7a是运行512位指令的结果,再加上对数据的窥探,这让我们立即解开了双模式行为的谜团。
以下是缓冲区大小为9864的17个样本的原始数据:
对于填充0和填充1的测试,性能遵循特定的模式:对于前9-10个样本,开始时速度较慢(约90 Gb/s),然后突然跃升到较高的性能级别(接近200 Gb/s)。事实证明,这只是电压和频率管理再次咬我们一口。在这种情况下,没有频率变化:原始数据有一个频率列,显示试验始终运行在3.5 GHz。仅存在电压变化,并且当电压变化时,CPU以降低的调度吞吐量2运行。
对于每个新的试用集(新的缓冲区大小值)重复此效果的原因是,每个新的试用集之前都有一个100ms的自旋等待:该自旋等待不运行任何AVX-512指令,因此CPU下降回较低的电压电平,并且此过程重复。当基准进入L2区域时,这种影响就会停止,因为在那里它足够慢,以至于被丢弃的10次预热试验足以吸收切换到更高电压电平的时间。
我们只需删除100ms的预热(将--预热-ms=0传递给基准)就可以避免这个问题,在本文的其余部分,我们将讨论无预热版本(我们保留10个预热试验,它们应该足够了)。
因此,我们只剩下第二个效果,即256位存储版本显示非常有效的消除,而不是512位版本。现在,让我们停止挑选256到512之间的收藏夹(把它放到您的堆栈上,我们稍后再讨论它),只关注256位存储的消除行为。
下面是256位存储版本的L3区域的特写,还显示了L2逐出类型,如上一篇文章中所讨论的:
图8我们最终实现了难以捉摸的(接近)100%消除冗余零商店!填充值为0的案例在96%的无提示(消除3个)逐出时达到峰值。典型的L3带宽在消除的情况下约为59 Gb/s,在未消除的情况下为约42 Gb/s,加速比超过40%!所以这对冰湖来说是一件潜在的大事。
与上次一样,我们还可以检查非核心跟踪器性能计数器,以查看通常会写回内存的较大缓冲区会发生什么情况。
图9与L3的情况一样,我们看到存储消除似乎有96%的效率:对于填充0的情况,去核到内存写回的数量持平于4%。将其与图3进行比较,图3是在Skylake-S上运行的相同基准,请注意,只消除了一半对RAM的写入。
此图表还包括alt01基准测试的结果。回想一下,此基准测试写入64字节的0和64字节的1。这意味着,通过零过零消除,最多只能消除一半的行。在Skylake-S上,只有大约50%的合格(零)行被取消,但在这里我们又一次达到了96%的取消!也就是说,在alt01的情况下,消除了48%的所有写入,其中一半是全1写入,不符合条件。
RAM区域的全零情况的渐近加速比小于L3区域,约为23%,但这仍然不是一个不容忽视的问题。交替情况的加速比为10%,略低于全零情况4好处的一半。在L3区域,我们还注意到alt01消除的好处仅约为7%,远低于您预期的约20%的好处(如果您削减全零情况下看到的40%好处)。我们在Skylake-S上看到了类似的效果。
最后值得一提的是,uncore中的这一小幅上升写入了填充0的情况:
这恰好发生在从L3到RAM的转换过程中,此时写入平缓降至每行0.04,但这种上升是相当稳定的。所以这里有一些有趣的效果,可能与L3缓存5的自适应特性有关。
如果我们回溯时间,是时候弹出心理堆栈并返回到我们之前注意到的事情:与512位存储相比,256位存储似乎在L3区域获得了更好的性能。
请记住,由于-march标志中的意外行为,我们最终得到了256位和512位版本。相反,他们依赖于这种怪异的6,让我们只编写稍微懒惰的7个方法,这些方法显式使用256位和512位存储,但在其他方面是相同的。填充256_0使用256位存储并写入零,我将让您模式匹配其余的名称。
图10此图表仅显示了17个试验的中位数。您可以查看原始数据来了解试验方差,但它通常很低。
在L1区域中,512位方法通常获胜,写入0或1之间没有明显区别(月球的两半大多对齐)。尽管如此,256位的商店与512位的商店大体上是有竞争力的:它们的吞吐量还不到512位的一半。这要归功于冰湖上的第二个商店港口。如果没有该功能,在3.5 GHz时您将被限制为112 Gb/s,但在这里,256位存储可以轻松达到~190 Gb/s,512位存储可以轻松达到~195 Gb/s。512位存储可能略有优势,因为执行的指令总数较少(约为256位情况的一半)和相关的二阶效应。
然而,在L2区域,256位方法似乎遥遥领先。这有点像水牛比尔队赢得了超级碗:这是不应该发生的。
图11 256位基准测试开始时与其512位基准大致持平,但随后随着区域接近L2的完整大小而逐渐远离。到L2区域结束时,它们拥有近13%的优势。这适用于两种填充256版本--写0和写1的风格。因此,这种效应似乎不能用商店淘汰来解释:我们已经知道商店被淘汰了,而且只有当区域是L3大小时,淘汰才开始发挥明显的作用。
在L3中,情况发生了变化:现在256位版本确实领先了,但只有写零的版本。256位和512位单填充版本的吞吐量下降,几乎达到相同的水平(但256位版本似乎仍然略微领先,但速度提高了约2%)。256位填零版本现在领先了大约45%!
让我们只关注写入零的两个基准:填充256_0和填充512_0,并打开L2逐出计数器(您现在可能已经看到了那个计数器):
仅显示L2线路输出静默事件-驱逐的其余部分照常处于非静默状态。
尽管我不得不让右轴传说在剧情中间漂浮着,但我希望故事是清晰的:256位商店以通常96%的比率被淘汰,但512位商店却徘徊在绝对像天空湖(Skylake)一样的约56%的水平上,我希望故事是清晰的:256位商店以通常96%的比率被淘汰,但512位商店却徘徊在绝对像天空湖(Skylake)一样的56%。我不能肯定,但我预计这种门店淘汰的差异在很大程度上解释了业绩差异。
我还检查了关闭预取时的行为,但模式非常相似,只是这两种方法在L3中的性能都有所降低(您可以自己看看)。有趣的是,对于零过零存储,L3中的256位存储性能几乎与L2中的512位存储性能相同!在性能方面(在此基准测试中),它几乎为您购买了缓存层次结构中的整个级别。
通常我会试着猜测这里发生了什么,但这次我不会这么做了。我就是不知道9。整个事情非常令人费解,因为L1之后的一切都是在缓存线的基础上操作的:我们希望核心在一个线内创建的细粒度存储模式基本上对缓存系统的其余部分是不可见的,因为它只看到整行。然而,对于内核是以两个256位块还是单个512位块写入高速缓存线,在L3中甚至在RAM10中存在一些较大的影响。
我们发现,最初在Skylake客户端上发现的商店消除优化仍然存在于Ice Lake中,并且在我们的Fill基准中的效率大约是Fill基准的两倍。观察到消除了96%的L2写回(到L3)和L3写回(到RAM),相比之下,Skylake只有50%到60%。我们发现,L3区域的加速比高达45%,RAM的加速比约为25%,而Skylake的加速比不到20%。
我们发现,当针对L2缓存或更大大小的区域进行填零写入时,256位写入通常比512位写入快得多。这对L2的影响最大,在L2中,256位过零写入比512位写入快45%。我们发现即使对于非零写入也有类似的影响,但仅在L2中。
目前还没有发布的Sunny Cove服务器芯片是否会表现出同样的优化,这是一个有趣的悬而未决的问题。
除非你只为自己的笔记本电脑进行开发,否则截至2020年5月,冰湖部署在你所关心的主机总数的很小一部分上,所以前一篇文章中的标题建议是适用的:这种优化不适用于足够的硬件,不足以让你专门针对它。这种情况在未来可能会随着“冰湖”和续集的推出而改变。在这种情况下,影响的大小可能使其在某些情况下值得优化。
如果你有什么要说的,请在下面留言或在黑客新闻上讨论。
它实际上仍在使用evex编码的avx-512指令vmovdqu32,这里的效率更高一些,因为avx-512对偏移量的编码更紧凑,偏移量是向量大小的倍数(通常是这样)。-↩。
在这种情况下,吞吐量只减少了一半,而当我们在SKx上查看调度限制时,吞吐量只有四分之一,因此根据这个非常初步的结果,冰湖的调度限制似乎不那么严重(这需要更深入的研究:我们从未使用商店在SKx上进行测试)。-↩。
严格来说,无声冲销是消除的充分条件,但不是必要条件,因此是消除门店数量的下限。据我所知,100%的门店都被淘汰了,但其中4%的门店是非静默回写的(但不是修改后的状态)。--↩。
其中一个原因可能是,只写入交替行比连续写入一半数据的成本要高一些。当然,这显然更接近核心,因为您接触的页面数量是连续情况下的一半,需要的页面遍历数量是一半,预取更有效,因为您跨越了一半的4K边界(4K边界处的预取存储),依此类推。即使在内存接口,交替行写入也可能效率较低,因为您从打开每个DRAM页中获得的好处较少,不能超过64字节的突发,等等。在一种病态情况下,如果控制器将交替行映射到交替通道,则交替行可能是带宽的一半,因为您将仅访问单个通道。我们可以试着通过尝试更粗粒度的交织来隔离这种效果。--↩。
L3能够确定当前的访问模式是否会更好地服务于类似MRU驱逐策略的东西,例如,当数据流在没有重用的情况下被访问时,最好是快速将该数据踢出缓存,而不是驱逐其他可能有用的数据。-↩
毕竟,这个问题很有可能会在后来的GCC版本中得到修复。--↩。
从我不做任何标量头或尾处理的意义上说,这些都是懒惰的:即使没有剩下64字节,最后的迭代也只执行全宽SIMD存储:我们最多用63字节覆盖缓冲区。我们在分配缓冲区时会考虑到这一点,方法是确保分配至少超出该数量。这对于较大的缓冲区来说无关紧要,但这意味着与准确执行填充的方法相比,此版本对于非常小的缓冲区将获得提升。无论如何,我们对这里的大缓冲很感兴趣。--↩。
最有可能的是,L1具有单个64字节宽的写入端口,如SKX,并且存储缓冲器头部的提交逻辑可以向前看一个存储,以查看它是否在同一行中,以便在单个周期内将两个存储出列。如果没有此功能,您可以在每个周期执行两个存储,但只能提交一个,因此长期存储吞吐量将被限制为每个周期一个。“↩。
我撒谎了。我至少有一些想法。CPU功率预算可能在核心和非核心之间动态划分,并且由于512位存储触发AVX-512功率预算,所以用于非核心的功率较少,并且它以较低的频率运行(可以检查)。这似乎不太可能,因为这应该不会明显影响淘汰的机会。--↩。
我们没有仔细观察RAM中的影响,但它仍然存在,尽管幅度较低。256位过零写入比同类型的512位写入快约10%.(完)↩