使用 Ivy Bridge 和 Haswell 循环展开以实现最大吞吐量

2023-12-09

我正在使用 AVX 同时计算八个点积。在我当前的代码中,我做了这样的事情(在展开之前):

常春藤桥/桑迪桥

__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {        
    __m256 breg0 = _mm256_load_ps(&b[8*i]);
    tmp0 = _mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0); 
}

Haswell

__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {      
    __m256 breg0 = _mm256_load_ps(&b[8*i]);
    tmp0 = _mm256_fmadd_ps(arge0, breg0, tmp0);
}

我需要为每种情况展开循环多少次才能确保最大吞吐量?

对于使用 FMA3 的 Haswell 我认为答案就在这里sandy-bridge 和 haswell SSE2/AVX/AVX2 每个周期的 FLOPS。我需要将循环展开 10 次。

对于 Ivy Bridge,我认为是 8。这是我的逻辑。 AVX 加法的延迟为 3,乘法的延迟为 5。Ivy Bridge 可以使用不同的端口同时执行一项 AVX 乘法和一项 AVX 加法。使用符号 m 表示乘法,a 表示加法,x 表示无运算以及表示部分和的数字(例如 m5 表示与第 5 个部分和相乘),我可以写:

port0:  m1  m2  m3  m4  m5  m6  m7  m8  m1  m2  m3  m4  m5  ... 
port1:   x   x   x   x   x  a1  a2  a3  a4  a5  a6  a7  a8  ...

因此,通过在 9 个时钟周期后使用 8 个部分和(四个来自加载,五个来自乘法),我可以在每个时钟周期提交一个 AVX 加载、一个 AVX 加法和一个 AVX 乘法。

我想这意味着 Ivy Bridge 和 Haswell 中的 32 位模式不可能实现该任务的最大吞吐量,因为 32 位模式只有 8 个 AVX 寄存器?

Edit:关于赏金。我的主要问题仍然存在。我想获得上面的 Ivy Bridge 或 Haswell 函数的最大吞吐量,n可以是大于或等于 64 的任何值。我认为这只能使用展开来完成(Ivy Bridge 为 8 次,Haswell 为 10 次)。如果您认为可以用其他方法来完成,那么让我们看看。从某种意义上说,这是一个变体如何实现每个周期理论最大 4 次 FLOP?。但我不仅仅需要乘法和加法,而是在 Ivy Bridge 的每个时钟周期寻找一个 256 位负载(或两个 128 位负载)、一个 AVX 乘法和一个 AVX 加法,或者两个 256 位负载和两个 FMA3 指令每个时钟周期。

我还想知道需要多少个寄存器。对于 Ivy Bridge,我认为是 10 个。一个用于广播,一个用于负载(由于寄存器重命名,只有一个),八个用于八个部分和。所以我认为这不能在 32 位模式下完成(事实上,当我在 32 位模式下运行时,性能会显着下降)。

我应该指出编译器可能会给出误导性的结果对于高度优化的矩阵乘法代码,MSVC 和 GCC 之间的性能差异

我当前用于 Ivy Bridge 的函数如下。这基本上是将 64x64 矩阵的一行相乘a全部为 64x64 矩阵b(我在每一行上运行这个函数 64 次a得到矩阵中的完整矩阵乘法c).

