SSE 矩阵-矩阵乘法

2023-12-10

我在 C 中使用 SSE 进行矩阵-矩阵乘法时遇到问题。

这是我到目前为止得到的:

#define N 1000

void matmulSSE(int mat1[N][N], int mat2[N][N], int result[N][N]) {
  int i, j, k;
  __m128i vA, vB, vR;

  for(i = 0; i < N; ++i) {
    for(j = 0; j < N; ++j) {
        vR = _mm_setzero_si128();
        for(k = 0; k < N; k += 4) {
            //result[i][j] += mat1[i][k] * mat2[k][j];
            vA = _mm_loadu_si128((__m128i*)&mat1[i][k]);
            vB = _mm_loadu_si128((__m128i*)&mat2[k][j]); //how well does the k += 4 work here? Should it be unrolled?
            vR = _mm_add_epi32(vR, _mm_mul_epi32(vA, vB));
        }
        vR = _mm_hadd_epi32(vR, vR);
        vR = _mm_hadd_epi32(vR, vR);
        result[i][j] += _mm_extract_epi32(vR, 0);
    }
  }
}

我似乎无法让它给出正确的结果。我错过了什么吗? 搜索似乎有很大帮助 - 每个结果要么只做 4x4 矩阵、mat-vec,要么是一些不太可读且难以理解的特殊魔法......


你说得对,你的vB是问题所在。您正在加载 4 个连续的整数,但是mat2[k+0..3][j]不连续。你实际上得到了mat2[k][j+0..3].


我忘记什么对 matmul 有效。有时并行产生 4 个结果效果很好,而不是对每个结果进行水平求和。

转置输入矩阵之一是可行的,并且成本为 O(N^2)。这是值得的,因为这意味着 O(N^3) matmul 可以使用顺序访问,并且当前的循环结构变得 SIMD 友好。

还有更好的方法,例如在使用之前调换小块,这样当您再次读取它们时,它们在 L1 缓存中仍然是热的。或者循环遍历目标行并添加一个结果,而不是累积单个或一小组行*列点积的完整结果。缓存阻塞(又称为循环平铺)是良好的 matmul 性能的关键之一。也可以看看每个程序员都应该了解哪些关于内存的知识?附录中有一个缓存阻塞的 SIMD FP matmul 示例,没有转置。

关于使用 SIMD 和缓存阻塞优化矩阵乘法已有很多文章。我建议你用谷歌搜索一下。大多数情况下可能是在谈论 FP,但它也适用于整数。

(除了 SSE/AVX 仅具有用于 FP 的 FMA,而不具有用于 32 位整数的 FMA,并且 8 位和 16 位输入 PMADD 指令执行对的水平加法。)


实际上我认为你可以在这里并行产生 4 个结果,如果一个输入已被转置:

void matmulSSE(int mat1[N][N], int mat2[N][N], int result[N][N]) {

  for(int i = 0; i < N; ++i) {
    for(int j = 0; j < N; j+=4) {   // vectorize over this loop
        __m128i vR = _mm_setzero_si128();
        for(int k = 0; k < N; k++) {   // not this loop
            //result[i][j] += mat1[i][k] * mat2[k][j];
            __m128i vA = _mm_set1_epi32(mat1[i][k]);  // load+broadcast is much cheaper than MOVD + 3 inserts (or especially 4x insert, which your new code is doing)
            __m128i vB = _mm_loadu_si128((__m128i*)&mat2[k][j]);  // mat2[k][j+0..3]
            vR = _mm_add_epi32(vR, _mm_mullo_epi32(vA, vB));
        }
        _mm_storeu_si128((__m128i*)&result[i][j], vR));
    }
  }
}

广播加载(或没有 AVX 的单独加载+广播)仍然比聚集便宜得多。

您当前的代码通过 4 次插入进行收集,而不是通过对第一个元素使用 MOVD 来破坏上一次迭代值的依赖链,因此情况更糟。但与负载 + PUNPCKLDQ 相比,即使是 4 个分散元素的最佳聚集也相当糟糕。更不用说这使得您的代码需要 SSE4.1。

虽然无论如何它都需要SSE4.1_mm_mullo_epi32而不是扩大PMULDQ (_mm_mul_epi32).

请注意,整数乘法吞吐量通常比 FP 乘法差,尤其是在 Haswell 及更高版本上。 FP FMA 单元每个 32 位元素仅具有 24 位宽乘法器(对于 FP 尾数),因此将这些乘法器用于 32x32=>32 位整数需要拆分为两个微指令。

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

SSE 矩阵-矩阵乘法 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • BASIC 中的 C 语言中的 PeekInt、PokeInt、Peek、Poke 等效项

    我想知道该命令的等效项是什么Peek and Poke 基本和其他变体 用 C 语言 类似PeekInt PokeInt 整数 涉及内存条的东西 我知道在 C 语言中有很多方法可以做到这一点 我正在尝试将基本程序移植到 C 语言 这只是使用
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置

