向量化模运算

2023-11-23

我正在尝试编写一些相当快速的分量向量加法代码。我正在使用(我相信是有符号的)64 位整数。

函数是

void addRq (int64_t* a, const int64_t* b, const int32_t dim, const int64_t q) {
    for(int i = 0; i < dim; i++) {
        a[i] = (a[i]+b[i])%q; // LINE1
    }
}

我正在编译icc -std=gnu99 -O3(icc,以便我稍后可以使用 SVML)在 IvyBridge(SSE4.2 和 AVX,但不是 AVX2)上。

我的基线是删除%q来自 LINE1。 100 个(迭代)函数调用dim=11221184需要 1.6 秒。 ICC 自动矢量化 SSE 代码;伟大的。

不过我真的很想做模块化添加。随着%q,ICC 不会自动矢量化代码,并且运行时间为 11.8 秒(!)。即使忽略之前尝试的自动矢量化,这仍然看起来有些过分。

由于我没有 AVX2,因此使用 SSE 进行矢量化需要 SVML,这也许就是 ICC 不自动矢量化的原因。无论如何,这是我对内部循环进行矢量化的尝试:

__m128i qs = _mm_set1_epi64x(q);
for(int i = 0; i < dim; i+=2) {
    __m128i xs = _mm_load_si128((const __m128i*)(a+i));
    __m128i ys = _mm_load_si128((const __m128i*)(b+i));
    __m128i zs = _mm_add_epi64(xs,ys);
    zs = _mm_rem_epi64(zs,qs);
    _mm_store_si128((__m128i*)(a+i),zs);
}

主循环的汇编是:

..B3.4:                         # Preds ..B3.2 ..B3.12
    movdqa    (%r12,%r15,8), %xmm0                          #59.22
    movdqa    %xmm8, %xmm1                                  #60.14
    paddq     (%r14,%r15,8), %xmm0                          #59.22
    call      __svml_i64rem2                                #61.9
    movdqa    %xmm0, (%r12,%r15,8)                          #61.36
    addq      $2, %r15                                      #56.30
    cmpq      %r13, %r15                                    #56.24
    jl        ..B3.4        # Prob 82%                      #56.24

因此代码正在按预期进行矢量化。我知道由于 SVML,我可能无法获得 2 倍的加速,但代码运行时间为 12.5 秒,比根本没有矢量化的情况慢!这真的是这里能做到的最好的事情吗?


SSE2 和 AVX2 都没有整数除法指令。 Intel 将 SVML 函数称为“内在函数”是不诚实的,因为其中许多函数都是复杂的函数,映射到多个指令,而不仅仅是几个指令。

有一种方法可以使用 SSE2 或 AVX2 进行更快的除法(和取模)。请参阅本文改进了不变整数除法。基本上,您预先计算除数,然后进行乘法。预先计算除数需要时间,但对于某个值dim在你的代码中它应该胜出。我在这里更详细地描述了这个方法SSE整数除法?我也在素数查找器中成功实现了这个方法使用 SIMD 查找素数列表 - SSE/AVX

Agner Fog 在他的代码中实现了 32 位(但不是 64 位)除法矢量类使用该论文中描述的方法。如果您想要一些代码,那么这将是一个很好的起点,但您必须将其扩展到 64 位。

编辑:根据 Mysticial 的评论并假设输入已经减少,我为 SSE 制作了一个版本。如果这是在 MSVC 中编译的,那么它需要处于 64 位模式,因为 32 位模式不支持_mm_set1_epi64x。这可以针对 32 位模式进行修复,但我不想这样做。

#ifdef _MSC_VER 
#include <intrin.h>
#endif
#include <nmmintrin.h>                 // SSE4.2
#include <stdint.h>
#include <stdio.h>

void addRq_SSE(int64_t* a, const int64_t* b, const int32_t dim, const int64_t q) {
    __m128i q2 = _mm_set1_epi64x(q);
    __m128i t2 = _mm_sub_epi64(q2,_mm_set1_epi64x(1));
    for(int i = 0; i < dim; i+=2) {
        __m128i a2 = _mm_loadu_si128((__m128i*)&a[i]);
        __m128i b2 = _mm_loadu_si128((__m128i*)&b[i]);
        __m128i c2 = _mm_add_epi64(a2,b2);
        __m128i cmp = _mm_cmpgt_epi64(c2, t2);
        c2 = _mm_sub_epi64(c2, _mm_and_si128(q2,cmp));
        _mm_storeu_si128((__m128i*)&a[i], c2);
    }
}