#include <immintrin.h>
extern "C" void row_m64x64(const float *a, const float *b, float *c) {      
    const int vec_size = 8;
    const int n = 64;
    __m256 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
    tmp0 = _mm256_loadu_ps(&c[0*vec_size]);
    tmp1 = _mm256_loadu_ps(&c[1*vec_size]);
    tmp2 = _mm256_loadu_ps(&c[2*vec_size]);
    tmp3 = _mm256_loadu_ps(&c[3*vec_size]);
    tmp4 = _mm256_loadu_ps(&c[4*vec_size]);
    tmp5 = _mm256_loadu_ps(&c[5*vec_size]);
    tmp6 = _mm256_loadu_ps(&c[6*vec_size]);
    tmp7 = _mm256_loadu_ps(&c[7*vec_size]);

    for(int i=0; i<n; i++) {
        __m256 areg0 = _mm256_set1_ps(a[i]);

        __m256 breg0 = _mm256_loadu_ps(&b[vec_size*(8*i + 0)]);
        tmp0 = _mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0);    
        __m256 breg1 = _mm256_loadu_ps(&b[vec_size*(8*i + 1)]);
        tmp1 = _mm256_add_ps(_mm256_mul_ps(areg0,breg1), tmp1);
        __m256 breg2 = _mm256_loadu_ps(&b[vec_size*(8*i + 2)]);
        tmp2 = _mm256_add_ps(_mm256_mul_ps(areg0,breg2), tmp2);    
        __m256 breg3 = _mm256_loadu_ps(&b[vec_size*(8*i + 3)]);
        tmp3 = _mm256_add_ps(_mm256_mul_ps(areg0,breg3), tmp3);   
        __m256 breg4 = _mm256_loadu_ps(&b[vec_size*(8*i + 4)]);
        tmp4 = _mm256_add_ps(_mm256_mul_ps(areg0,breg4), tmp4);    
        __m256 breg5 = _mm256_loadu_ps(&b[vec_size*(8*i + 5)]);
        tmp5 = _mm256_add_ps(_mm256_mul_ps(areg0,breg5), tmp5);    
        __m256 breg6 = _mm256_loadu_ps(&b[vec_size*(8*i + 6)]);
        tmp6 = _mm256_add_ps(_mm256_mul_ps(areg0,breg6), tmp6);    
        __m256 breg7 = _mm256_loadu_ps(&b[vec_size*(8*i + 7)]);
        tmp7 = _mm256_add_ps(_mm256_mul_ps(areg0,breg7), tmp7);    
    }
    _mm256_storeu_ps(&c[0*vec_size], tmp0);
    _mm256_storeu_ps(&c[1*vec_size], tmp1);
    _mm256_storeu_ps(&c[2*vec_size], tmp2);
    _mm256_storeu_ps(&c[3*vec_size], tmp3);
    _mm256_storeu_ps(&c[4*vec_size], tmp4);
    _mm256_storeu_ps(&c[5*vec_size], tmp5);
    _mm256_storeu_ps(&c[6*vec_size], tmp6);
    _mm256_storeu_ps(&c[7*vec_size], tmp7);
}

对于 Sandy/Ivy Bridge,您需要按 3 展开:

  • 只有 FP Add 依赖于循环的前一个迭代
  • FP Add可以在每个周期发出
  • FP Add 需要三个周期才能完成
  • 因此按 3/1 = 3 展开完全隐藏了延迟
  • FP Mul 和 FP Load 不依赖于先前的迭代,您可以依靠 OoO 核心以接近最优的顺序发出它们。仅当这些指令降低了 FP Add 的吞吐量时,它们才会影响展开因子(此处情况并非如此,FP Load + FP Add + FP Mul 可以在每个周期发出)。

