我获取 int 数组点积的内在函数比正常代码慢,我做错了什么?

如何解决我获取 int 数组点积的内在函数比正常代码慢,我做错了什么?

我正在尝试了解内在以及如何正确利用和优化它,我决定实现一个函数来获得两个数组的点积作为学习的起点。

我创建了两个函数来获取整数数组 int 的点积,一个以正常方式编码,您循环遍历两个数组的每个元素,然后对每个元素执行乘法,然后添加/累加/sum 得到的乘积得到点积。

另一个使用内在的方式,我对每个数组的四个元素执行内在操作,我使用 _mm_mullo_epi32 将它们中的每一个相乘,然后使用 2 水平相加 {{1 }} 获取当前 4 个元素的总和,然后将其加到 dot_product,然后继续下一个 4 个元素,然后重复直到达到计算的限制 _mm_hadd_epi32,然后我计算其他剩余元素使用正常方式避免计算出数组的内存,然后我比较两者的性能。

具有两种点积函数的头文件

vec_loop

cpp 代码,用于测量每个函数所花费的时间

// main.hpp
#ifndef main_hpp
#define main_hpp

#include <iostream>
#include <immintrin.h>

template<typename T>
T scalar_dot(T* a,T* b,size_t len){
    T dot_product = 0;
    for(size_t i=0; i<len; ++i) dot_product += a[i]*b[i];
    return dot_product;
}

int sse_int_dot(int* a,int* b,size_t len){
    
    size_t vec_loop = len/4;
    size_t non_vec = len%4;
    size_t start_non_vec_i = len-non_vec;

    int dot_prod = 0;

    for(size_t i=0; i<vec_loop; ++i)
    {
        __m128i va = _mm_loadu_si128((__m128i*)(a+(i*4)));
        __m128i vb = _mm_loadu_si128((__m128i*)(b+(i*4)));
        va = _mm_mullo_epi32(va,vb);
        va = _mm_hadd_epi32(va,va);
        va = _mm_hadd_epi32(va,va);
        dot_prod += _mm_cvtsi128_si32(va);
    }

    for(size_t i=start_non_vec_i; i<len; ++i) dot_prod += a[i]*b[i];

    return dot_prod;
}

#endif

编译:

  • 内在版本:// main.cpp #include <iostream> #include <chrono> #include <random> #include "main.hpp" int main() { // generate random integers unsigned seed = std::chrono::steady_clock::now().time_since_epoch().count(); std::mt19937_64 rand_engine(seed); std::mt19937_64 rand_engine2(seed/2); std::uniform_int_distribution<int> random_number(0,9); size_t LEN = 10000000; int* a = new int[LEN]; int* b = new int[LEN]; for(size_t i=0; i<LEN; ++i) { a[i] = random_number(rand_engine); b[i] = random_number(rand_engine2); } #ifdef SCALAR int dot1 = 0; #endif #ifdef VECTOR int dot2 = 0; #endif // timing auto start = std::chrono::high_resolution_clock::now(); #ifdef SCALAR dot1 = scalar_dot(a,b,LEN); #endif #ifdef VECTOR dot2 = sse_int_dot(a,LEN); #endif auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end-start); std::cout<<"proccess taken "<<duration.count()<<" nanoseconds\n"; #ifdef SCALAR std::cout<<"\nScalar : Dot product = "<<dot1<<"\n"; #endif #ifdef VECTOR std::cout<<"\nVector : Dot product = "<<dot2<<"\n"; #endif return 0; }
  • 普通版:g++ main.cpp -DVECTOR -msse4.1 -o main.o

我的机器:

  • 架构:x86_64
  • CPU:1
  • CPU 内核:4
  • 每核线程数:1
  • 型号名称:Intel(R) Pentium(R) CPU N3700 @ 1.60GHz
  • 一级缓存:96 KiB
  • L1i 缓存:128 KiB
  • 二级缓存:2 MiB
  • 一些标志:sse、sse2、sse4_1、sse4_2

g++ main.cpp -DSCALAR -msse4.1 -o main.o中有main.cpp数组的10000000个元素,当我在我的机器上编译上面的代码时,似乎内部函数运行速度比普通版本慢,大多数时候,内部函数需要int,有时甚至更长,而普通代码只需要97529675 nanoseconds,这里我认为我的内部函数应该运行得更快如果优化标志关闭,但结果确实有点慢。

所以我的问题是:

  • 为什么我的内在函数运行速度较慢? (我做错了什么吗?)
  • 如何纠正我的内在实现,正确的方法是什么?
  • 即使优化标志关闭,编译器也会自动矢量化/展开正常代码
  • 鉴于我的机器的规格,获得点积的最快方法是什么?

希望有人能帮忙,谢谢

解决方法

因此,根据@Peter Cordes、@Qubit 和@j6t 的建议,我稍微调整了代码,现在只在循环内进行乘法运算,然后将水平加法移到循环外。 .. 它设法将内在版本的性能从 Thread 左右提高到 97529675 nanoseconds 左右,这比我之前的实现要快得多,编译标志相同,10000000 int 数组的元素。

这里是 main.hpp 中的新函数

56444187 nanoseconds

如果此代码还有更多需要改进的地方,请指出,现在我将把它留在这里作为答案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res