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

2023-12-05

我们有一个简单的内存吞吐量基准。它所做的只是对一大块内存重复进行memcpy。

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

任何想法为什么会发生这种情况?以下代码在 VS2015 的 Release 中编译,并报告完成每个 memcpy 的平均时间:

64 位:Skylake 为 2.2 毫秒,而 Broadwell-E 为 4.5 毫秒

32 位:Skylake 为 2.2 毫秒,而 Broadwell-E 为 3.5 毫秒.

我们可以通过利用多个线程在四通道 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 上的内存带宽受到以下因素的限制max_concurrency / latency从 L1D 到系统其余部分的传输,而不是 DRAM 控制器瓶颈。每个内核都有 10 个行填充缓冲区 (LFB),用于跟踪发往/来自 L1D 的未完成请求。 (以及 16 个“超级队列”条目,用于跟踪往返 L2 的线路)。

(更新:实验表明 Skylake 可能有 12 个 LFB,而 Broadwell 中有 10 个。例如图 7僵尸加载纸,以及其他性能实验,包括@BeeOnRope 对多个商店流的测试)


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

SKX(Skylake-server / AVX512,包括 i9“高端桌面”芯片)对此确实很糟糕:L3 /内存延迟明显高于 Broadwell-E / Broadwell-EP,因此单线程带宽更差与具有相似核心数量的 Broadwell 相比。 (SKX 使用网格而不是环形总线,因为这样可以更好地扩展,有关两者的详细信息,请参阅此。但显然,恒定因素在新设计中是不好的。也许未来几代将拥有更好的中小型核心数量的 L3 带宽/延迟。不过,每核专用 L2 已增加到 1MiB,因此 L3 可能故意放慢速度以节省电量。)

(像问题中那样的 Skylake 客户端(SKL),以及后来的四核/六核台式机/笔记本电脑芯片,如 Kaby Lake 和 Coffee Lake,仍然使用更简单的环形总线布局。只有服务器芯片发生了变化。我们还没有确切知道 Ice Lake 客户端会做什么。)


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

有关此内容的更多信息,请参阅延迟受限平台部分这个答案关于 x86 内存带宽。 (并阅读带有 SIMD 循环与 SIMD 循环的 memcpy/memset 的其他部分rep movs/rep stos、NT 商店与常规 RFO 商店等。)

