大数组上的 SSE 性能较慢

2024-05-15

我是 SSE 编程新手,所以我希望有人可以帮助我。我最近使用 GCC SSE 内在函数实现了一个函数来计算 32 位整数数组的总和。下面给出了我的实现代码。

int ssum(const int *d, unsigned int len)
{
  static const unsigned int BLOCKSIZE=4;
  unsigned int i,remainder;
  int output;
  __m128i xmm0, accumulator;
  __m128i* src;

  remainder = len%BLOCKSIZE;
  src = (__m128i*)d;
  accumulator = _mm_loadu_si128(src);

  output = 0;
  for(i=BLOCKSIZE;i<len-remainder;i+=BLOCKSIZE){
    xmm0 = _mm_loadu_si128(++src);
    accumulator = _mm_add_epi32(accumulator,xmm0);
  }

  accumulator = _mm_add_epi32(accumulator, _mm_srli_si128(accumulator, 8));
  accumulator = _mm_add_epi32(accumulator, _mm_srli_si128(accumulator, 4));
  output = _mm_cvtsi128_si32(accumulator);


  for(i=len-remainder;i<len;i++){
    output += d[i];
  }
  return output;
}

正如您所看到的,这是一个相当简单的实现,我使用扩展的 xmm 寄存器一次对数组 4 求和,然后通过将剩余元素相加来最后进行清理。

然后,我将这个 SIMD 实现的性能与普通的 for 循环进行了比较。该实验的结果可在此处获取:

SIMD 与 for 循环 https://i.stack.imgur.com/eWBM6.png

正如您所看到的,与 for 循环相比,对于高达约 5M 元素的输入大小(意味着数组的长度),此实现确实显示出约 60% 的加速。然而,对于较大的输入大小值,与 for 循环相关的性能会急剧下降,并且仅产生大约 20% 的加速。

我无法解释这种性能的急剧下降。我或多或少在内存中线性步进,因此缓存未命中和页面错误的影响对于两种实现来说应该大致相同。我在这里缺少什么?有什么办法可以拉平这条曲线吗?任何想法将不胜感激。


对于大输入,数据位于缓存之外,并且代码受内存限制。
对于小输入,数据位于缓存内(即 L1 / L2 / L3 缓存),并且代码受计算限制。
我假设您在性能测量之前没有尝试刷新缓存。

高速缓存位于 CPU 内部,高速缓存和 ALU(或 SSE)单元之间的带宽非常高(高带宽 - 传输数据的时间更少)。
您的最高级别缓存(即 L3)大小约为 4MB 到 8MB(取决于您的 CPU 型号)。
较大量的数据必须位于 DDR SDRAM 上,即外部 RAM(CPU 外部)。
CPU通过内存总线连接到DDR SDRAM,其带宽比高速缓冲存储器低得多。

Example:
假设您的外部 RAM 类型是双通道 DDR3 SDRAM 1600 https://en.wikipedia.org/wiki/DDR3_SDRAM。 外部RAM和CPU之间的最大理论带宽约为25GB/秒。

将 100MBytes 数据(以 25GB/S 速度)从 RAM 读取到 CPU 大约需要 100e6 / 25e9 = 4 毫秒。
根据我的经验,使用的带宽约为理论带宽的一半,因此读取时间约为8毫秒。

计算时间更短:
假设循环的每次迭代大约需要 2 个 CPU 时钟(仅是一个示例)。
每次迭代处理 16 字节的数据。
处理 100MB 的总 CPU 时钟大约需要 (100e6 / 16)*2 = 12500000 clk。
假设CPU频率为3GHz。
SSE 总处理时间约为 12500000 / 3e9 = 4.2 毫秒。

正如您所看到的,从外部 RAM 读取数据所花费的时间是 SSE 计算时间的两倍。

由于数据传输和计算是并行发生的,因此总时间是 4.2mesc 和 8msec 中的最大值(即 8msec)。

假设不使用 SSE 的循环需要两倍的计算时间,因此不使用 SSE 的计算时间约为 8.4 毫秒。

在上面的示例中,使用 SSE 的总体改进约为 0.4 毫秒。

注意:所选数字仅用于示例目的。


基准:
我对我的系统做了一些基准测试。
我使用的是 Windows 10 和 Visual Studio 2010。
基准测试:对 100MBytes 数据求和(对 25*1024^2 32 位整数求和)。

