首页 > 编程语言 >x86平台SIMD编程入门(5):提示与技巧

x86平台SIMD编程入门(5):提示与技巧

时间:2023-11-04 17:36:54浏览次数:53  
标签:__ 缓存 x86 编程 C++ 内存 SIMD 向量

1、提示与技巧

  • 访问内存的成本非常高,一次缓存未命中可能会耗费100~300个周期。L3缓存加载需要40~50个周期,L2缓存大约需要10个周期,即使L1缓存的访问速度也明显慢于寄存器。所以要尽量保持数据结构对SIMD友好,优先选择std::vectorCAtlArrayeastl::vector等容器,按照顺序读取数据以提高缓存命中率。如果数据比较稀疏,可以将其组织为小型密集块的稀疏集合,其中每个块的大小至少为1个SIMD寄存器的大小。如果需要遍历链表或图,同时对每个节点进行计算,可以使用_mm_prefetch函数来将数据预先加载到缓存中。

  • 为了获取最佳性能,内存访问需要内存对齐。更具体地说,内存访问不应该超出缓存行(cache line)的边界。缓存行的大小为64字节,且按64字节地址对齐。当SIMD向量正确对齐(SSE向量16字节对齐、AVX向量32字节对齐)时,内存访问将保证只触及一个缓存行。

  • 在处理成对的32位浮点数(如2D平面中的FP32向量)时,可以用一条FP64数的指令加载或存储两个标量,我们只需要对指针进行类型转换,并对向量使用_mm_castps_pd/_mm_castpd_ps函数即可。同样,我们也可以随意使用FP64洗牌/广播函数来移动这些向量中的FP32值对。

  • C++有很多优秀的矢量化库,例如Eigen、DirectXMath等,它们已经实现了相当复杂的功能,有时候直接使用它们就好了,没必要再重复造轮子。

  • 不要在函数或方法中写入类似static const __m128 x = something();这样的语句,因为在现代C++中,这种结构保证了线程安全,而为了支持语言标准,编译器必须输出一些模板代码,这些代码可能会有锁和分支。我们可以将该值放在全局变量中,这样它们就能在main()开始运行前被初始化,或者在DLL的LoadLibrary返回前被初始化。或者,也可以将该值放在一个本地非静态常量中。

  • 如果使用VC++,请在频繁调用的循环体中对性能敏感的SIMD函数使用__forceinline修饰符。指令经常会包含幻数(magic number),或是不随循环而改变的常量。与标量代码不同的是,SIMD常量通常来自内存而不是指令流,当编译器被告知__forceinline时,它可以加载这些SIMD常量一次,并在循环过程中将它们保存在向量寄存器中(除非寄存器短缺导致它们被放到内存)。如果没有内联,代码将在执行函数时重新加载这些常量。VC++的内联功能对于标量代码是适用的,但对SIMD代码却基本不起作用,所以需要使用__forceinline来强制内联。GCC和Clang的内联功能会更好,但强制内联有时候仍有帮助,可以将__forceinline定义为宏:

    #define __forceinline inline __attribute__((always_inline))
    
  • 如果要根据硬件支持的指令集来动态选择函数的实现版本,请在调用函数指针或虚类方法时使用__vectorcall调用约定,这样函数会尽量在向量寄存器中传递参数与返回值。

2、参考资料

标签:__,缓存,x86,编程,C++,内存,SIMD,向量
From: https://www.cnblogs.com/moonzzz/p/17808626.html

相关文章

  • x86平台SIMD编程入门(4):整型指令
    1、算术指令算术类型函数示例加_mm_add_epi32、_mm256_sub_epi16减_mm_sub_epi32、_mm256_sub_epi16乘_mm_mul_epi32、_mm_mullo_epi32除无水平加/减_mm_hadd_epi16、_mm256_hsub_epi32饱和加/减_mm_adds_epi8、_mm256_subs_epi16最大/最小值_......
  • JUC并发编程学习笔记(八)读写锁
    读写锁ReadWriteLockReadWriteLock只存在一个实现类那就是ReentrantReadWriteLock,他可以对锁实现更加细粒化的控制读的时候可以有多个阅读器线程同时参与,写的时候只希望写入线程是独占的Demo:packageorg.example.rw;importjava.util.HashMap;importjava.util.Map;impo......
  • 实验3 C语言函数应用编程
    任务11#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);8voidprint_spaces(intn);9voidprint_blank_lines(intn......
  • x86平台SIMD编程入门(3):浮点指令
    1、算术指令算术类型函数示例备注加_mm_add_sd、_mm256_add_ps减_mm_sub_sd、_mm256_sub_ps乘_mm_mul_sd、_mm256_mul_ps除_mm_div_sd、_mm256_div_ps平方根_mm_sqrt_sd、_mm256_sqrt_ps倒数_mm_rcp_ss、_mm_rcp_ps、_mm256_rcp_ps快速计算......
  • x86平台SIMD编程入门(2):通用指令
    1、重解释转换虽然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它们是不同的类型。有一些intrinsic函数可以将它们重新解释为不同的类型,如下表所示,行代表源类型,列代表目标类型。__m128__m128d__m128i__m256__m256d__m256d__m128=_mm_castps_......
  • x86平台SIMD编程入门(1):SIMD基础知识
    1、简介SIMD(SingleInstruction,MultipleData)是一种并行计算技术,它通过向量寄存器存储多个数据元素,并使用单条指令同时对这些数据元素进行处理,从而提高了计算效率。SIMD已被广泛应用于需要大量数据并行计算的领域,包括图像处理、视频编码、信号处理、科学计算等。许多现代处理......
  • 【教3妹学编程-算法题】117. 填充每个节点的下一个右侧节点指针 II
    2哥 :3妹,听说你昨天去面试了,怎么样啊?3妹:嗨,别提了,让我回去等通知,估计是没有通知了,还浪费我请了一天假。2哥 :你又请假了啊,你是怎么跟你那个严厉的老板请假的。3妹:我说我2哥生病了,嘿嘿~2哥:一猜就是说我生病了,自从你找工作,我这一年都病了十几回了……3妹:没办法,假不好请嘛,我尽快......
  • 教3妹学编程-算法题】2914. 使二进制字符串变美丽的最少修改次数
    3妹:呜呜,烦死了,脸上长了一个痘2哥 :不要在意这些细节嘛,不用管它,过两天自然不就好了。3妹:切,你不懂,影响这两天的心情哇。2哥 :我看你是不急着找工作了啊,工作那么辛苦,哪还有时间想这些啊。3妹:说到找工作,我又要去刷题了。2哥:我给你出一道关于美丽的题吧,让你的心情美丽美丽~ 1题目......
  • 【教3妹学编程-算法题】数组中两个数的最大异或值
    3妹:“太阳当空照,花儿对我笑,小鸟说早早早,你为什么背上炸药包”2哥 :3妹,什么事呀这么开心呀。3妹:2哥你看今天的天气多好啊,阳光明媚、万里无云、秋高气爽,适合秋游。2哥:是啊,都快立冬了,天气还是这么热。今年的冬天比以往来的要晚一些。3妹:晚来也是要来的,看天气预报下周要降温,估计没几......
  • UE4中的C++编程简介
    对官方文档的学习链接利用UE创建一个C++基类在编辑器中可以选择父类,根据这个父类我们可以创建一个基类用于后续的蓝图类制作。以Actor父类为例创建基类,其头文件会包含一个构造函数,一个Tick函数的重载和一个BeginPlay函数的重载。BeginPlay函数告诉Actor以可运行状态进入了游戏......