C++那些事之高性能SIMD

news2024/12/29 2:25:47

C++那些事之高性能SIMD

最近在看相关向量化的内容,看起来有点头大,借此机会,学习一下高性能SIMD编程。

SIMD全称single-instruction multiple-data,单指令多数据。

在传统的计算机架构中,CPU一次只能处理一个数据元素。但是,许多任务涉及对大量数据执行相同的操作,例如对数组中的所有元素进行加法、乘法或逻辑操作等。SIMD编程通过向CPU提供专门的指令集,使得CPU能够同时对多个数据元素执行相同的操作。

这种处理方式特别适合涉及向量、矩阵、图像、音频和视频等数据的计算。

目前比较常用的有SSE、SSE2、AVX128、AVX256、AVX512。

本节,将简单学习一下AVX512的一些操作,操作比较多,这里只是引入一些。

1.术语

首先第一个问题便是,simd编程的代码跟平时写的代码长相不大一样,各种下划线以及命名,完全看不懂,如何理解呢?

诸如:

  • _mm512_set1_ps

Broadcast single-precision (32-bit) floating-point value a to all elements of dst.

  • _mm512_set1_epi32

Broadcast 32-bit integer a to all elements of dst.

于是,找到了下面这个表格:

AbbreviationFull NameC/C++ Equivalent
pspacked single-precisionfloat
phpacked half-precisionNone*
pdpacked double-precisiondouble
pchpacked half-precision complexNone*
pi8packed 8-bit integerint8_t
pi16packed 16-bit integerint16_t
pi32packed 32-bit integerint32_t
epi8extended packed 8-bit integerint8_t
epi16extended packed 16-bit integerint16_t
epi32extended packed 32-bit integerint32_t
epi64extended packed 64-bit integerint64_t
epi64xextended packed 64-bit integerint64_t

https://stackoverflow.com/questions/70911872/what-are-the-names-and-meanings-of-the-intrinsic-vector-element-types-like-epi6

再比如:

_mm512_mask_load_ps

_mm512_mask_loadu_ps

u表示unordered,表示加载无序,当使用 _mm512_mask_loadu_ps 函数加载内存中的数据时,不会执行对内存地址的任何对齐要求。而_mm512_mask_load_ps要求满足 64 字节对齐要求。

这样对照着学习,非常快的便可以知道每个接口的含义了。

相关API可以看看Intel Intrinsics Guide。

https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html

2.实际例子

2.1 求最小值

对于512位,我们可以存储16个32位float。

static inline rf_512 load(float* ptr) { return _mm512_loadu_ps(ptr); }
float a[width] = {1.0, 2.0,  3.0,  22.0, 5.0,  17.0, 9.0,  8.0,
                  9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0};
float b[width] = {3.3, 6.2,   5.3,   4.4,   5.5,   6.6,   7.7,  8.8,
                  9.9, 10.10, 21.11, 12.12, 13.13, 14.14, 15.0, 16.16};
rf_512 data = minimum(load(a), load(b));

于是我们可以快速得到:

1 2 3 4.4 5 6.6 7.7 8 9 10 11 12 13 14 15 16

2.2 快速打乱数据顺序

对于输入数据是

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

我们可以快速得到:

16.16 2 14.14 13.13 5 6 7 8 9 10 11 12 13 14 15 16

对应实现:

static inline rf_512 permutexvar(ri_512 idx, rf_512 src) {
  return _mm512_permutexvar_ps(idx, src);
}
/*
raw data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
shuffle data: 16.16 2 14.14 13.13 5 6 7 8 9 10 11 12 13 14 15 16
*/
void print_permutexvar_mask() {
  float a[width] = {1.0, 2.0,  3.0,  4.0,  5.0,  6.0,  7.0,  8.0,
                    9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0};
  float b[width] = {1.1, 2.2,   3.3,   4.4,   5.5,   6.6,   7.7,  8.8,
                    9.9, 10.10, 11.11, 12.12, 13.13, 14.14, 15.0, 16.16};
  mask_type mask = make_bit_mask<1, 0, 1, 1, 0>();
  int idx_array[width] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  ri_512 idx = _mm512_loadu_si512((__m512i*)idx_array);
  rf_512 result = permutexvar_mask(load(a), mask, idx, load(b));
  float result_arr[width];
  store(result, result_arr);
  std::cout << "raw data: ";
  for (int i = 0; i < width; i++) {
    std::cout << a[i] << " ";
  }
  std::cout << std::endl;

  std::cout << "shuffle data: ";
  for (int i = 0; i < width; i++) {
    std::cout << result_arr[i] << " ";
  }
  std::cout << std::endl;
}

