SIMD系列-GATHER/SCATTER操作

news2024/9/23 15:22:10

SIMD系列-GATHER/SCATTER操作

众所周知,SIMD寄存器可以使用LOAD/STORE操作与标量域(或者更准确的说是内存)进行通信。这些操作的缺点是:只允许移动内存中连续的数据元素。然而,我们代码中,经常需要访问非连续的内存。本教程中将解释GATHER/SCATTER操作以及他们如何类推到LOAD/STORE操作。

某些情况下,您可能希望使用来自非连续内存位置的数据填充寄存器。几个使用例子:

1)访问数组中的每隔一个元素(跨步访问

2)以新计算的偏移量访问数组的元素(索引访问

3)以不同顺序访问元素(随机访问

本文讨论前两种情况。最后一类需要在permutations背景下进行更彻底的讨论,因此我们将在下一个教程中讨论。

那么什么是SCATTER操作呢?它是GATHER操作的逆操作,将寄存器的内容“分散”到内存中。因此类似于STORE操作,但能够进行非连续内存访问。

1、Stried access跨步访问

当访问的内存字段距离相等时,内存访问模式称为跨步。这个距离称为步幅(不要与SIMD步幅混淆)。跨步访问的简单图示:

5a43be85ca7d215aacef4153f147c8b9.png

正如你所见,STRIDE-1访问是GATHER操作符的特殊情况:LOAD操作。那为什么我们有单独的LOAD和GATHER操作(以及STORE和SCATTER),而不仅仅简化事情并仅使用GATHER?有2种解释,首先是一个历史问题:早期处理器仅实现LOAD指令在内存和标量寄存器之间移动数据。由于在标量域中,您可以使用单个标量索引访问任何元素,因此不需要更灵活的操作。其次,是性能方面:除了传递基内存地址外,GATHER指令还需要如何计算指定偏移的相关信息。无论指令在处理器内如何实现,这都是额外的自由度,可能意味着更长的执行时间,但肯定意味着额外的电路。

性能提示尽可能使用LOAD/STORE操作,并尽可能避免GATHR/SCATTER。在大多数情况下,意味着必须修改您的数据结构/算法。但当您确定无法重新设计结构时,才使用GATHE/SCATTER。

执行跨步访问时,需要知道什么是基地址(作为指向数据开头的指针传递)和跨步值(作为标量整数传递)。步幅始终作为元素数量而不是内存偏移量传递,以便可以简化编程。

以下代码展示了如何执行跨步内存访问:

float a[LARGE_DATA_SIZE];
uint32_t STRIDE = 8;
...
for(int i = 0; i < PROBLEM_SIZE; i+=8) {
  SIMDVec<float, 8> vec;
 
  // Note that we have to scale the loop index.
  int offset = i*STRIDE;
 
  // 'load' the data to vec.
  vec.gather(&a[offset], STRIDE);
  // do something useful
  vec += 3.14;
  // store the result at original locations
  vec.scatter(&a[offset], STRIDE);
}

当使用跨步访问时,我们必须传递第一个元素地址。这是通过在每次迭代中计算偏移变量来完成的。然后,GATHER操作使用该本地基地址和标量步幅来计算相应元素的偏移量。

一旦必要的计算结束,更新的结果将存储回原始位置。

2、Indexed access索引访问

Indexed access比跨步访问更通用。主要区别在于,您必须传递无符号整数索引的SIMDVec,而不是传递标量步幅参数。Indexed access可以使用下图理解:

2e8fbab4055f62240dd4560471e94f72.png

这种模式的优点是,每个元素都可以使用专用索引来检索。缺点是这种方式的索引可能会完全破坏基于硬件的内存预取,进而对性能产生负面影响。另外注意,所有元素可能都离得很远,这意味着必须将更多缓存行移动到最低缓存级别。使用索引访问的示例:

float a[LARGE_DATA_SIZE];
int indices[PROBLEM_SIZE];
uint32_t STRIDE = 4;
...
for(int i = 0; i < PROBLEM_SIZE; i+=8) {
  SIMDVec<float, 8> vec;
 
  // Here we are using precomputed indices,
  // but they can be computed on-the-fly if necessary.
  SIMDVec<uint32_t, 8> indices_vec(&indices[i];
 
  // 'load' the data to vec.
  vec.gather(&a[0], indices_vec);
  // do something useful
  vec += 3.14;
  // store the result at original locations
  vec.scatter(&a[0], indices_vec);
}

基本区别在于,我们将使用32b索引的无符号整数向量,而不是传递标量步长。

注意:目前该库正在使用与所有gathered向量的标量元素具有相同精度的无符号整数向量。当处理混合精度以及小类型(例如uint8_t)没有足够的位来表示完整范围的索引时,这回导致麻烦。该库将更新为始终使用uint32_t索引向量。

3、确保有条件访问

编写代码时可能会发现的问题之一是:尝试处理条件语句。考虑以下标量代码:

float a[PROBLEM_SIZE], b[PROBLEM_SIZE];
float c[LARGE_DATASET_SIZE];
...
for(int i = 0; i < PROBLEM_SIZE; i++) {
 // Here we are checking if for some reason one of the 
 // values in (a[i],b[i]) pair is not determined properly.
 if (std::isfin(a[i] - b[i])) {
   // Calculate the index only if both 'a' and 'b' are well defined
   int index = int(a[i] - b[i]);
   // 'gather' single element at a time
   float temp = c[index]; 
   // Do something with the value
   temp += 3.14; 
   // Update the values of 'c'
   c[index] = temp;
 }
}

您应该已经知道:请参阅 UME::SIMD Tutorial 8: Conditional execution using masks。使用掩码的向量代码将执行if分支内的所有操作。将上面代码重写:

float a[PROBLEM_SIZE], b[PROBLEM_SIZE];
float c[LARGE_DATASET_SIZE];
...
// For simplification we are assuming that: ((PROBLEM_SIZE % 8) == 0)
for(int i = 0; i < PROBLEM_SIZE; i+= 8) {
 // Here we are checking if for some reason (e.g. a design decision) one 
 // of the values in (a[i],b[i]) pair is not determined properly.
 
 SIMDVec<float, 8> a_vec(&a[i]), b_vec(&b[i]);
 SIMDVecMask<8> condition = (a_vec - b_vec).isfin();
 
// if (std::isfin(a[i] - b[i])) {
 SIMDVec<uint32_t, 8> indices = a_vec - b_vec;
 SIMDVec<float, 8> temp;
 
 temp.gather(&c[0], indices); // This is WRONG!!!
 temp.adda(condition, 3.14); // only change selected elements
 temp.scatter(&c[0], indices); // Again WRONG!!!
}

为什么这段代码中的GATHER和SCATTER操作是错误的?即使索引不正确,它们都试图访问内存。但 GATHER 和 SCATTER 都不关心这一点。他们必须相信我们能为他们提供正确的索引,至少出于性能原因。如果索引不正确,它们将尝试访问可能位于“c”数据集边界之外的内存。这可能会导致内存故障,因此我们必须使用条件掩码来保护内存读取和写入:

float a[PROBLEM_SIZE], b[PROBLEM_SIZE];
float c[LARGE_DATASET_SIZE];
...
// For simplification we are assuming that: ((PROBLEM_SIZE % 8) == 0)
for(int i = 0; i < PROBLEM_SIZE; i+= 8) {
 // Here we are checking if for some reason (e.g. by design?) one of the 
 // values in (a[i],b[i]) pair is not determined properly.
 
 SIMDVec<float, 8> a_vec(&a[i]), b_vec(&b[i]);
 SIMDVecMask<8> condition = (a_vec - b_vec).isfin();
 
 // if (std::isfin(a[i] - b[i])) {
 SIMDVec<uint32_t, 8> indices = a_vec - b_vec;
 SIMDVec<float, 8> temp;
 
 temp.gather(condition, &c[0], indices); // Now the read is CORRECT!!!
 temp += 3.14; // we don't have to mask this operation
 temp.scatter(condition, &c[0], indices); // Again no problems here.
}

因此,在更正后的版本中,我们必须简单地将附加掩码参数传递给内存访问操作,而不是算术运算。该库将负责保护读取的安全,以便它们仅访问允许的内存地址。

4、总结

介绍了 GATHER/SCATTER 操作的概念,并解释了为什么它们是我们的 SIMD 编程模型的有用补充。我们研究了跨步和索引内存访问模式,并解释了这个概念如何概括 LOAD/STORE 操作。

虽然非常有用,但“GATHER/SCATTER”操作是一把双刃剑,既可以让我们的生活更轻松,也可以破坏我们的性能。

5、原文

https://gain-performance.com/2017/06/15/umesimd-tutorial-9-gatherscatter-operations/

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

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

相关文章

浅谈大数据软件的功能性分析

在当今时代的潮流中&#xff0c;工作中遇到大数据处理的时候非常多&#xff0c;因此需要一些大数据分析软件帮助人们进行工作。由于这些软件针对的对象不同&#xff0c;因此使用方法也不同&#xff0c;那么为了帮助更多的人了解大数据分析软件&#xff0c;我们就对这些软件的功…

【Linux命令200例】mc一个十分实用的文件管理器

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

ARM裸机-4

1、什么是交叉编译 1.1、两种开发模式 非嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&#xff08;源代码&#xff09;、编译得到可执行程序&#xff0c;发布给A&#xff08;类&#xff09;机运行。 嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&am…

【PWN · Stack Smash】[2021 鹤城杯]easyecho

花式栈溢出——Canary保护是吧&#xff1f;接化发&#xff0c;拿来吧你 目录 前言 一、代码分析 0.保护 1.main函数 2.sub_CF0()函数 &#xff08;v9指向的函数&#xff09; 二、Stack Smash过程 0.原理简述 1.条件与准备 2.地址泄露 ①真实地址泄露 ②flag地址泄露…

解决问题:python PermissionError: [WinError 5]拒绝访问

重要&#xff1a;关闭PyCharm Community Edition 2022.3等与python相关的编程程序找到按照python解释器的位置python->右键>属性>安全->点击组或用户名"中的Users->编辑点击"组或用户名"中的Users->把"完全控制"打钩->应用->…

【Java】使用JDBC操作MySQL(快速入门+详解)

文章目录 1. JDBC概述2. JDBC快速入门2.1 下载驱动jar包2.2 数据准备2.3 创建工程2.4 编写代码 3. JDBC API详解3.1 DriverManager3.2 Connection3.2.1 获取执行SQL对象3.2.1 管理事务 3.3 Statement3.3.1 执行DML语句3.3.2 执行DDL语句 3.4 ResultSet3.4.1 ResultSet对象方法3…

ChatGPT 实现前一天

提出需求 个人输入需求&#xff1a; Java实现键盘输入日期 输出前一天&#xff0c;需要考虑润年和非润年&#xff0c;2月是否有29号&#xff0c;大月小月的区分等细节处理&#xff0c;不符合的有对应提示&#xff0c;不使用java包里的封装好的类 ChatGPT4分析出的语义&#xff…

人工智能安全-2-非平衡数据处理

0 提纲 现象与原因非平衡数据处理方法概览数据预处理层面特征层算法层面1 现象与原因 非平衡数据分类问题:在网络信息安全问题中,诸如恶意软件检测、SQL注入、不良信息检测等许多问题都可以归结为机器学习分类问题。这类机器学习应用问题中,普遍存在非平衡数据的现象。 产…

哈希函数如何工作 ?

动动发财的小手&#xff0c;点个赞吧&#xff01; 作为一名程序员&#xff0c;您每天都会使用哈希函数。它们在数据库中用于优化查询&#xff0c;在数据结构中用于使速度更快&#xff0c;在安全性中用于保证数据安全。几乎每次与技术的交互都会以某种方式涉及哈希函数。 哈希函…

生命在于学习——APP渗透学习笔记

一、app渗透篇 1、Android 简介 自从 Android 被谷歌收购&#xff08;2005 年&#xff09;&#xff0c;谷歌已经完成了整个开发&#xff0c;在过去的 9 年里&#xff0c;尤其是在安全方面&#xff0c;有很多变化。 现在&#xff0c;它是世界上最广泛使用的智能手机平台&#…

代码、低代码、无代码开发触手可及的低代码平台源码

基于moleculer微服务架构开发的低代码平台源码&#xff0c;代码、低代码、无代码开发触手可及。 一、低代码平台系统功能 【公司信息】 管理员可通过页面顶部设置菜单或者应用程序中设置应用进入到后台设置页面。 在公司信息页面可进行基础信息修改&#xff0c;启用用户自助…

我在CSDN创作的第五十天

这篇文章主要是写给自己的&#xff0c;是对自己现在阶段的一个认识&#xff0c;6月10号&#xff0c;我在CSDN发布了第一篇文章&#xff0c;距离现在不多不少&#xff0c;刚刚好是50天&#xff0c;期间创作的都是C语言的一些内容&#xff0c;我创作的文章也都是我现在所学的知识…

Django系列之DRF简单使用

基于ModelViewSets的简单使用 models.py from django.db import modelsclass AuthorDetail(models.Model):gender models.CharField(max_length8)birthday models.DateField()telephone models.BigIntegerField()addr models.CharField(max_length64)class Author(models…

手机的python怎么运行文件,python在手机上怎么运行

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;手机上的python怎么运行程序&#xff0c;手机的python怎么运行文件&#xff0c;今天让我们一起来看看吧&#xff01; 1、python程序怎么在手机上运行 python语言应用很广泛&#xff0c;自己也很喜欢使用它&#xff0c;其…

自学网络安全(黑客)入门

自学网络安全入门可以按照以下步骤进行&#xff1a; 确定学习目标&#xff1a;网络安全是一个广泛的领域&#xff0c;包括密码学、网络防御、漏洞利用等方面。确定自己想要学习的具体方向&#xff0c;可以更好地规划学习路线。 学习基础知识&#xff1a;网络安全的基础知识包括…

Leetcode周赛 | 2023-7-30--我真是个废物

2023-7-30--我真是个废物 题1体会我的代码 题2体会我的代码 题3体会我的代码 题1 体会 根本没想到用双指针。原因是&#xff0c;没想到还要用一个字典去维护子数组中各个数字的出现频次&#xff0c;以及出现频次不小于1 (也就是大于0) 的数字个数。 这里的双重循环也很巧妙&am…

牛客 排座椅(贪心)

上课的时候总有一些同学和前后左右的人交头接耳&#xff0c;这是令小学班主任十分头疼的一件事情。不过&#xff0c;班主任小雪发现了一些有趣的现象&#xff0c;当同学们的座次确定下来之后&#xff0c;只有有限的D对同学上课时会交头接耳。 同学们在教室中坐成了 M 行 N 列&…

【每日一题Day281】LC142链表 Ⅱ| 快慢指针 哈希表

环形链表 Ⅱ【LC142】 给定一个链表&#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使…

用JavaScript和HTML实现聊天页面和功能(超详细)

文章目录 &#x1f680;一、介绍&#x1f680;二、开始编码&#x1f50e;2.1 创建一个HTML文件&#x1f50e;2.2 编写样式&#x1f50e;2.3 完善聊天页面&#x1f50e;2.4 编写按钮逻辑&#x1f50e;2.5 测试聊天效果&#x1f50e;2.6 优化对话显示&#x1f50e;2.7 设置一个自…

Cesium地形裁剪

基于纹理映射实现的裁剪&#xff0c;反裁剪也可以。比判断点是否在多边形内裁剪性能要好的多&#xff0c;缺点是在边缘锯齿感会比较明显。 3DTileset 的裁剪也和这样一样用纹理映射实现了&#xff0c;效果一样