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

agg*_*k02 12 performance benchmarking x86 intel cpu-architecture

我们有一个简单的内存吞吐量基准.对于大块内存,它所做的只是重复记忆.

在几台不同的机器上查看结果(针对64位编译),Skylake机器的性能明显优于Broadwell-E,保持OS(Win10-64),处理器速度和RAM速度(DDR4-2133)不变.我们不是说几个百分点,而是大约2个因素.Skylake配置为双通道,Broadwell-E的结果不会因双/三/四通道而异.

任何想法为什么会这样?随后的代码在VS2015的Release中编译,并报告完成每个memcpy的平均时间:

64位:Skylake为2.2ms,Broadwell-E为4.5ms

32位:Skylake为2.2ms,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();
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 9

现代CPU上的单线程内存带宽受到max_concurrency / latency从L1D到系统其余部分的传输的限制,而不受DRAM控制器瓶颈的限制.每个内核都有10个线路填充缓冲器(LFB),用于跟踪发往/来自L1D的未完成请求.(以及跟踪到/来自L2的线路的16个"超级"条目).

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

SKX(Skylake-server/AVX512,包括i9"高端桌面"芯片)非常糟糕:L3 /内存延迟明显高于Broadwell-E/Broadwell-EP,因此单线程带宽更差比具有相似核心数的Broadwell.(SKX使用网格而不是环形总线,因为它可以更好地扩展,有关两者的详细信息,请参阅此内容.但显然新设计中的常数因素不好;未来几代可能会有更好的L3带宽/延迟用于中小型核心数量虽然私有的每核L2升级到1MiB,所以L3可能会故意减速以节省电力.)


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

有关此内容的更多信息,请参阅本答案中有关x86内存带宽的Latency-bound Platforms部分.(并阅读其他部分的memcpy/memset与SIMD循环相比rep movs/rep stos,以及NT存储与常规RFO存储等等.)

还有关系:每个程序员应该了解内存?(2017年更新的内容仍然是真实的,2007年的优秀文章发生了哪些变化).