随机推荐

  • 将 ssh -V 保存到变量

    我正在尝试自动测试从 72 个远程服务器返回到中央服务器的无密码 ssh 我有中央服务器无密码 ssh 可以连接到 72 台服务器 但需要它从它们返回到中央服务器 72 台服务器有两个 ssh 版本之一 OpenSSH 4 3p2 Open
  • 通过单击外部关闭 div

    我想通过单击其中的关闭链接来隐藏 div or单击该 div 之外的任意位置 我正在尝试执行以下代码 它会通过正确单击关闭链接来打开和关闭 div 但如果我无法通过单击 div 外部的任何位置来关闭它 link click function
  • 如何将元素添加到通配符通用集合中?

    为什么此 Java 代码会出现编译器错误 1 public List
  • Typescript 文件无法在 Visual Studio 2015 的 Angular 2 上编译

    我跟着扎克的回答并创建新的 VS 2015 NET 5 项目并使用 Typescript 运行 Angular 2 看起来它正在工作 但有一个小问题 我的应用程序 ts import Component from angular2 core
  • 以编程方式禁用移动网络

    我正在开发一个应用程序 用户可以在单击按钮时启用 禁用移动网络 我用谷歌搜索了这个问题 但我只得到了飞行模式的解决方案 在飞行模式下 WI FI 和蓝牙也被禁用 我不希望他们通过使用飞行模式概念来禁用 我只想禁用移动网络 以编程方式实现它的
  • 如何在 for 循环中为文本添加动画效果?

    我正在尝试创建一个侧边栏动画效果 div class sidebar description sidebar personal info section A passionate span class changing keywords s
  • 如何使用 LINQ 删除列表中的最小值和最大值

    我有一个如下所示的列表 List
  • 如何在 Windows Azure 上使用 PHP 云服务访问 ConfigurationSettings?

    我希望能够从 Windows Azure 云服务 Web 角色 中的 PHP 应用程序内访问 ConfigurationSettings 但我似乎无法使其工作 我已在 ServiceDefinition csdef 中配置了此配置 并且在
  • Observable.ObserveOn() 似乎没有效果

    我正在尝试使用 Rx 并行处理项目 看来我无法告诉 Rx 并行运行我的观察者的 OnNext 这是测试代码来演示 Test public void ObservableObserveOnNewThreadRunsInParallel Con
  • 如何使用 Kotlin 谓词将列表拆分为子列表?

    我正在尝试一种惯用且理想的功能方式来将 Kotlin 中的列表拆分为子列表 想象一下输入是 aaa bbb ccc ddd eee fff 我想回来 aaa bbb ccc ddd eee fff 对于给定的谓词string isEmpty
  • 什么是 muiName 属性?何时必须为 Material-UI 组件设置它?

    在官方的material ui文档中 有一个例子AppBar成分here看起来像这样 import React Component from react import AppBar from material ui AppBar impor
  • ggplot2 - 可以通过计算的 y (stat_summary) 值重新排序 x 吗?

    是否可以通过 stat summary 使用计算出的 y 重新排序 x 值 我认为这应该有效 stat summary aes x reorder XVarName y 但我收到以下错误 错误 stat summary 需要以下缺失的美感
  • xpath:字符串操作

    因此 在我的 scrapy 项目中 我能够隔离一些特定字段 其中一个字段返回类似以下内容 Rank Info on 2013 06 27 14 26 Read 174 Times 通过表达式选择 td class show content
  • 相同连续数字的正则表达式

    我如何编写一个正则表达式来处理子字符串是 6 个或更多连续数字的所有实例 例如这样 000000 111111 222222 333333 444444 555555 I tried 0 9 6 我计划稍后对此进行否定 以便我可以在这些情况
  • 未找到致命错误“stdio.h”

    为什么我会收到此消息 编译器是 clang 的 这是一个简单的程序 出于示例目的 include
  • Django 为用户信号创建配置文件

    我尝试使用信号为用户帐户创建配置文件 但编写代码后根本没有创建 姜戈3 0 5 用户 模型 py from django db import models from django contrib auth models import Use
  • Selenium + VBA 控制 Chrome

    我使用 selenium vba 启动 chrome 以打开单元格范围 A1 A10 中列出的 10 个网址 我对硒不熟悉 经过多次尝试 我终于得出了下面笨重的代码 Private selenium As New ChromeDriver
  • 函数变量和应用中的 ()

    The 类型和功能讲座呈现函数 f44 gt Integer f44 44 我输入以下内容 ghci gt let f 5 ghci gt f 5 但是 我很困惑 in let f 通常 作为初学者 我见过函数名称后面有一个不可变变量 即f
  • 如何以编程方式设置 Jenkins Email-ext 插件的收件人?

    我正在尝试设置收件人Email ext aka Editable Email Notficiation 给失败测试的所有者 由于只有在构建失败后才能计算所有者 因此Inject Environment Variables插件无法使用 如何才
  • SSE 矩阵-矩阵乘法

    我在 C 中使用 SSE 进行矩阵 矩阵乘法时遇到问题 这是我到目前为止得到的 define N 1000 void matmulSSE int mat1 N N int mat2 N N int result N N int i j k