int main() {
    const int64_t dim = 20;
    int64_t a[dim];
    int64_t b[dim];
    int64_t q = 10;

    for(int i=0; i<dim; i++) {
        a[i] = i%q; b[i] = i%q;
    }
    addRq_SSE(a, b, dim, q);
    for(int i=0; i<dim; i++) {
        printf("%d\n", a[i]);
    }   
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

向量化模运算 的相关文章

随机推荐

  • 在 Capistrano 3 中永久切换用户(单独授权和部署)

    我们在服务器管理中有以下模式 所有用户都有自己的用户 但部署完全由特殊的部署用户执行 无法直接登录 我们在 Capistrano 2 x 中使用了这个方法 default run options shell sudo u deploy ba
  • 使用Unity将对象注入到IValueConverter实例中

    我在 Silverlight 5 项目中有一个 IValueConverter 实例 它将自定义数据转换为不同的颜色 我需要从数据库中读取实际的颜色值 因为这些值可以由用户编辑 由于 Silverlight 使用异步调用通过实体框架从数据库
  • 如何使元素水平和垂直居中

    我试图将选项卡内容垂直居中 但是当我添加 CSS 样式时display inline flex 水平文本对齐消失 如何为每个选项卡同时进行 x 和 y 文本对齐 box sizing border box leftFrame backgro
  • Flutter 中已弃用“canLaunch”

    我用过网址启动器包裹 String query Uri encodeComponent Utils getSelectedStoreAddress var appleUrl maps q query var googleUrl https
  • Primefaces p:fileUpload 在 IE 10 中不起作用

    p fileUpload 中的更新属性和 onComplete 在 IE10 中不起作用 在 IE 9 中 sizeLimit 属性被忽略 有谁遇到过这种情况吗 我尝试通过在 p fileUoload 上使用 onComplete 属性来调
  • 如何在Python中查找两个日期之间的星期一或任何其他工作日的数量?

    我有两个日期 我需要找出有多少个周一至周五到来 除周六 周日 每天都应该计算在内 目前我在想 import calendar import datetime start date datetime datetime strptime 01
  • 如何在带有 Entity Framework Core 1.0 (EF7) 的脚手架 DbContext 中使用数据库视图

    很遗憾实体框架核心 1 0 以前称为实体框架 7 尚不支持视图 我正在尝试使用表来 伪造 它 然而脚手架dotnet dbcontext ef scaffold命令当前无法识别或生成视图 我想要一个允许查询视图和更新表的 DbContext
  • 在 getStaticProps 函数中序列化 Next.js 时出错?

    我在用着getStaticProps 函数 我无缘无故地收到此错误 错误 序列化错误 posts 0 从返回getStaticProps在 原因 object object Object 无法序列化为 JSON 请仅返回 JSON 可序列化
  • 使用 php 获取 mysql 表中记录总数的最佳方法是什么?

    从大表中选择记录总数的最有效方法是什么 目前 我只是在做 result mysql query SELECT id FROM table total mysql num rows result 有人告诉我 如果表中有很多记录 这不是很有效或
  • stringByAppendingPathComponent,它是如何工作的?

    编辑 v002 我看了所有的评论 我开始明白我应该做什么 为此 我修改了我的代码 见下文 我将 newPath 更改为 NSString 删除了 alloc init 和结束 release 因为它现在由系统处理 我正在使用 stringB
  • 向量上的修改时复制语义不会在循环中追加。为什么?

    这个问题听起来似乎得到了部分回答here但这对我来说还不够具体 我想更好地理解何时通过引用更新对象以及何时复制对象 更简单的例子是向量增长 下面的代码在 R 中效率极低 因为在循环之前没有分配内存 并且在每次迭代时都会创建一个副本 x ru
  • Java中有instanceOf(Class c)之类的东西吗?

    我想检查一个对象是否o是该类的一个实例C或的一个子类C 例如 如果x属于班级Point I want x instanceOf Point class to be true并且x instanceOf Object class to be
  • 在 Matlab 中通过函数句柄传递附加参数

    我有一个需要优化的函数 比如 Matlab 中的 Function 该函数取决于我想要优化的变量 例如 x 和一个不需要优化的参数 例如 Q 因此 函数 Function x Q 换句话说 我有一个 Q 值数组 并且想要为每个 Q 找到最佳
  • 获取现有的或创建新的 akka actor

    我正在尝试使用 ActorFor 获取现有的 ActorRef 或创建一个新的 ActorRef 如果它不存在 我有以下代码 但它似乎没有按预期工作 isTermminate 始终为 true ActorSystem system Acto
  • 原子操作会阻塞其他线程吗?

    我试图让 原子与非原子 的概念在我的脑海中扎根 我的第一个问题是我找不到 现实生活中的类比 就像原子操作上的客户 餐厅关系或类似的东西 我还想了解原子操作如何将自己置于线程安全编程中 在这篇博文中 http preshing com 201
  • 安装:Microsoft Visual C++ Redistributable 卡在“正在处理:Windows7_MSU_X64”

    我正在尝试安装 Microsoft Visual C Redistributable 软件包 因为无法安装我的 xampp apache 模块 安装需要很长时间才能完成 我应该怎么办 这种情况常见吗 我所要做的就是等待吗 他们完全被这个设置
  • 如何检查FormData?

    我试过了console log并使用循环遍历它for in 这里是MDN 参考在 FormData 上 两种尝试都在这fiddle var fd new FormData key poulate with dummy data fd app
  • 在 PyQt 中绘制多边形

    背景 我想在屏幕上绘制一个简单的形状 并且我选择 PyQt 作为要使用的包 因为它似乎是最成熟的 我并没有以任何方式锁定它 Problem 仅在屏幕上绘制一个简单的形状 例如多边形 似乎过于复杂 我发现的所有示例都尝试做很多额外的事情 但我
  • 需要无效 Swing 组件的高度

    基本设置是这样的 我有一个垂直的 JSplitPane 我想要一个固定大小的底部组件和一个调整大小的顶部组件 我通过调用来完成setResizeWeight 1 0 在此应用程序中 有一个按钮可恢复 默认 窗口配置 窗口的默认高度是桌面高度
  • 向量化模运算

    我正在尝试编写一些相当快速的分量向量加法代码 我正在使用 我相信是有符号的 64 位整数 函数是 void addRq int64 t a const int64 t b const int32 t dim const int64 t q