ARM技术william hill官网
直播中

李英

7年用户 1475经验值
私信 关注
[经验]

一文详解SIMD架构与SVE2的演进

Arm推出了具有日益强大的安全性和人工智能 (AI) 能力的下一代 Armv9 架构。紧随其后的是 推出的全新 Arm Total Compute 解决方案,其中包括首款 Armv9 CPU。开发人员将立即看到的最大新功能是矢量处理的增强。它将在更广泛的应用中增强机器学习 (ML) 和数字信号处理 (DSP) 能力。在这篇博文中,我们将分享第二版可扩展矢量扩展(SVE2) 的优势和好处。

图1 。在 Armv9 中为 ML 和 DSP 扩展矢量处理(来自 Arm Vision Day)

什么是 SVE 和 SVE2?

利用并行执行指令(称为 SIMD(单指令多数据)指令)可以加快处理大量数据的应用程序的速度。SVE最初是作为 Armv8.2 架构的可选扩展引入的,遵循现有的Neon 技术。SVE2作为 SVE 的功能扩展,为 Armv9 CPU 引入。SVE2和SVE的主要区别在于指令集的功能覆盖。SVE 专为高性能计算 (HPC) 和 ML 应用程序而设计。SVE2 扩展了 SVE 指令集,以支持 HPC 和 ML 之外的数据处理领域,例如计算机视觉、多媒体、游戏、LTE 基带处理和通用软件。我们将 SVE 和 SVE2 视为我们 SIMD 架构的演进,带来了 Neon 已经提供的功能之外的许多有用功能。

为什么使用 SVE2?

顾名思义,SVE2 设计理念使开发人员能够编写和构建软件一次,然后在具有各种 SVE2 矢量长度实现的不同 AArch64 硬件上运行相同的二进制文件。由于某些笔记本电脑和移动设备的向量长度不同,SVE2 可以通过共享代码来降低跨平台支持的成本。消除重新构建二进制文件的要求可以更轻松地移植软件。二进制文件的可扩展性和可移植性意味着开发人员不必了解和关心目标设备的向量长度。当软件跨平台共享或长时间使用时,SVE2 的这一特殊优势更为有效。

除此之外,SVE2 生成的汇编代码比 Neon 更简洁、更容易理解。这显着降低了生成代码的复杂性,使其更易于开发和维护。这提供了整体更好的开发人员体验。

如何使用 SVE2

那么,您如何才能充分利用 SVE2?有几种方法可以编写或生成 SVE2 代码:使用 SVE2 的库

使用 SVE2 的库

已经有可用的 SVE2 高度优化的库,例如Arm Compute Library。Arm Compute Library 提供优于其他开源替代方案的卓越性能,并立即支持 SVE2。

支持 SVE2 的编译器

C/C++ 编译器从 C/C++ 循环生成 SVE2 代码。要生成 SVE2 代码,请为 SVE2 功能选择适当的编译器选项。例如,对于 armclang,启用 SVE2 优化的一个选项是 March=armv8-a+sve2。

C/C++ 中的 SVE2 内在函数

SVE2 内在函数是编译器用适当的 SVE2 指令替换的函数调用。SVE2 内在函数使您可以直接从 C/C++ 代码访问大部分 SVE2 指令集。您可以在此处通过内部函数搜索引擎搜索 SVE2 内部函数 。

#include <arm_sve.h>

void saxpy(const float x[], float y[], float a, int n) {

for (int i = 0; i < n; i += svcntw()) {

svbool_t pg = svwhilelt_b32(i, n);

svfloat32_t vec_x = svld1(pg, &x[i]);

svfloat32_t vec_y = svld1(pg, &y[i]);

vy = svmla_x(pg, vy, vx, a);

svst1(pg, &y[i], vy);

}

}

代码1 。SVE2 内在示例

SVE2 组装

您可以使用 SVE2 指令编写汇编文件,也可以根据需要使用内联汇
编。