CPU

  • 英特尔酷睿 i5 3550(艾维桥)。
  • CPU基础频率为3.3GHz。
  • 测试期间的实际核心速度:3.6GHz(启用 Turbo boost)。
  • L1数据缓存大小:32KBytes。
  • 二级缓存大小:256Bytes(单核二级缓存大小)。
  • L3 缓存大小:6MBytes。

记忆:

  • 8GB DDR3 双通道。
  • RAM频率:666MHz(相当于不带DDR的1333MHz)。
  • 内存理论最大带宽:(128*1333/8) / 1024 = 20.8GBytes/Sec。

  1. 总计 100MB 作为大块with SSE(外部 RAM 中的数据)。
    处理时间:6.22毫秒
  2. 总和 1KB 100 次with SSE(缓存内的数据)。
    处理时间:3.86毫秒
  3. 总计 100MB 作为大块没有上交所(外部 RAM 中的数据)。
    处理时间:8.1毫秒
  4. 总和 1KB 100 次没有上交所(缓存内的数据)。
    处理时间:4.73毫秒

已使用内存带宽:100/6.22 =16GB/Sec (数据大小除以时间).
SSE 每次迭代的平均时钟(缓存中的数据):(3.6e9*3.86e-3)/(25/4*1024^2) =2.1 时钟/迭代 (总 CPU 时钟除以迭代次数).

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

大数组上的 SSE 性能较慢 的相关文章

  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • 在 HKCR 中创建新密钥有效,但不起作用

    我有以下代码 它返回 成功 但使用两种不同的工具使用搜索字符串 3BDAAC43 E734 11D5 93AF 00105A990292 搜索注册表不会产生任何结果 RegistryKey RK Registry ClassesRoot C
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 前向声明类型和“已声明为类类型的非类类型”

    我对以下代码有问题 template
  • 未找到 Boost 库,但编译正常

    我正在尝试在 C 中使用 boost 的文件系统 使用时看起来编译没问题 c c Analyse c o Analyse o g W Wall L usr local lib lboost filesystem lboost system
  • java中如何重新初始化int数组

    class PassingRefByVal static void Change int pArray pArray 0 888 This change affects the original element pArray new int
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何使用 ASP.NET Core 获取其他用户的声明

    我仍在学习 ASP NET Core 的身份 我正在进行基于声明的令牌授权 大多数示例都是关于 当前 登录用户的 就我而言 我的 RPC 服务正在接收身份数据库中某个用户的用户名和密码 我需要 验证是否存在具有此类凭据的用户 获取该用户的所
  • 获取没有显式特征的整数模板参数的有符号/无符号变体

    我希望定义一个模板类 其模板参数始终是整数类型 该类将包含两个成员 其中之一是类型T 另一个作为类型的无符号变体T 即如果T int then T Unsigned unsigned int 我的第一直觉是这样做 template
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • 将函数参数类型提取为参数包

    这是一个后续问题 解包 元组以调用匹配的函数指针 https stackoverflow com questions 7858817 unpacking a tuple to call a matching function pointer
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • 模板类中的无效数据类型生成编译时错误?

    我正在使用 C 创建一个字符串类 我希望该类仅接受数据类型 char 和 wchar t 并且我希望编译器在编译时使用 error 捕获任何无效数据类型 我不喜欢使用assert 我怎样才能做到这一点 您可以使用静态断言 促进提供一个 ht
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • 将 Lambda 表达式树与 IEnumerable 结合使用

    我一直在尝试了解有关使用 Lamba 表达式树的更多信息 因此我创建了一个简单的示例 这是代码 如果作为 C 程序粘贴到 LINQPad 中 它可以工作 void Main IEnumerable
  • C++:二叉树所有节点值的总和

    我正在准备面试 我被一个二叉树问题困住了 我们如何计算二叉树所有节点中存在的值的总和 优雅的递归解决方案 伪代码 def sum node if node NULL return 0 return node gt value sum nod

