SSE,行主要与列主要性能问题

2024-04-20

出于个人和娱乐目的,我正在使用 SSE(4.1) 编写一个 geom 库。

我花了最后 12 个小时试图理解处理行主要与列主要存储矩阵时的性能问题。

我知道 Dirext/OpenGL 矩阵是以行主顺序存储的,因此对我来说,将矩阵按行主顺序存储会更好,这样在将矩阵存储到 GPU/着色器或从 GPU/着色器加载矩阵时就不会进行转换。

但是,我做了一些分析,并且我通过专栏专业获得了更快的结果。

要使用行主变换矩阵变换一个点,它是 P' = P * M。而在列主变换矩阵中,它是 P' = M * P。 因此,在列专业中,它只是 4 点积,因此在行专业中,只有 4 个 SSE4.1 指令 (_mm_dp_ps ),我必须在转置矩阵上执行这 4 个点积。

10M 向量的性能结果

(30/05/2014@08:48:10)日志:[5](Vec.Mul.Matrix)= 76.216653 ms(行主要变换)

(30/05/2014@08:48:10)日志:[6](Matrix.Mul.Vec)= 61.554892 ms(列主要变换)

我尝试了几种方法来进行 Vec * Matrix 操作,使用或不使用 _MM_TRANSPOSE ,我发现最快的方法是这样的:

mssFloat    Vec4::operator|(const Vec4& v) const //-- Dot Product
{
    return _mm_dp_ps(m_val, v.m_val, 0xFF ).m128_f32[0];
}
inline Vec4 operator*(const Vec4& vec,const Mat4& m)
{
    return Vec4(    Vec4( m[0][0],m[1][0],m[2][0],m[3][0]) | vec
        ,   Vec4( m[0][1],m[1][1],m[2][1],m[3][1]) | vec
        ,   Vec4( m[0][2],m[1][2],m[2][2],m[3][2]) | vec
        ,   Vec4( m[0][3],m[1][3],m[2][3],m[3][3]) | vec
                );
}

我的类 Vec4 只是一个 __m128 m_val,在优化的 C++ 中,向量构造都是在 SSE 寄存器上有效完成的。

我的第一个猜测是,这种乘法不是最佳的。我是 SSE 的新手,所以我有点困惑如何优化它,我的直觉告诉我使用 shuffle 指令,但我想了解为什么它会更快。它会比分配更快地加载 4 shuffle __m128 ( __m128 m_val = _mm_set_ps(w, z, y, x); )

From https://software.intel.com/sites/landingpage/IntrinsicsGuide/ https://software.intel.com/sites/landingpage/IntrinsicsGuide/我找不到 mm_set_ps 的性能信息

编辑:我仔细检查分析方法,每个测试都以相同的方式完成,因此没有内存缓存差异。为了避免本地缓存,我正在对随机错误向量数组进行操作,每个测试的种子都是相同的。每次执行时仅进行 1 次测试,以避免内存缓存提高性能。


不要使用_mm_dp_ps用于矩阵乘法!我已经在以下位置详细解释了这一点使用 SSE 进行高效 4x4 矩阵向量乘法:水平加法和点积 - 有什么意义? https://stackoverflow.com/questions/14967969/efficient-4x4-matrix-vector-multiplication-with-sse-horizontal-add-and-dot-prod(顺便说一下,这是我关于 SO 的第一篇文章)。

除了 SSE 之外,您不需要任何其他东西就可以有效地完成此操作(甚至不需要 SSE2)。使用此代码可以高效地执行 4x4 矩阵乘法。如果矩阵按行优先顺序存储,则gemm4x4_SSE(A,B,C)。如果矩阵按列优先顺序存储,则gemm4x4_SSE(B,A,C).