还相关:每个程序员都应该了解哪些关于内存的知识?(2017 年更新了 2007 年那篇优秀文章中仍然真实的内容和发生的变化)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Skylake 在单线程内存吞吐量方面比 Broadwell-E 好很多? 的相关文章

  • 如何使用 Java2D 创建硬件加速图像?

    我正在尝试创建一个快速图像生成器 它可以执行大量 2d 转换和形状渲染 因此我尝试使用 BufferedImage 然后获取 Graphics2D 对象来执行所有绘图 我现在主要关心的是 make 速度非常快 所以我创建一个像这样的 Buf
  • 为什么在 this 方法中添加 If 语句会大大降低速度?

    我在中遇到过这个回答另一个问题 https stackoverflow com questions 12233594 faster way to apply alpha to a jpeg in an android app 我试图诊断哪些
  • Java中精确的时间测量

    Java 提供了两种获取当前时间的方法 System nanoTime and System currentTimeMillis 第一个给出的结果以纳秒为单位 但实际精度比这要差得多 许多微秒 JVM 是否已经为每台特定机器提供了最佳的价值
  • 如何清除chrome性能条目或绕过其数量限制?

    我使用 Google Chrome 来分析一些使用 Javascript 动态加载脚本和其他资源的网页的性能 我用performance getEntries 方法 但我注意到 Chrome 只记录前 150 个资源 我找不到任何方法来获取
  • mfence 和 asm 易失性 ("" : : : "内存") 的区别

    据我了解 mfence是硬件内存屏障 而asm volatile memory 是编译器障碍 但是 可以asm volatile memory 用来代替 mfence 我感到困惑的原因是这个链接 http gcc gnu org ml gc
  • ListDictionary 类是否有通用替代方案?

    我正在查看一些示例代码 其中他们使用了ListDictionary对象来存储少量数据 大约 5 10 个对象左右 但这个数字可能会随着时间的推移而改变 我使用此类的唯一问题是 与我所做的其他所有事情不同 它不是通用的 这意味着 如果我在这里
  • 为什么这个函数在额外读取内存时运行速度如此之快?

    我目前正在尝试了解 x86 64 上某些循环的性能属性 特别是我的 Intel R Core TM i3 8145U CPU 2 10GHz 处理器 具体来说 在循环体内添加一条额外的指令来读取内存几乎可以使性能提高一倍 而细节并不是特别重
  • 我们是否需要使用 MappedByteBuffer.force() 将数据刷新到磁盘?

    我正在使用 MappedByteBuffer 来加速文件读 写操作 我的问题如下 我不确定是否需要使用 force 方法将内容刷新到磁盘 似乎没有 force getInt 仍然可以完美工作 好吧 因为这是一个内存映射缓冲区 我假设 get
  • 内在数组访问比 std::vector 访问快得多——黑魔法?

    我已经设置了一个测试程序来将数组访问性能与 std vector 的访问性能进行比较 我发现了几个类似的问题 但似乎没有一个问题能解决我的具体问题 一段时间以来 我一直在摸不着头脑 为什么数组访问似乎比向量访问快 6 倍 而我过去读到它们应
  • 有人真正有效地实现了斐波那契堆吗?

    你们中有人曾经实施过斐波那契堆 http en wikipedia org wiki Fibonacci heap 几年前我就这样做了 但它比使用基于数组的 BinHeaps 慢了几个数量级 当时 我认为这是一个宝贵的教训 告诉我们研究并不
  • 内存分配/释放瓶颈?

    在典型的实际程序中 内存分配 释放的瓶颈有多大 欢迎来自性能通常很重要的任何类型的程序的答案 malloc free 垃圾收集的正确实现是否足够快 以至于它只是少数极端情况下的瓶颈 或者大多数性能关键型软件会从尝试减少内存分配量或拥有更快的
  • numpy 数组最快的保存和加载选项

    我有一个生成二维的脚本numpy数组与dtype float和形状的顺序 1e3 1e6 现在我正在使用np save and np load对数组执行 IO 操作 然而 这些函数对于每个数组都需要几秒钟的时间 是否有更快的方法来保存和加载
  • Cython:为什么 size_t 比 int 快?

    更改某些 Cython 变量的类型int输入size t可以显着减少某些功能的时间 30 但我不明白为什么 例如 cimport numpy as cnp import numpy as np def sum int cnp int64 t
  • Linq to object:内部查询性能

    在回答其中一项时问题 https stackoverflow com questions 46501476 using linq and lambdas to search dictionaryclassliststruct data 46
  • Scala 中的模式匹配是如何在字节码级别实现的?

    Scala 中的模式匹配是如何在字节码级别实现的 是不是像一系列if x instanceof Foo 构造 还是其他什么 它对性能有何影响 例如 给出以下代码 来自Scala 示例 http www scala lang org docu
  • VBA 代码基准测试

    对 VBA 代码进行基准测试最准确的方法是什么 在我的例子中 我正在 Excel 中测试代码 除了下面的 2 种之外 还有其他对代码进行基准测试的技术吗 如果有 该方法的优点 缺点是什么 这里有两种流行的方法 First Timer Sub
  • 在高负载站点中使用 PHP 的策略

    在你回答这个问题之前 我从未开发过任何足够流行的东西来达到高服务器负载 把我当作 叹气 一个刚刚登陆地球的外星人 尽管我了解 PHP 和一些优化技术 我正在开发一个工具PHP如果效果好的话 可以吸引相当多的用户 然而 虽然我完全有能力开发该
  • 较低级别的缓存是否可以具有更高的关联性并且仍然保留包含性?

    较低级别的缓存是否可以具有更高的关联性并且仍然保留包含性 假设我们有 2 级缓存 L1 最接近 CPU L2 最接近主内存 L1 高速缓存是与 4 个组关联的 2 路组 假设 L2 高速缓存与 16 个高速缓存行直接映射 并假设两个高速缓存
  • 电路解码所需的最小输入位数

    我正在学习计算机体系结构 并且正在阅读有关编码器和解码器的内容 在 MIPS 处理器中 操作码有 6 位 我想知道构建解码器来解码操作码需要多少输入位 我知道解码器是一个组合电路 它将二进制信息从 n 个输入线转换为最多 2 n 个唯一的输
  • 为什么线程本地存储不使用页表映射来实现?

    我希望使用 C 11thread local将非常频繁地访问的每线程布尔标志的关键字 然而 大多数编译器似乎都使用一个表来实现线程本地存储 该表将整数 ID 槽 映射到当前线程上的变量地址 此查找将发生在性能关键的代码路径内 因此我对其性能