ld1w { z0.s }, p0/z, [x1, x8, lsl #2]

ld1w { z1.s }, p0/z, [x2, x8, lsl #2]

子 z0.s、z0.s、z1.s

st1w { z0.s }, p0, [x0, x8, lsl #2]

包括x8

而 p0.s, x8, x9

b.mi.LBB0_1

代码2 。SVE2 组装示例

如果有支持 SVE2 的库可以提供您需要的功能,那么使用它们可能是最简单的选择。汇编通常可以为某些应用程序提供令人印象深刻的性能,但由于寄存器管理和可读性,它更难以编写和维护。另一种替代方法是使用内在函数,它生成适当的 SVE2 指令并允许从 C/C++ 代码调用函数,从而提高可读性。除了库和内在函数之外,SVE2 还允许您让编译器自动矢量化代码,从而在保持高性能的同时提高易用性。有关如何为 SVE2 编程的更多信息,请访问此 Arm 开发人员页面。

SVE2 可能有效的示例

SVE2 不仅使向量长度可扩展,而且还具有许多其他特性。在本节中,我们将向您展示一些使用 SVE2 的好处的示例以及一些已添加的新说明。

收集负载和分散存储

非线性数据访问模式在各种应用程序中都很常见。许多现有的 SIMD 算法花费大量时间将数据结构重新排列为可矢量化的形式。SVE2 的收集加载和分散存储允许在非连续内存位置和 SVE2 寄存器之间直接传输数据。

图 2 。收集负载和分散存储

FFT(快速傅立叶变换)是可以从中受益的一个过程示例。此操作在图像压缩和无线通信等许多领域都很有用。这种分散存储功能非常适合FFT 中使用的蝶形运算寻址。

计算能力更强的指令

SVE2 指令集实现复值整数运算。它们对于具有复杂计算的操作特别有用,例如用于表示游戏中对象的方向和旋转的四元数。例如,SVE2 汇编中带符号的 16 位复数向量的乘法可以比 Neon 汇编中快 62%。下面是向量乘法的 C 代码版本。类似地,发现使用复数计算 8x8 逆矩阵的速度提高了约 13%。

结构 cplx_int16_t {

int16_t 重新;

int16_t im;

};

int16_t Sat(int32_t a) {

int16_t b = (int16_t) a ;

如果 (a > MAX_INT16) b = 0x7FFF; // MAX_INT16 = 0x00007FFF

如果 (a < MIN_INT16) b = 0x8000; // MIN_INT16 = 0xFFFF8000

返回 b ;

}

无效vecmul(int64_t n,cplx_int16_t * a,cplx_int16_t * b,cplx_int16_t * c){

for (int64_t i=0; i<n; i++) {

c[i].re = Sat((((int32_t)(a[i].re * b[i].re) +

(int32_t)0x4000)>>15) -

(((int32_t)(a[i].im * b[i].im) +

(int32_t)0x4000)>>15));

c[i].im = Sat((((int32_t)(a[i].re * b[i].im) +

(int32_t)0x4000)>>15) +

(((int32_t)(a[i].im * b[i].re) +

代码3 。与 16 位复数整数元素向量乘法的 C 代码

适用于各种应用的全新说明

SVE2 中还引入了一些新指令,例如按位置换、字符串处理和密码学。其中,我想重点介绍一下直方图加速说明。图像直方图广泛应用于计算机视觉和图像处理领域,例如,通过使用 OpenCV 等库。它可用于图像阈值处理和图像质量改进等技术。现代相机和智能手机利用此类信息来计算曝光控制和白平衡,以提供更好的图像质量。

SVE2 中新引入的直方图加速指令提供了两个特定元素匹配的向量寄存器的计数。使用这些指令,可以用更少的指令和比以前更快的速度计算直方图。例如,直方图计算通常如下编码。在我检查 SVE2 功能的实验中,编译器还不够成熟,无法识别循环模式并获取最新指令。因此,我们准备了带有专门指令的汇编代码,以允许对该循环进行矢量化。结果是使用 SVE2 优化的程序集比编译的 C 代码快约 29%。Neon 不提供矢量化这种过程的方法。本节用于衡量性能的汇编代码,以及编译器版本和选项,

void calc_histogram(unsigned int * histogram, uint8_t * records, unsigned int nb_records) {

for (unsigned int i = 0; i < nb_records; i++) {

直方图[记录[i]] += 1;

}

}

代码4 。图像直方图计算的 C 代码

结论

SVE2 是用于计算机视觉、游戏及其他领域的出色指令集。还有许多其他功能我们没有在这里提到,所以如果您想了解更多关于 SVE2 的信息,请查看此页面。此外,可以在此处找到有关 SVE2 编程示例的更多详细信息。未来,将有更多使用 SVE2 的有效用例和应用示例,而不仅仅是突出原始操作的差异。此外,随着时间的推移,编译器优化应该会变得更好。

原作者:三海幸树

更多回帖

发帖
×
20
完善资料,
赚取积分