【学习体会】SIMD256技术 & AVX2指令集 & 使用immintrin的api和数据结构编写测试实例 & immintrin的api解析

2023-10-26

目录

SIMD256技术 & AVX2指令集

C++的immintrin库

使用immintrin的api和数据结构

举个例子:计算pi

immintrin的api解析

_mm256_set1_pd

_mm256_set_pd

_mm256_setzero_pd

_mm256_add_pd 

_mm256_mul_pd

_mm256_div_pd

_mm256_store_pd

_mm256_load_pd

基本数据类型(uint8_t, uint16_t 等)

对于`uint8_t`类型

_mm256_storeu_si256

_mm256_loadu_si256

对于`uint16_t`类型


SIMD256技术 & AVX2指令集

什么是SIMD,Single Instruction Multiple Data,单指令多数据。

什么是SIMD256技术,就是CPU同时对256bit的数据进行读写或者运算。

256 bit = 32 Bytes,一般的,double占8个字节,float和int占4个字节,char占1个字节

那么 256 bit = 4 double = 8 float = 8 int = 32 char

那么就是说可以同时读写操作4个double,或者8个float,或者8个int,或者32个char

C++的immintrin库

这就有点像烤面包,我们不是一个面包一个面包的进行烤制,而是同时烤十几个,这样的效率肯定是会更高。

关于immintrin的api使用,可以查看官方文档:

Floating-Point Memory and Initialization Operations Using Streaming SIMD Extensions 2 | Microsoft Docs

使用immintrin的api和数据结构

举个例子:计算pi

正常的写法是逐个累加计算:

//正常的逐个累加运算
double compute_pi_naive(size_t dt) {

	double pi = 0.0;

	double delta = 1.0 / dt;

	for (size_t i = 0; i < dt; i++) {

		double x = (double)i / dt;

		pi += delta / (1 + x * x);
	}
	return pi * 4.0;
}

 其中,dt 是指 [ 0 , 1 ] 被分为多少份。我们可以设置 dt 尽可能大,已逼近连续积分的结果,比如dt = 134217728

那么,如果我们使用immintrin,则

#include<immintrin.h>
double compute_pi_sim256(size_t dt) {

	double pi = 0.0;

	double delta = 1.0 / dt;

	__m256d ymm0, ymm1, ymm2, ymm3, ymm4;

	ymm0 = _mm256_set1_pd(1.0);

	ymm1 = _mm256_set1_pd(delta);

	ymm2 = _mm256_set_pd(0.0, delta, delta * 2, delta * 3);

	ymm4 = _mm256_setzero_pd();

	for (int i = 0; i < dt - 4; i += 4) {

		ymm3 = _mm256_set1_pd(i*delta);

		ymm3 = _mm256_add_pd(ymm3, ymm2);// 构造 x

		ymm3 = _mm256_mul_pd(ymm3, ymm3);// 构造 x^2

		ymm3 = _mm256_add_pd(ymm0, ymm3);// 构造 1 + x^2

		ymm3 = _mm256_div_pd(ymm1, ymm3);// 构造 delta / ( 1 + x^2 )

		ymm4 = _mm256_add_pd(ymm4, ymm3);// 叠加结果
	}
	
	double tmp[4];
	_mm256_store_pd(tmp, ymm4);

	pi += tmp[0] + tmp[1] + tmp[2] + tmp[3];

	return pi * 4.0;
}

这是一段针对double数据的simd256代码,

用到的数据结构是`__m256d`,这意味着这256bit是装着4个double数据。

结果对比:

#include <iostream>
#include <ctime>
#include<immintrin.h>
int main() {//test_cal_pi

	clock_t start, end;

	size_t dt = 134217728;

	double result1, result2;

	//普通函数计时
	start = clock();
	result1 = compute_pi_naive(dt);
	end = clock();
	cout << "naive: " << result1 << " use time: " << end - start << endl;

	//simd256计时
	start = clock();
	result2 = compute_pi_sim256(dt);
	end = clock();
	cout << "simd256: " << result2 << " use time: " << end - start << endl;
	

	return 0;
}

同样的结果,simd256将时间减少了75.3%

接下来,我们对每一个api进行解析:

这里我能找到的就是_mm系列的,这个系列只能支持simd128,而不是simd256,但是其实整体的思路都差不多,因此也可以当作我们使用simd256的文档,如果又找到了我会发出来。

immintrin的api解析

_mm256_set1_pd

_mm_set1_pd | Microsoft Docs

设置一个`double`数据给一个`__m256d`,那么会自动复制为4份

_mm256_set_pd

_mm_set_pd | Microsoft Docs