随机推荐

  • 如何解析 XML 以检索嵌入的文本节点

    我想解析这个 XML 文件 要解析的 XML 文件
  • 为什么不允许“SplFileInfo”序列化?

    我正在尝试存储一个数组SplFileInfo缓存中的实例serialize命令 但该命令抛出此异常 Exception with message Serialization of SplFileInfo is not allowed 为什么
  • Pygame:画线

    在我之前的问题中Python 中的 For 循环函数 我在放置包含为刽子手游戏画线的命令的函数时遇到了麻烦 它并没有完全划清界限 我首先怀疑这是 for 循环或函数的问题 现在我意识到 Pygame 存在一些问题 我尝试在加拿大国家使用此代
  • PDO:用bindvalue和%来准备

    我在各个网站上查看了一个多小时 但无法解决我的问题 所以这是有效的代码 animes array q this gt db gt query SELECT id nom nom id FROM animes WHERE nom LIKE c
  • django 1.11.4 中的错误('datetime.datetime'对象没有属性'split')

    我正在通过官方文档上的教程学习 django 版本 1 11 4 我使用 python 3 6 5 和 mysql8 作为数据库 我还使用 mysql connector django 连接到 mysql 数据库 我尝试制作第一个 Djan
  • 正则表达式。查找包含某个单词的段落

    在这样的文本中 p 1 bla bla em bla em bla bla p p 2 bla bla em bla em bla TEXT bla p p 3 bla bla em bla em bla bla p p 4 bla bla
  • Google App Engine - 单个数据存储大约使用多少配额?

    数据存储放入的延迟约为 150 毫秒 http code google com status appengine detail datastore 2010 03 11 ae trust detail datastore put laten
  • 尝试使用 C# ado,net 将行插入到 sql server 数据库

    我正在尝试在控制台应用程序中使用 Ado Net 在 SQL Server 数据库中插入一行 我正在从键盘读取输入 这是我的代码 private void InsertStudents string con SqlConnection Co
  • Spring + JPA + Hibernate

    我是春天的新手 我正在尝试使用 Spring 3 1 3 和 JPA 2 0 设置简单的 Web 应用程序 我已将所有必需的库添加到 WEB INF lib 中 启动过程中没有错误 但我的 DaoImpl 文件中的entityManager
  • 从项目目录内的文件夹中读取文件

    在 JSP 项目中 我正在从目录中读取文件 如果我给出完整路径 那么我可以轻松读取该文件 BufferedReader br new BufferedReader new FileReader C ProjectFolderName fil
  • for(;;)循环解释

    在 JS 中 我偶然发现了一种 for 循环 它是for 其功能类似于while true 环形 for 循环括号中的分号起什么作用 for statement 1 statement 2 statement 3 code block to
  • scikit-learn 中每个数据分割的交叉验证指标

    我需要为 X test y test 数据的每个分割显式获取交叉验证统计信息 因此 为了尝试这样做 我做了 kf KFold n splits n splits X train tmp y train tmp X test tmp y te
  • 带有辅助工具提示的 EditText

    我在 iPhone 上有这个应用程序 我想使其适用于 Android 在 iPhone 上 当开始在 EditText 中编辑文本时 显示屏顶部会显示带有消息的工具提示 我想让它也适用于 Android 但我没有找不到任何有帮助的东西 这里
  • 如何在c#项目中使用c++ dll? [复制]

    这个问题在这里已经有答案了 可能的重复 在 C 应用程序中使用 C 类 DLL 我尝试在 c 中添加引用以添加 c dll 失败 如果您有任何其他方法在 c 中添加或使用 c dll 我们该如何使用 我在 C 项目中添加 dll 的错误在哪
  • Visual Basic 6 中 Shell 进程的标准输出读取

    首先 我要声明我不是 Visual Basic 6 专家 我的需要是 从 VB6 客户端代码启动外部 exe 文件 等待该过程完成 并在执行期间 即时 读取来自其标准输出的消息 以便我可以将其打印在文本文件小部件或类似部件上 我想知道是否有
  • 带有本地 docker 的 Jenkins 服务器

    我的 CI 实施有问题 我安装了 Jenkins 服务器并创建了构建管道 来自本教程 https getintodevops com blog building your first docker image with jenkins 2
  • php 邮件附件

    我一直在使用这个脚本向某些员工发送电子邮件 但由于我的系统发生了变化 我现在必须随电子邮件发送附件 并且我已经尝试了多种代码来完成此操作 但没有成功 我仍然收到电子邮件 但没有附件 在这种情况下毫无意义 我已将我正在使用的脚本放在下面 我已
  • 我可以使用 C++ 程序之外的随机内存地址访问随机数据吗

    如果有两个程序正在运行 其中一个程序在某个内存地址存储一个数字 如果我知道该内存地址 并将其硬编码到第二个程序中并打印出该地址处的值 它实际上会得到该信息吗 C 是否允许程序访问 RAM 中存储的任何数据 无论它是否是程序的一部分 在没有虚
  • CSS 负边距定位

    使用负边距进行定位可以吗 我当前的网站中有很多内容 感觉这不是一种稳定的定位方式 我通常也建议使用它们 例如 我有一个结账页面 其中三个 div 彼此叠置 div class A header div div class B content
  • 为什么 Skylake 在单线程内存吞吐量方面比 Broadwell-E 好很多?

    我们有一个简单的内存吞吐量基准 它所做的只是对一大块内存重复进行memcpy 查看几台不同机器上的结果 针对 64 位编译 Skylake 机器的表现明显优于 Broadwell E 操作系统 Win10 64 处理器速度和 RAM 速度