void gemm4x4_SSE(float *A, float *B, float *C) {
    __m128 row[4], sum[4];
    for(int i=0; i<4; i++)  row[i] = _mm_load_ps(&B[i*4]);
    for(int i=0; i<4; i++) {
        sum[i] = _mm_setzero_ps();      
        for(int j=0; j<4; j++) {
            sum[i] = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(A[i*4+j]), row[j]), sum[i]);
        }           
    }
    for(int i=0; i<4; i++) _mm_store_ps(&C[i*4], sum[i]); 
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SSE,行主要与列主要性能问题 的相关文章

  • 起订量要求?违背了目的?

    是否需要虚拟化您想要模拟的所有属性访问器就违背了模拟的目的 我的意思是 如果我必须修改我的对象并虚拟化我想要模拟的每个访问器 我难道不能继承我的类并自己模拟它吗 你的问题非常有效 但如果你仔细想想 没有其他方法可以模拟课程 如果你采用一个接
  • 如何将十六进制字符串转换为十六进制数字[重复]

    这个问题在这里已经有答案了 可能的重复 如何将十六进制字符串转换为有符号整数 https stackoverflow com questions 3705429 how do i convert hex string into signed
  • 获取 std::variant 当前持有的 typeid(如 boost::variant type())

    我已经从 boost variant 迁移到 std variant 但遇到了障碍 我在 boost type 中使用了一个很好的函数 它可以让你获取当前持有的 typeid 看https www boost org doc libs 1
  • 使用API​​隐藏程序标题栏

    它可以使用 c 和 windows api 删除窗口控制台标题栏 如果是的话如何 请 这个简单的应用程序隐藏并显示其所在控制台的标题栏 它会立即将控制台标题更改为 guid 以查找窗口句柄 然后 它使用 ToggleTitleBar 使用找
  • 是否允许将类模板类型参数键入相同的名称?

    这似乎可以在 MSVC 中按预期编译甚至工作 但它是合法的 C 代码吗 它是否能保证执行此处所期望的操作 即将模板类型导出到结构体的同名用户 template
  • 使用 OpenGL 着色器进行数学计算 (C++)

    我有一个矩阵 例如 100x100 尺寸 我需要对每个元素进行计算 matrix i j tt 8 5例如 我有一个巨大的矩阵 我想使用 OpenGL 着色器来实现该算法 我想使用着色器 例如 uniform float val unifo
  • 在Application_AquireRequestState事件中用POST数据重写Url

    我有一个在其中注册路线的代码Application AcquireRequestState应用程序的事件 注册路由后 我会在 Http 运行时缓存中设置一个标志 这样我就不会再次执行路由注册代码 在此事件中注册路线有特定原因Applicat
  • 矩阵向量变换

    我正在编写一个代码来制作软件蒙皮器 骨骼 皮肤动画 并且我正处于 优化 阶段 蒙皮器工作得很好 并且在 Core 上 1 09 毫秒内对 4900 个三角形网格与 22 个骨骼进行蒙皮Duo 2 Ghz 笔记本 我需要知道的是 1 有人可以
  • 是否有像 gccxml 这样的用于生成包装器的 C 标头解析器工具?

    我需要为一种新的编程语言编写一些 C 标头包装器 并且想要类似 gccxml 的东西 但不完全依赖 gcc 以及它在 Windows 系统上带来的问题 只需要读C而不是C 只要有完整的文档记录 任何格式的输出都可以 Linux Solari
  • C# datagridview 列转入数组

    我正在用 C 构建一个程序 并在其中包含一个 datagridview 组件 datagridview 有固定数量的列 2 我想将其保存到两个单独的数组中 但行数确实发生了变化 我怎么能这样做呢 假设一个名为 dataGridView1 的
  • 无法加载文件或程序集“EntityFramework,版本=6.0.0.0”

    我究竟做错了什么 我该如何解决这个问题 我有一个包含多个项目的解决方案 它是一个 MVC NET 4 5 Web 应用程序 在调试模式下启动后调用其中一个项目时 出现此错误 导致此错误的项目具有以下参考 两个都是版本6 0 0 0 应用程序
  • 在简单注入器中注册具有多个构造函数和字符串依赖项的类型

    我正在尝试弄清楚如何使用 Simple Injector 我在项目中使用了它 注册简单服务及其组件没有任何问题 但是 当组件具有两个以上实现接口的构造函数时 我想使用依赖注入器 public DAL IDAL private Logger
  • dropdownlist DataTextField 由属性组成?

    有没有一种方法可以通过 C 使 asp net 中的下拉列表的 datatextfield 属性由对象的多个属性组成 public class MyObject public int Id get set public string Nam
  • 错误左值需要作为赋值C++的左操作数

    整个程序基本上只允许用户移动光标 如果用户位于给定的坐标范围 2 2 内 则允许用户键入输入 我刚刚提供了一些我认为足以解决问题的代码 我不知道是什么导致了这个问题 你能解释一下为什么会发生吗 void goToXY int int 创建一
  • 将非算术类型作为参数传递给 cmath 函数是否有效?

    给定以下用户定义类型S具有转换功能double struct S operator double return 1 0 以及以下调用cmath http en cppreference com w cpp header cmath使用类型的
  • 相当于 C# 中 Java 的“ByteBuffer.putType()”

    我正在尝试通过从 Java 移植代码来格式化 C 中的字节数组 在 Java 中 使用方法 buf putInt value buf putShort buf putDouble 等等 但我不知道如何将其移植到 C 我尝试过 MemoryS
  • TPL 数据流块下游如何获取源生成的数据?

    我正在使用 TPL Dataflow 处理图像 我收到处理请求 从流中读取图像 应用多次转换 然后将生成的图像写入另一个流 Request gt Stream gt Image gt Image gt Stream 为此 我使用块 Buff
  • g++ C++0x 枚举类编译器警告

    我一直在将可怕的 C 类型安全伪枚举重构为新的 C 0x 类型安全枚举 因为它们是way更具可读性 不管怎样 我在导出的类中使用它们 所以我明确地将它们标记为导出 enum class attribute visibility defaul
  • 无法使 Polly 超时策略覆盖 HttpClient 默认超时

    我正在使用 Polly 重试策略 并且正如预期的那样 在重试过程中HttpClient达到 100 秒超时 我尝试了几种不同的方法来合并 Polly 超时策略 将超时移至每次重试而不是总计 但 100 秒超时仍然会触发 我读过大约 5 个
  • FindAsync 很慢,但是延迟加载很快

    在我的代码中 我曾经使用加载相关实体await FindAsync 希望我能更好地遵守 C 异步指南 var activeTemplate await exec DbContext FormTemplates FindAsync exec