准确地给出每一个double的值。

假设是simd128,则设置2个double;如果是simd256,则设置4个double。

_mm256_setzero_pd

_mm_setzero_pd | Microsoft Docs

设置值为0

_mm256_add_pd 

_mm_add_pd | Microsoft Docs

两个数相加

_mm256_mul_pd

_mm_mul_pd | Microsoft Docs

 两个数相乘 

_mm256_div_pd

_mm_div_pd | Microsoft Docs

 两个数相除,a除以b,value = a / b

_mm256_store_pd

_mm_store_pd | Microsoft Docs

 将一个`__m256d`存放在指定double指针指向的地址

 提示:这里的double指针指向的地址必须是对齐32位的

参考:【学习体会】aligned_malloc实现内存对齐_LeonJin的博客-CSDN博客

_mm256_load_pd

_mm_load_pd | Microsoft Docs

 从double指针指向的地址读取256bit数据,存放在`__m256d`中。

以上是对于基本类型double的基本操作了,对于float类型来说,只要把pd改为sd就可以。

基本数据类型(uint8_t, uint16_t 等)

而对于其他的基本数据类型(uint8_t, uint16_t 等),immintrin提供不同的数据结构和api接口:

对于`uint8_t`类型

typedef uint8_t	pixeltype;		// 无符号8位整数
typedef __m256i simd256type;
#define simd256_set1(_value) (_mm256_set1_epi8(_value))
#define simd256_store(_index,_value) (_mm256_storeu_si256(_index,_value))
#define simd256_load(_index) (_mm256_loadu_si256(_index))
#define simd256_min(_value1,_value2) (_mm256_min_epu8(_value1,_value2))
#define simd256_add(_value1,_value2) (_mm256_add_epi8(_value1,_value2))
#define simd256_sub(_value1,_value2) (_mm256_sub_epi8(_value1,_value2))
#define MAX_VALUE UINT8_MAX

这里使用的数据结构是 `__mm256i`,不论是有符号还是无符号,都是用这一个 。

对于store,load,或者其他算术运算则会用是否带 `u` 进行区分。

_mm256_storeu_si256

_mm_storeu_si128 | Microsoft Docs

 将一个`__m256i`存放在指定__m256i*指针指向的地址。

这里我们一般不会创建__m256i[]数组,而是char[]或者uint8_t[]数组。

然后在存放的时候进行强制类型转换,比如:

uint8_t index[32];
__m256i c0;
_mm256_storeu_si256((__m256i*)index, c0);

 如果是操作有符号的int8_t,则得用_mm256_store_si256

_mm256_loadu_si256

_mm_loadu_si128 | Microsoft Docs

 加载一个`__m256i`,同样地对地址进行强制类型转换。

uint8_t index[32];
__m256i c0;
c0 = _mm256_loadu_si256((__m256i*)index);

 如果是操作有符号的int8_t,则得用_mm256_load_si256

对于`uint16_t`类型

typedef uint16_t	pixeltype;		// 无符号8位整数
typedef __m256i simd256type;
#define simd256_set1(_value) (_mm256_set1_epi16(_value))
#define simd256_store(_index,_value) (_mm256_storeu_si256(_index,_value))
#define simd256_load(_index) (_mm256_loadu_si256(_index))
#define simd256_min(_value1,_value2) (_mm256_min_epu16(_value1,_value2))
#define simd256_add(_value1,_value2) (_mm256_add_epi16(_value1,_value2))
#define simd256_sub(_value1,_value2) (_mm256_sub_epi16(_value1,_value2))
#define MAX_VALUE UINT16_MAX

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

【学习体会】SIMD256技术 & AVX2指令集 & 使用immintrin的api和数据结构编写测试实例 & immintrin的api解析 的相关文章

