为什么Skylake在单线程内存吞吐量方面比Broadwell-E好得多?



我们有一个简单的内存吞吐量基准测试。它所做的只是重复内存块。

在几台不同的机器上查看结果(针对64位编译),Skylake机器的表现明显好于Broadwell-E,保持操作系统(Win10-64)、处理器速度和RAM速度(DDR4-2133)相同。我们说的不是几个百分点,而是大约2。Skylake配置为双通道,Broadwell-E的结果不会因双/三/四通道而变化。

你知道为什么会这样吗?下面的代码是在VS2015的Release中编译的,并报告完成每个内存的平均时间:

64位:Skylake 2.2ms vs Broadwell-E 4.5ms

32位:Skylake 2.2ms vs Broadwell-E 3.5ms

通过使用多线程,我们可以在四通道Broadwell-E构建中获得更大的内存吞吐量,这很好,但是看到单线程内存访问如此巨大的差异令人沮丧。对于为什么差异如此明显有什么想法吗?

我们还使用了各种基准测试软件,它们验证了这个简单的例子所显示的-单线程内存吞吐量在Skylake上要好得多。

#include <memory>
#include <Windows.h>
#include <iostream>
//Prevent the memcpy from being optimized out of the for loop
_declspec(noinline) void MemoryCopy(void *destinationMemoryBlock, void *sourceMemoryBlock, size_t size)
{
    memcpy(destinationMemoryBlock, sourceMemoryBlock, size);
}
int main()
{
    const int SIZE_OF_BLOCKS = 25000000;
    const int NUMBER_ITERATIONS = 100;
    void* sourceMemoryBlock = malloc(SIZE_OF_BLOCKS);
    void* destinationMemoryBlock = malloc(SIZE_OF_BLOCKS);
    LARGE_INTEGER Frequency;
    QueryPerformanceFrequency(&Frequency);
    while (true)
    {
        LONGLONG total = 0;
        LONGLONG max = 0;
        LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
        for (int i = 0; i < NUMBER_ITERATIONS; ++i)
        {
            QueryPerformanceCounter(&StartingTime);
            MemoryCopy(destinationMemoryBlock, sourceMemoryBlock, SIZE_OF_BLOCKS);
            QueryPerformanceCounter(&EndingTime);
            ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
            ElapsedMicroseconds.QuadPart *= 1000000;
            ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
            total += ElapsedMicroseconds.QuadPart;
            max = max(ElapsedMicroseconds.QuadPart, max);
        }
        std::cout << "Average is " << total*1.0 / NUMBER_ITERATIONS / 1000.0 << "ms" << std::endl;
        std::cout << "Max is " << max / 1000.0 << "ms" << std::endl;
    }
    getchar();
}

现代cpu上的单线程内存带宽受限于从L1D到系统其余部分的传输的max_concurrency / latency,而不是受限于dram控制器瓶颈。每个核心有10个行填充缓冲区(lfb),用于跟踪来自L1D的未完成请求。(还有16个"超级队列"条目,跟踪从L2到L2的行)。

(更新:实验表明Skylake可能有12个lfb,而Broadwell只有10个。例如zombiload论文中的图7,以及其他性能实验,包括@BeeOnRope对多个存储流的测试)


英特尔的多核芯片比四核或双核台式机/笔记本电脑芯片具有更高的L3/内存延迟,因此单线程内存带宽实际上在大型至强处理器上更差,尽管多线程的最大聚合带宽要好得多。它们在连接内核、内存控制器和系统代理(PCIe等)的环形总线上有更多的跳点。

SKX (Skylake-server/AVX512,包括i9"高端桌面"芯片)在这方面真的很糟糕:L3/内存延迟明显高于Broadwell- e/Broadwell- ep,因此单线程带宽甚至比具有相似核心数的Broadwell更差。(SKX使用网格而不是环形总线,因为它可以更好地缩放,请参阅这两个细节。但显然,在新的设计中,不变的因素是不好的;也许未来的一代将有更好的L3带宽/延迟小/中等核数。私有的每核L2被提升到1MiB,所以可能L3故意变慢以节省电力。

(SKL)在问题中,后来的四核/六核桌面/笔记本电脑芯片,如Kaby Lake和咖啡湖,仍然使用更简单的环总线布局。只有服务器芯片变了。我们还不确定冰湖客户端会怎么做


四核或双核芯片只需要几个线程(特别是如果核心+非核心(L3)的时钟高)来饱和其内存带宽,而具有快速DDR4双通道的Skylake具有相当大的带宽。

有关这方面的更多信息,请参阅本回答中关于x86内存带宽的延迟绑定平台部分。(并阅读其他部分的memcpy/memset与SIMD循环与rep movs/rep stos, NT store与常规RFO store,等等)

还相关:关于内存,每个程序员都应该知道什么?(2017年更新了2007年那篇优秀的文章中哪些仍然是正确的,哪些改变了)。

我终于得到了VTune(评估)启动和运行。它在Broadwell-E上给出的DRAM绑定分数为。602(介于0和1之间),在Skylake上给出的分数为。324,其中Broadwell-E延迟的很大一部分来自内存延迟。考虑到记忆棒的速度是相同的(除了Skylake中配置的双通道和Broadwell-E中配置的四通道),我最好的猜测是Skylake中内存控制器的某些方面要好得多。

这使得购买Broadwell-E架构变得更加困难,并且需要您真正需要额外的内核才能考虑它。

我还得到了L3/TLB miss计数。Broadwell-E上TLB脱靶率高20%,L3脱靶率高36%。

我不认为这真的是"为什么"的答案,所以我不会这样标记,但我认为我目前会尽可能接近一个。感谢一路走来所有有帮助的评论。

最新更新