随机推荐

  • 对 xhtml5 感到困惑:不再有“”,现在强制使用“meta”?

    我已经是长期用户XHTML 1 0 Strict 我现在正尝试在我的新项目中切换到 XHTML5 我很困惑对于 HTML5 不再被认为是有效的http validator w3 org http validator w3 org 这是为什么
  • 我无法更新 Google App 脚本上的脚本

    我在公司使用Google App 更新脚本时经常遇到问题 当我更新我的脚本时 我在 Google 网站上的网页没有更新 而且很长一段时间 更新脚本时我必须创建一个新脚本 我可以解决这个问题吗 regards 有两种方法可以publish你的
  • 如何更轻松地在 Emacs 中的缓冲区之间切换?

    我最近开始使用 emacs 并且大部分时间我都很享受使用它 我唯一不喜欢的是在缓冲区之间切换 我经常打开一些缓冲区 并且我已经厌倦了使用C x b and C x C b 是否有任何软件包可以使缓冲区之间的切换变得更容易 我调查过emacs
  • 测试应用程序的可访问性(对讲)

    我正在使我的应用程序可访问性兼容 为此 通过在 xml 中提供 android contentDescription your string 来向可访问性框架提供正确的数据 我还看到了关于使应用程序可访问的 Android 开发人员指南 概
  • 沟通差距:用户与分析师-设计师

    通常的做法是使用案例研究 构建工作流和数据流等 但这并不一定会在用户 发起者和分析师 设计者之间创建共享词汇表 通常 其中一方都必须获得其他专业领域 内部 的术语和观点 这通常会导致误解和澄清会议 进入 RAD 技术 如进化原型 等 用户
  • 在Java中声明布尔变量的正确方法是什么?

    我刚刚开始学习Java 在我关注的在线课程中 我被要求尝试以下代码 String email1 email protected cdn cgi l email protection String email2 email protected
  • Sklearn LogisticRegressionCV 的类似数组的输入

    最初 我从a读取数据 csv文件 但在这里我从列表构建数据框 以便可以重现问题 目的是使用交叉验证来训练逻辑回归模型LogisticRegressionCV indeps M F M F M M F M M F F F F F M F F
  • 使用 Numpy for Python 创建 cx_Freeze exe

    我正在尝试使用 cx Freeze 创建一个基本的 exe 它适用于没有 numpy 的 py 程序 但我无法使用 numpy 正确制作一个程序 有想法该怎么解决这个吗 我需要在 setup py 中包含一些内容吗 当我去运行 exe 时
  • 更改传单归属控制位置

    我在我的应用程序中使用 WebView 来显示传单地图 在 HTML 文件中 我有以下制作人员和链接 L tileLayer https api tiles mapbox com v4 id z x y png access token x
  • 使用 LLVM 为整个源代码生成 CFG

    LLVM 社区的任何人都知道是否有一种方法可以使用以下方法为整个输入源代码生成 CFG opt dot cfg foo ll bc 由于此函数为每个函数生成 CFG 因此函数之间的连接将被忽略 看来旧的分析工具已经贬值了 我想知道你是否找到
  • 使用 highcharts 在堆栈标签中显示特定系列值

    这是我正在处理的内容 http jsfiddle net josip0423 prJjY 171 http jsfiddle net josip0423 prJjY 171 过去几个小时我一直在努力解决这个问题 但一无所获 我对 javas
  • C# 异步操作

    实际上我很难理解 BeginInvoke 和 EndInvoke 对 class AsynchronousDemo public delegate void DemoDelegate static void Main DemoDelegat
  • glGenerateMipmap 是否在 sRGB 纹理的线性空间中执行平均?

    OpenGL 3 3 规范似乎没有要求 mipmap 生成在线性空间中完成 我能找到的只有以下内容 派生的 mipmap 数组的内部格式都与 levelbase 数组和派生数组的维度如下 第 3 8 14 节中描述的要求 的内容 派生数组是
  • GPS 坐标(以度为单位)来计算距离

    在iPhone上 我以十进制度数获取用户的位置 例如 纬度39 470920和经度 0 373192 也就是A点 我需要用另一个 GPS 坐标 同样以十进制表示 B 点创建一条线 然后 计算从 A 到 B 的线与另一个点 C 之间的距离 垂
  • 在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda

    首先请注意 我并不期待why do you want to obfuscate library评论 这是我要问的一个真正的问题 我在使用 Kotlin 编写的 Android 库处理 R8 混淆时遇到了问题 我有一个公共 API 方法 其注
  • 使用 C# 不使用 xslt 将 XML 转换为 CSV

    我一直在网上搜索 我假设有人必须在我之前需要这个并且做得更好 以获取 xml 到 csv 转换器 我有一个非常标准的 xml 如下
  • IE7 大纲:0 不工作

    我知道大纲是用于可访问性的 但还有另一种方法 a outline 0 可以在 IE7 中运行的东西 也许使用 Jquery 对于 jquery 你可以尝试这样的事情 a focus function this blur 它本质上与 IE 7
  • 决定要 #include 哪些标准头文件

    假设我正在编辑一些大型 C 源文件 并且我添加了几行碰巧使用的代码auto ptr 如下例所示 include
  • c中前缀和后缀的优先级和结合性

    int main char arr geeksforgeeks char ptr arr while ptr 0 ptr printf s s arr ptr getchar return 0 while循环内的语句 ptr 我不明白的行为
  • SSE,行主要与列主要性能问题

    出于个人和娱乐目的 我正在使用 SSE 4 1 编写一个 geom 库 我花了最后 12 个小时试图理解处理行主要与列主要存储矩阵时的性能问题 我知道 Dirext OpenGL 矩阵是以行主顺序存储的 因此对我来说 将矩阵按行主顺序存储会