随机推荐

  • mysql references关键字_mysql--一些关键字

    primary key 和unique key 在实际工作中 查看表设计总能看到这样的情况 一个primary 一个unique 还有一个key CREATE TABLE user id int 11 NOT NULL AUTO INCRE
  • 智能RFID电动车防盗管理系统解决方案

    一 RFID城市电动自行车技术诞生 随着城市经济的快速发展 电动自行车作为大众百姓日常出行的主要交通工具 数量急速增多 据统计 至2015年底全国电动自行车保有量已超过2亿辆 并且还以每年2000千万辆的速度增长 这方便民众出行的同时 也给
  • plsql替换

    s select from wh where dl delete from up update set aw a where 1 1 and sf select t rowid from srf select a rowid a from
  • React 性能优化,你需要知道的几个点

    转自于 https www jianshu com p 333f390f2e84 写了一段时间的react之后 渐渐的喜欢上了使用react来写应用 我们知道 Facebook在推出react时打出的旗号之一就是高性能 今天我们还一起来聊一
  • Python 手把手实现M3U8视频抓取

    声明 本文只作学习研究 禁止用于非法用途 否则后果自负 如有侵权 请告知删除 谢谢 此案例比较适合新手学习JS逆向 引言 本文出自微信公众号 Python三剑客 作者 阿K 阅读时长 5min 留言 文章输出我一直贯彻着即拿即用的方式为大家
  • java错误-The prefix "aop" for element "aop:aspectj-autoproxy" is not bound.

    配置springmvc的aop时出错 当我向配置文件中添加
  • web安全的漏洞种类

    SQL注入 SQL注入 SQL Injection 是一个常见的发生于应用程序和数据库之间的web安全漏洞 由于在开发过程中的设计不当导致程序中忽略了检查 没有有效的过滤用户的输入 是攻击者可以向服务器提交不正常的访问数据 即恶意的的SQL
  • logback.xml日志文件配置说明

  • MATLAB学习笔记(系统学习)

    教程来源 1 MATLAB教程 https www cainiaojc com matlab matlab tutorial html 不断学习补充中 文章目录 一 MATLAB基础 1 在MATLAB中使用分号 2 save命令用于将工作
  • windows:开机自动执行bat脚本

    参考 https blog csdn net li1325169021 article details 79889082
  • 在线等待,求高手,socket发送延迟问题

    在线等待 我的app可以按取颜色 色盘与固定颜色的button 使用tcp socket传输 让灯可以根据按的颜色做改变 目前碰到的问题是 1 前面动作都可以正常执行 但按取到后面时就会产生延迟的问题发生 颜色还是可按取 但灯不会变色 但时
  • 光通量发光强度照度亮度关系_照度、发光强度、光通量之间是什么关系

    我们发现有不少朋友对照度 发光强度和光通量这三个概念之间的关系总是搞混淆 包括他们各自的含义 以及标识单位 这里 我们就系统的来解读一下 首先 我们来看一下三者各自的名词解释 光通量 照度 亮度的关系 1 照度 也称光照度 指的是某光源照射
  • JS 如何判断当前页面是否全屏

    点击事件 span class iconfont icon quanping1 span js 代码 fullscreenchange fullScreen 被弃用 const isFullScreen document fullScree
  • 二级建造师继续教育留念

    35 下列关于地方性法规 规章之间冲突时的法律适用 表述正确的是 A 地方性法规 规章之间不一致时 由有关机关依照下列规定的权限作出裁决 B 地方性法规与部门规章之间时同一事项的规定不一致的 由国务院裁决 C 部门规章之间对同一事项的规定不
  • 超级炫酷的决策树可视化R包

    决策树的可视化我们之前介绍过 主要是使用rpart plot包 视觉效果还是不错的 mlr3 模型评价 今天再给大家介绍一个更加花里胡哨的R包 treeheatr 安装 install packages treeheatr install
  • centos7 安装docker

    1 检查linux内核版本 要求版本高于3 10 uname r 2 安装辅助工具 yum install y yum utils device mapper persistent data lvm2 3 设置docker的yum源 sud
  • 什么是测试用例?如何设计?

    在学习或者实际的测试工作中经常都会提到 测试用例 这个词 没错 测试用例是测试工作的核心 不管要做的是什么样的测试 在真正动手执行测试之前 我们都需要先根据软件需求来设计测试用例 之后再依据设计好的测试用例 展开测试工作 那么问题来了 什么
  • 制作Station主机的Armbian启动卡

    Station主机支持很多种操作系统 烧录系统可以连接电脑进行线刷 也可以制作TF卡启动卡 方便系统的切换 本文介绍了制作Armbian启动卡的方法 见视频 视频演示 通过TF卡启动的时候需要先擦除EMMC里面的系统或者暂时拆掉EMMC模块
  • 年底裁员潮,你有没有被"N+1"?

    2018年11月28日上午 前一天加班到深夜的李女士 又一大早起床匆匆赶去上班了 她在一家垂直电商公司工作多年 岁末将至 一切和往常一样 为了在年前完成比上一季度更高的 KPI 她所在团队经常通宵达旦赶工 李女士准备开始新一天的鸡血工作 主
  • 【学习体会】SIMD256技术 & AVX2指令集 & 使用immintrin的api和数据结构编写测试实例 & immintrin的api解析

    目录 SIMD256技术 AVX2指令集 C 的immintrin库 使用immintrin的api和数据结构 举个例子 计算pi immintrin的api解析 mm256 set1 pd mm256 set pd mm256 setze