对于 Haswell,您需要按 10 展开:

  • 只有 FMA 依赖于循环的前一次迭代
  • FMA 可以在每个周期重复发出(即平均独立指令需要 0.5 个周期)
  • FMA 的延迟为 5
  • 因此按 5/0.5 = 10 展开完全隐藏了 FMA 延迟
  • 这两个 FP Load 微操作不依赖于之前的迭代,并且可以与 2x FMA 共同发布,因此它们不会影响展开因子。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Ivy Bridge 和 Haswell 循环展开以实现最大吞吐量 的相关文章

  • 尚未注册类型“IServiceProviderFactory[Autofac.ContainerBuilder]”的服务

    当运行以下命令添加数据库迁移脚本时 出现以下错误 dotnet ef migrations add InitialCreate v o Migrations context MyContext 访问 Microsoft Extensions
  • 有没有快速创建集合的方法?

    目前我正在创建一个像这样的新集 std set a s s insert a1 s insert a2 s insert a3 s insert a10 有没有办法创建s在一行 int myints 10 20 30 40 50 std s
  • 何时使用 =default 使析构函数默认?

    尽管对构造函数使用 default 对我来说很清楚 即强制编译器在其他构造函数存在时创建默认构造函数 但我仍然无法理解这两种类型的析构函数之间的区别 那些使用 default 的 那些没有显式定义并由编译器自动生成的 我唯一想到的是 gro
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • VS 程序在调试模式下崩溃,但在发布模式下不崩溃?

    我正在 VS 2012 中运行以下程序来尝试 Thrust 函数查找 include cuda runtime h include device launch parameters h include
  • 读取 C# 中的默认应用程序设置

    我的自定义网格控件有许多应用程序设置 在用户范围内 其中大部分是颜色设置 我有一个表单 用户可以在其中自定义这些颜色 并且我想添加一个用于恢复默认颜色设置的按钮 如何读取默认设置 例如 我有一个名为的用户设置CellBackgroundCo
  • 信号处理程序有单独的堆栈吗?

    信号处理程序是否有单独的堆栈 就像每个线程都有单独的堆栈一样 这是在 Linux C 环境中 来自 Linux 手册页signal 7 http kernel org doc man pages online pages man7 sign
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 找不到 assimp-vc140-mt.dll ASSIMP

    我已经从以下位置下载了 Assimp 项目http assimp sourceforge net main downloads html http assimp sourceforge net main downloads html Ass
  • 单例模式和 std::unique_ptr

    std unique ptr唯一地控制它指向的对象 因此不使用引用计数 单例确保利用引用计数只能创建一个对象 那么会std unique ptr与单例执行相同 单例确保只有一个实例属于一种类型 A unique ptr确保只有一个智能指针到
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • 运行选定的代码生成器时出错:“未将对象引用设置到对象的实例。”错误?

    我已经尝试了所有解决方案 例如修复 VS 2013 但没有用 当您通过右键单击控制器文件夹来创建控制器并添加控制器时 然后右键单击新创建的控制器的操作并选择添加视图 当我尝试创建视图时 就会发生这种情况 它不是一个新项目 而是一个现有项目
  • 是否有相当于 Clang/LLVM 的 .spec 文件,在哪里可以找到参考?

    The gcc驱动程序可以配置为使用特定的链接器 特定的选项和其他细节 例如覆盖系统头 specs files 当前 截至撰写本文时 GCC 版本 4 9 0 的手册此处描述了规范文件 https gcc gnu org onlinedoc
  • cout 和字符串连接

    我刚刚复习了我的 C 我尝试这样做 include
  • 更改 Windows Phone 系统托盘颜色

    有没有办法将 Windows Phone 上的系统托盘颜色从黑色更改为白色 我的应用程序有白色背景 所以我希望系统托盘也是白色的 您可以在页面 XAML 中执行此操作
  • 如何在 DropDownList 中保留空格 - ASP.net MVC Razor 视图

    我在视图中通过以下方式绑定我的模型 问题是我的项目文本是格式化文本 单词之间有空格 如下所示 123 First 234 00 123 AnotherItem 234 00 123 Second 234 00 我想保留此项目文本中的空格 即
  • 将 char[][] 转换为 char** 会导致段错误吗?

    好吧 我的 C 有点生疏了 但我想我应该用 C 来做我的下一个 小 项目 这样我就可以对其进行抛光 并且我已经有不到 20 行的段错误了 这是我的完整代码 define ROWS 4 define COLS 4 char main map
  • C++0x中disable_if在哪里?

    Boost 两者都有enable if and disable if 但 C 0x 似乎缺少后者 为什么它被排除在外 C 0x 中是否有元编程工具允许我构建disable if按照enable if 哦 我刚刚注意到std enable i
  • 使我的 COM 程序集调用异步

    我刚刚 赢得 了在当前工作中维护用 C 编码的遗留库的特权 这个dll 公开使用 Uniface 构建的大型遗留系统的方法 除了调用 COM 对象之外别无选择 充当此遗留系统与另一个系统的 API 之间的链接 在某些情况下 使用 WinFo

