网站服务器地址查询,做美缝在哪个网站接单,山西省建设厅入晋备案网站,wordpress自助友链AVX 指令集系列深度介绍#xff1a;领域、意义、以及 AVX / AVX2 的基本用法与样例
前言
PS下#xff0c;笔者不是专门做这一块的#xff0c;是聊天的时候聊到这里#xff0c;发现这个领域对我而言相当的陌生#xff0c;打算好好的记录个笔记唠下#xff0c;所以我没办…AVX 指令集系列深度介绍领域、意义、以及 AVX / AVX2 的基本用法与样例前言PS下笔者不是专门做这一块的是聊天的时候聊到这里发现这个领域对我而言相当的陌生打算好好的记录个笔记唠下所以我没办法完全保证我搜集得到的内容百分百准确。看官自行评判。为什么要关心 AVX—— 向量化计算的领域与意义我关心这个有的时候是高清视频渲染嗯笔者参与的项目有涉及到这块所以才知晓还有这个领域的毕竟在现代计算任务中无论是高清视频渲染、人工智能模型训练还是复杂的科学仿真数据量都在呈指数级增长。传统的SISD单指令单数据处理模式——即每次操作只处理一个数据项——已逐渐成为计算效率的瓶颈。为了突破这一瓶颈SIMD单指令多数据概念应运而生。它允许 CPU 用一条指令同时处理一组数据这种“成批处理”的技术被称为向量化。AVXAdvanced Vector Extensions高级向量扩展正是 x86 架构中最重要的向量化指令集之一。我们很自然的就要问了那怎么优化的在 CPU 内部寄存器是数据参加运算前必须停留的“临时月台”。在早期的 SSE 技术时代这个月台的宽度是 128 位。如果我们处理的是“单精度浮点数”每个数据占 32 位那么一个周期内只能并排排下 4 个数据进行计算。而 AVX 技术将这个月台的宽度翻倍到了256 位。这意味着 CPU 的硬件通道发生了质变现在它可以在同一个瞬间同时吞吐并处理8 个单精度浮点数或者4 个更大、更精确的双精度浮点数。这种位宽的翻倍本质上是为数据流动修建了更宽的高速公路让计算的“胃口”增大了一倍。在传统的计算指令中CPU 的操作逻辑通常比较“粗糙”。比如要执行 A B 的操作计算结果必须强制覆盖掉原来的数据 A。这种设计被称为“两操作数”模式它具有一定的破坏性——如果你后续还需要用到原始数据 A就必须在计算前额外花时间把它备份到另一个地方。AVX 引入了更先进的VEX 编码实现了“三操作数”模式。它允许程序下达更精细的指令“取数据 A取数据 B计算结果存入 C”。这样一来原始数据 A 和 B 都被完好地保留了下来。这种进化精简了大量的重复劳动减少了数据在内存中反复搬运、备份的开销使得整个程序的逻辑变得更加轻盈和高效。AVX 带来的不仅仅是速度的微调而是处理逻辑的底层进化。它将原本需要一个接一个排队执行的“串行”任务转化为成批进行的“向量化”任务。在理想的计算密集型场景下如科学模型计算或高画质渲染这种转化能让 CPU 的工作效率产生数倍的飞跃。这种进步意味着在面对海量数字运算时CPU 能够极大程度地释放其算术吞吐量。以前需要反复旋转的时钟周期现在通过一次强有力的“向量化打击”即可完成从而在不单纯依赖提高主频的情况下实现了性能的跨越式提升。AVX2整型运算与灵活性的飞跃2013 年发布的AVX2进一步完善了这一体系。如果说 AVX 解决了“算得快”的问题那么 AVX2 则解决了“算得广”的问题全面整型化AVX2 将原有的 256 位并行计算能力从浮点数扩展到了整数领域。这对于数据压缩、图像处理以及数据库检索等依赖整数运算的场景至关重要。非连续数据处理Gather/Permute在实际应用中数据往往零散地分布在内存中。AVX2 引入了“收集”Gather指令允许 CPU 从不连续的内存地址批量抓取数据显著增强了处理复杂数据结构的能力。在代码中使用 AVX / AVX2编译器开关GCC/Clang:AVX:-mavxAVX2:-mavx2FMA若需要:-mfma若希望对目标 CPU 最佳化-marchnative但会生成依赖当前 CPU 的代码MSVC:/arch:AVX或/arch:AVX2视 VS 版本推荐做法编译时可以生成带 AVX/AVX2 的专门文件或编译多版本并在运行时选择runtime dispatch。Intrinsics示例 API浮点AVX__m256float32 ×8和__m256ddouble ×4load/store:_mm256_loadu_ps,_mm256_storeu_psunalignedadd/mul:_mm256_add_ps,_mm256_mul_psfused:_mm256_fmadd_ps需要 FMA整数AVX2__m256iadd:_mm256_add_epi32gather:_mm256_i32gather_epi32从 int 索引收集shift/and/or:_mm256_slli_epi32,_mm256_and_si256等基本样例C/C intrinsics下面这些小样例可以比较直观的体验下AVX。浮点数组相加AVX#includeimmintrin.h#includestddef.hvoidadd_float_arrays_avx(constfloat*a,constfloat*b,float*out,size_t n){size_t i0;constsize_t stride8;// 8 floats per __m256for(;istriden;istride){__m256 va_mm256_loadu_ps(ai);// unaligned load__m256 vb_mm256_loadu_ps(bi);__m256 vr_mm256_add_ps(va,vb);_mm256_storeu_ps(outi,vr);}// tailfor(;in;i)out[i]a[i]b[i];}编译g -O3 -mavx -stdc17 avx_samples.cpp -o avx_samples浮点点积AVX reduction#includeimmintrin.h#includestddef.hfloatdot_product_avx(constfloat*a,constfloat*b,size_t n){size_t i0;constsize_t stride8;__m256 acc_mm256_setzero_ps();for(;istriden;istride){__m256 va_mm256_loadu_ps(ai);__m256 vb_mm256_loadu_ps(bi);__m256 prod_mm256_mul_ps(va,vb);acc_mm256_add_ps(acc,prod);}// horizontal sum of acc__attribute__((aligned(32)))floattmp[8];_mm256_store_ps(tmp,acc);floatsumtmp[0]tmp[1]tmp[2]tmp[3]tmp[4]tmp[5]tmp[6]tmp[7];for(;in;i)suma[i]*b[i];returnsum;}试一下AVX2整型并行加法与 gather 示例#includeimmintrin.h#includestddef.h// add 8 32-bit ints in parallelvoidadd_int32_avx2(constint32_t*a,constint32_t*b,int32_t*out,size_t n){size_t i0;constsize_t stride8;// 8 x int32 in 256 bitsfor(;istriden;istride){__m256i va_mm256_loadu_si256((const__m256i*)(ai));__m256i vb_mm256_loadu_si256((const__m256i*)(bi));__m256i vr_mm256_add_epi32(va,vb);_mm256_storeu_si256((__m256i*)(outi),vr);}for(;in;i)out[i]a[i]b[i];}// gather example: gather int32_t at indices array idx from base pointer basevoidgather_example(constint32_t*base,constint32_t*idx,int32_t*out){__m256i vindex_mm256_loadu_si256((const__m256i*)idx);// indices__m256i gathered_mm256_i32gather_epi32(base,vindex,4);_mm256_storeu_si256((__m256i*)out,gathered);}编译g -O3 -mavx2 -stdc17 avx_samples.cpp -o avx2_samples