2.3 旋转

对于一个数组:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

我们可以旋转得到:

4 5 6 7 8 9 10 11 12 13 14 15 16 1 2 3

or

14 15 16 1 2 3 4 5 6 7 8 9 10 11 12 13

也就是rotate down or rotate up。

在这里,我们可以这样实现:

rf_512 rotateGeneral(float* arr, int s) {
  int idx_array[width];
  for (int i = 0; i < width; i++) {
    idx_array[i] = (i + s) % width;
  }
  ri_512 idx = _mm512_loadu_si512((__m512i*)idx_array);
  rf_512 result = permutexvar(idx, load(arr));
  return result;
}

等等,还有其他的例子,可以发现通过使用simd,我们可以实现一些非常有趣的算法,加速对数组,批量数据的处理。

后面会继续学习simd,一起加油吧~

注:本节的完整示例已在星球更新,谢谢~

78c5b16c419ace1ddda758d37d099162.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/812335.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】Feature scaling and Learning Rate (Multi-variable)

Feature scaling and Learning Rate 1、数据集2、学习率2.1 α \alpha α 9.9e-72.2 α \alpha α 9e-72.3 α \alpha α 1e-7 3、特征缩放3.1 特征缩放的原因3.2 Z-score 归一化3.3 预测3.4 损失等值线 导入所需的库 import numpy as np np.set_printoptions(precision…

【C++】类和对象-C++运算符重载

运算符重载 1.加号运算符重载 代码&#xff1a; #include <iostream> using namespace std; /******************************************/ //加号运算符重载class Person { public:int m_A;int m_B;//1、成员函数重载号(不能与下面方式2同时存在&#xff0c;否则代码报…

在docker中没有vi如何修改docker中的文件

今天在做学成在线的项目&#xff0c;遇到了一个问题&#xff0c;就是死活登不上xxl-job&#xff0c;按照之前遇到的nacos的问题&#xff0c;我怀疑很大概率是和当时的ip设置有关&#xff0c;不知道nacos的ip怎么修改的同学&#xff0c;可以看看这篇文章&#xff1a;关于docker中…

电子词典

项目要求&#xff1a; 1.登录注册功能&#xff0c;不能重复登录&#xff0c;重复注册。用户信息也存储在数据库中。 2.单词查询功能 3.历史记录功能&#xff0c;存储单词&#xff0c;意思&#xff0c;以及查询时间&#xff0c;存储在数据库 4.基于TCP&#xff0c;支持多客户…

【AI网站分享】

AI网站分享 1 AI应用2 AI 写作3 AI 编程4 AI设计5 AI作图6 AI训练模型7 AI影音编辑8 AI效率助手 网站链接&#xff1a; https://tools.haiyong.site/ai/ 网站中的内容大致可以分为八类&#xff1a;AI应用、AI写作、 AI 编程、 AI设计、 AI作图、AI训练模型、 AI影音编辑、 AI效…

线程属性——线程分离应用

文章目录 相关函数初始化释放线程属性的资源获取线程分离的状态属性设置线程分离的状态属性获取线程的栈的大小线程分离应用 相关函数 可以通过man pthread_attr_然后按两次table键查询和属性相关的函数 初始化 释放线程属性的资源 获取线程分离的状态属性 设置线程分离的状…

C# VS2022+WinForm+Oracle19.3+存储过程,SQL和代码分离

【我的目的】&#xff1a;SQL和代码分别存放在不同的地方&#xff0c;便于随时修改SQL的内容&#xff0c;也便于修改SQL的书写格式 方案1&#xff1a;把SQL存放在DataSet.xsd中实现SQL和代码分离 方案2&#xff1a;用存储过程实现SQL和代码分离 我最倾向方案1&#xff0c;利用…

链路 聚合

静态链路聚合&#xff1a;多数内网使用 。非物理直连建议与BFD联动 动态链路聚合LACP&#xff1a;是公有协议、内网、二层专线接口都能使用&#xff0c;现网多数使用此方式链路 聚合 PAGP&#xff1a;思科私有协议&#xff0c;只支持思科设备使&#xff0c;现网多数不用

Windows驱动开发

开发Windows驱动程序时&#xff0c;debug比较困难&#xff0c;并且程序容易导致系统崩溃&#xff0c;这时可以使用Virtual Box进行程序调试&#xff0c;用WinDbg在主机上进行调试。 需要使用的工具&#xff1a; Virtual Box&#xff1a;用于安装虚拟机系统&#xff0c;用于运…

谨防虚假发货!了解如何辨别真假发货单号

随着电子商务的发展&#xff0c;快递行业成为了一个不可忽视的重要环节。然而&#xff0c;虚假发货单号的出现给快递行业带来了一定的困扰。为了解决这个问题&#xff0c;一些快递批量查询高手软件开始应用于虚假发货单号的分析。本文将介绍这些软件如何分析出虚假发货单号&…

应用开发者的疑问:大模型是银弹吗?

被当成银弹的大模型 ChatGPT 火了之后&#xff0c;大模型似乎被当成了真正的银弹&#xff0c;所有的体验问题都想通过大模型解决&#xff1a; 能不能和大模型对话订机票&#xff1f;自然语言生成 SQL&#xff0c;简化报表分析工作&#xff1f;大模型帮老年人操作软件&#xff…

nosql之redis集群

文章目录 一.redis集群1.单节点redis服务器带来的问题2.集群redis3.集群的优势4.redis集群的实现方法5.redis群集的三种模式5.1 主从复制5.2 哨兵5.3 集群 二.Redis 主从复制1.主从复制概念2.主从复制的作用3.主从复制流程4.搭建Redis 主从复制4.1 安装 Redis4.2 修改 Redis 配…

RBF神经网络原理和matlab实现

1.案例背景 1.1 RBF神经网络概述 径向基函数(Radical Basis Function,RBF)是多维空间插值的传统技术,由Powell于1985年提出。1988年, Broomhead和 Lowe根据生物神经元具有局部响应这一特点,将 RBF引入神经网络设计中,产生了RBF神经网络。1989 年&#xff0c;Jackson论证了…

开源项目-erp企业资源管理系统(毕设)

哈喽,大家好,今天给大家带来一个开源项目-erp企业资源管理系统,项目通过ssh+oracle技术实现。 系统主要有基础数据,人事管理,采购管理,销售管理,库存管理,权限管理模块 登录 主页 基础数据 基础数据有商品类型,商品,供应商,客户,仓库管理功能

Python零基础入门(十)——模块与包

系列文章目录 个人简介&#xff1a;机电专业在读研究生&#xff0c;CSDN内容合伙人&#xff0c;博主个人首页 Python入门专栏&#xff1a;《Python入门》欢迎阅读&#xff0c;一起进步&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; 码字不易&#xff0c;如果觉得文章不…

【C语言-扫雷游戏全功能详解】

目录 理解扫雷原理 梳理扫雷过程 9*9 棋盘 初始化棋盘 显示棋盘 ​编辑 布置雷 排查雷 统计x,y坐标周围有几个雷 使用递归函数来实现周围没地雷时展开多个 判断成功排除后剩下的方格数是否等于地雷数 排查函数 梳理编写代码思路 头文件game.h 库函数所需要头文件 …

STM32 cubemx配置USART DMA传输

文章目录 前言一、DMA概念二、STM32 DMA数据手册分析3.DMA模式介绍4.cubemx配置总结 前言 本篇文章来讲解DMA的概念&#xff0c;并使用DMA来进行串口的数据收发。 一、DMA概念 DMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;是一种计算机系统的技…

vue 设置数组

手写获取数据 <el-form-item label"缴纳方"><el-select v-model"form.invoiceCategoryName" placeholder"请选择缴纳方"><el-optionv-for"item in kplmList":key"item.value":label"item.label":v…

求解方程x^2=a的根,不使用库函数直接求解(不动点迭代法)

首先可以将方程两边同时加上x&#xff0c;&#xff0c;这时候两边同时再除以1x&#xff0c;就得到了&#xff0c;变形为。&#xff08;变性后的迭代式不唯一&#xff0c;这里随便选取一个&#xff09; 当x是准确值的时候&#xff0c;两边应该是相等的&#xff0c;如果x是近似值…

数据库连接池的使用

十、数据库连接池的使用 1、c3p0数据库连接池 硬编码&#xff1a; c3p0的帮助文档 c3p0配置文件&#xff1a; 2、dbcp数据库连接池 配置文件&#xff1a; 3、druid 将上面三个做成工具类&#xff1a;