随机推荐

  • ASP.NET Core:从 GET 重定向到 POST

    我想打电话MarriageById作为 GET 像这样 var url MarriageById id id 但我也想拥有一个ActionResult Marriage Marriage marriage 在显示视图之前会进行一些处理 这第
  • 为什么使用 Prism EventAggregator 时未调用我的 Subscribe 方法?

    我正在学习棱镜 几个小时后我就遇到了一个问题 订阅事件时 订阅方法没有被调用 我在用Prism and Autofac 在下面的简化示例中 主视图模型 Publish dupa 事件被称为ctor 然后单击按钮更新窗口被打开 在窗口的后端创
  • 在 VBA 中编程多个 .FindNext

    我对VBA相对缺乏经验 但通常可以完成简单的任务 我目前在使用 Find 函数时遇到问题 我知道 excel 没有能力执行两次 finds 但我在为第二次查找编写循环时遇到问题 到目前为止我的代码在这里 Dim j As Integer D
  • eclipse 没有为其中开发的任何应用程序生成 apk 文件吗?

    我一直在使用 eclipse IDE 在 android 中开发一些应用程序 所有这些应用程序在模拟器上运行良好 但 eclipse 没有生成它们的 apk 文件 并且我无法在任何设备中安装应用程序 此外 在模拟器上运行应用程序时 它不会给
  • 阻止外部访问 PHP 脚本但允许 AJAX

    我读了很多关于 htaccess 规则 检查标头 使用加密等的内容 但我还没有找到我想要的答案 我知道 假设服务器设置正确 您将无法使用 AJAX 访问我珍贵的 PHP 脚本 我尝试检查是否定义了一个访问变量 该变量不允许地址栏访问 但也阻
  • 在express.js上启用HTTPS

    我正在尝试让 HTTPS 在 Express js 上为 Node 工作 但我无法弄清楚 这是我的app js code var express require express var fs require fs var privateKe
  • Android KSOAP2 抛出 SocketTimeoutException

    我在我的 Android 项目中使用了上述 SOAP 对象库 以便连接到 NET Web 服务 该应用程序运行良好 直到我做了一些更改并增加 减少了目标 API 它开始抛出 SocketTimeoutException 并且不会消失 我在用
  • 选择firstChild和空格问题

    我有一个这样的标记 table thead tr td Hello td tr thead table 但是当我尝试选择第一个孩子时 table 它返回空格 正如预期的那样 var ss document getElementById my
  • 样式下拉(选择)框

    我知道使用 jquery 可以制作一些看起来像选择框的东西 这样我就可以让它看起来像我想要的那样 然而 如果只有 css 我有多少控制权 我使用了边框 内边距和宽度 最终结果看起来很棒 唯一让我烦恼的是掉落的部分 这有什么控制吗 有填充看起
  • 调用open时如何调用sys_open而不是sys_openat

    我编写了一段代码来生成系统调用 void open test int fd const char filepath if fd 1 printf Open s Failed n filepath else printf Successful
  • 带有有效负载或表单数据的 DELETE 请求会导致错误请求

    我正在使用 Java Jersey 2 17 构建 RESTful Web 服务 客户端 我正在使用 ExtJS 5 进行开发 我的服务课程 主程序 java public class Main public static final St
  • 如何使用正则表达式通过 jQuery 通过 ID 选择元素?

    我有以下输入元素
  • 以编程方式启用/禁用多点触控手指输入?

    我有一台运行 Windows 7 且支持多点功能的平板电脑 然而 当使用手写笔并距离显示器太远时 我经常会不小心用手指敲击它 从而导致不必要的鼠标点击 解决方案是导航到 控制面板 笔和手指输入 手指输入 然后停用 使用手指作为输入设备 复选
  • mysql负载测试工具

    我想计算表的每行大小 有没有可用的工具 还有人知道任何负载测试工具吗 提前致谢 问候 玛纳西 计算平均行大小 SHOW TABLE STATUS FROM databasename LIKE pattern 超级一击是 MySQL 和 Po
  • 检测耳机是否插入 iOS 设备

    iOS 设备上有互动电影 当电影开始时 点击 视频开始的那个人会问你插入耳机 如果插入 那么视频应该自动跳到故事 直接转到视频故事 我应该怎么办 以及如何编写代码 首先 您必须注册 AudioRoute 更改 AudioSessionAdd
  • JS:在文本中查找 URL,创建链接

    下面用 JS 重写的 PHP 代码是什么 以便文本 blob 内的 url 链接可以替换为 html 链接 我已经开始了jsfiddle
  • 更改PIL模块中的图像颜色

    我正在尝试改变颜色的强度以获得不同颜色的图像 import PIL from PIL import Image from PIL import ImageEnhance from PIL import ImageDraw read imag
  • 如何禁止从 Angular JS 下拉列表中选择特定选项?

    我想从 AngularJS 下拉列表中禁用特定选项 它应该列在下拉列表中 但不应允许选择它 所以我需要禁用它 我的文件 tpl html
  • 重复本地通知不更新内容

    我制作了一个应用程序 每天上午 9 点发送一条本地通知 向用户显示随机素数 问题是显示的数字始终相同 创建通知请求的代码仅被调用一次 这是我所期望的 因为通知是重复的 那么我如何更新其内容 我可以提供生成随机素数的代码 但我已经测试过它并且
  • 使用 Ivy Bridge 和 Haswell 循环展开以实现最大吞吐量

    我正在使用 AVX 同时计算八个点积 在我当前的代码中 我做了这样的事情 在展开之前 常春藤桥 桑迪桥 m256 areg0 mm256 set1 ps a m for int i 0 i