随机推荐

  • 如何使用 winforms 在 vb.net 中制作大型按钮网格(24x20 或类似)?

    我正在 vb net WinForms 中制作一个座位预订系统 我需要用户能够选择他们想要使用的座位并改变颜色 这样他们就可以知道它已选择 我开始尝试使用按钮 但 480 个按钮严重减慢了表单的加载时间 然后我尝试了在行 列中带有按钮的数据
  • onclick 函数上的 CSS 选择器

    有没有办法让CSS选择器onclick function 您可以在onclick https stackoverflow com questions 24365416 select element which have specific a
  • 快速约会算法

    我在一家咨询公司工作 大部分时间都在客户所在地 正因为如此 我很少见到同事 为了更好地了解彼此 我们将安排一个晚宴 会有很多小桌子 方便人们聊天 为了在聚会期间与尽可能多的不同的人交谈 每个人都必须每隔一段时间 比如每小时 换一张桌子 如何
  • Python:使用 string.format() 将单词大写

    是否可以使用字符串格式将单词大写 例如 user did such and such format user foobar 应该返回 Foobar 做了这样那样的事情 请注意 我很清楚 capitalize 但是 这是我正在使用的代码 非常
  • 通过推送通知唤醒

    Suppose 有一些对象 例如 一个数组a 和依赖于对象的条件 例如 a empty 当前线程以外的某些线程可以操作该对象 a 因此条件评估值的真实性会随着时间的推移而变化 如何让当前线程在代码中的某个时刻休眠 并在条件满足时通过推送通知
  • 片段内容下方是否存在持久性 BottomSheet?

    Using a 持久底表 https material google com components bottom sheets html bottom sheets persistent bottom sheets 在一个协调器布局 htt
  • CakePHP 会话被写入 /tmp/ 而不是 /app/tmp/sessions/

    这里有类似的简单但未回答的问题 cakephp 会话 tmp sessions 中没有新文件 https stackoverflow com questions 24733151 cakephp session no new files i
  • 如何将 hls.js 与 React 结合使用

    我需要一些帮助来尝试弄清楚如何在 React 中使用 hls js 让我解释一下我必须从 api 获取 m3u8 的情况我能够使用基本的 html 使其工作
  • 什么是 API 密钥? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如今 我几乎在每个跨服务应用程序中都看到这个词 API 密钥到底是什么以及它的用途是什么 另外 公共 API 密钥和私有 API 密钥
  • IntelliJ:线程“主”java.lang.NoClassDefFoundError中的异常:org/apache/spark/sql/types/DataType

    附言 有一个类似的问题here https stackoverflow com questions 40287289 java lang noclassdeffounderror org apache spark logging 但那是在
  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • Linq to Entities 中的动态 where 子句 (OR)

    在文中here https stackoverflow com questions 9122220 dynamic where clause in linq to entities我学习了如何使用 Linq 的延迟执行来构建动态查询 但查询
  • 我如何选择特定的cookie?

    如何从响应中选择特定的 cookie 我收到的响应有 6 个 Set Cookie 行 但我只需要其中一些用于我的下一篇文章 HTTP 1 1 200 OK date Thu 05 Mar 2015 13 49 29 GMT cache c
  • C++中const对象位于哪个内存区域? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何使用数据绑定将点击侦听器设置为 LinearLayout

    我目前正在尝试将点击侦听器设置为LinearLayout查看在 xml使用数据绑定的布局文件 我已经设法让它在其他视图上很好地工作 比如Button or TextView 但由于某种原因 它不能与LinearLayout 这是我尝试的基本
  • 我的单元测试 ReSharper 装订线图标未显示

    我已经安装了 ReSharper 4 1 和 Gallio 3 0 5 但没有获得单元测试的装订线图标 测试似乎在测试资源管理器中运行良好 但代码中的测试旁边没有图标 可能是什么原因造成的 我之前安装了 MbUnit 2 4 ReSharp
  • db2中如何删除所有非数字字母

    我在 DATA 列 varchar 中有一些数据 如下所示 Nowshak 7 485 m Maja e Korabit Golem Korab 2 764 m Tahat 3 003 m Morro de Moco 2 620 m Cer
  • 通过 .NET Core 控制台应用程序中的依赖项注入访问配置

    如何正确激活使用 ServiceCollection Configure 函数添加的配置 public static void Main args args serviceCollection new ServiceCollection s
  • 如何实现 ALTER TABLE 的示例[重复]

    这个问题在这里已经有答案了 我已经多次问过这个问题 但尚未得到完整的答案 如何实现 ALTER TABLE 语句以向数据库添加列 有人可以给我举个例子吗 请阅读SQLite ALTER TABLE 参考 http sqlite org la
  • 大数组上的 SSE 性能较慢

    我是 SSE 编程新手 所以我希望有人可以帮助我 我最近使用 GCC SSE 内在函数实现了一个函数来计算 32 位整数数组的总和 下面给出了我的实现代码 int ssum const int d unsigned int len stat