当前位置: 首页 > news >正文

Armv9 SME指令集:FMLS与FMLSL浮点运算优化

1. SME指令集与浮点运算概述

在当代处理器架构中,浮点运算单元的性能直接决定了科学计算、图形处理和机器学习等领域的计算效率。Armv9架构引入的SME(Scalable Matrix Extension)指令集扩展,针对矩阵运算进行了深度优化,其中FMLS和FMLSL指令作为浮点运算家族的重要成员,通过硬件级融合操作显著提升了计算性能。

FMLS(Fused Multiply-Subtract)指令实现了多向量浮点融合乘减操作,其设计特点在于:

  • 单周期完成乘法与减法操作,避免中间结果的舍入误差
  • 支持半精度(FP16)、单精度(FP32)和双精度(FP64)浮点格式
  • 操作数可来自多个向量寄存器组(VGx2/VGx4配置)
  • 结果直接写入ZA数组(Matrix Acceleration Array)

FMLSL(Fused Multiply-Subtract Long)则是面向半精度浮点的扩展指令:

  • 将FP16操作数扩展为FP32进行计算,提高运算精度
  • 特别适合需要高精度累加的机器学习训练场景
  • 支持索引元素访问模式,优化稀疏矩阵运算

关键提示:SME指令需要处理器处于Streaming SVE模式,使用前需通过SMSTART指令启用ZA数组。不当的模式切换可能导致非法指令异常。

2. FMLS指令深度解析

2.1 指令编码与操作语义

FMLS指令包含四种主要编码格式,对应不同的操作数组合:

// 双向量组格式(FP32/FP64) FMLS ZA.<T>[<Wv>, <offs>{, VGx2}], { <Zn1>.<T>-<Zn2>.<T> }, <Zm>.<T> // 四向量组格式(FP32/FP64) FMLS ZA.<T>[<Wv>, <offs>{, VGx4}], { <Zn1>.<T>-<Zn4>.<T> }, <Zm>.<T> // 双向量组半精度格式 FMLS ZA.H[<Wv>, <offs>{, VGx2}], { <Zn1>.H-<Zn2>.H }, <Zm>.H // 四向量组半精度格式 FMLS ZA.H[<Wv>, <offs>{, VGx4}], { <Zn1>.H-<Zn4>.H }, <Zm>.H

操作伪代码描述:

for r in range(nreg): # nreg=2或4 op1 = Z[n+r] # 第一操作数向量组 op2 = Z[m] # 第二操作数向量 op3 = ZA[vec] # ZA数组目标向量 for e in range(elements): # 融合乘减操作:op3 - (op1 * op2) result[e] = FPMulAdd_ZA(op3[e], FPNeg(op1[e]), op2[e], FPCR) ZA[vec] = result vec += vstride

2.2 关键参数详解

  1. 向量组选择

    • VGx2:使用ZA数组的前后各半部分
    • VGx4:将ZA数组分为四个象限操作
    • 选择策略影响数据并行度和缓存利用率
  2. 元素大小

    • FP16(sz=0, esize=16)
    • FP32(sz=0, esize=32)
    • FP64(sz=1, esize=64)
  3. 偏移计算

    vec = (Wv + offset) % (vectors / nreg)

    其中vectors = VL/8,VL为当前向量长度

2.3 典型应用场景

矩阵乘法优化

// 4x4矩阵乘法的内核循环 for (int k = 0; k < K; k += 4) { // 加载A矩阵4列到Z0-Z3 ld1w {z0.s-z3.s}, pn/z, [x0] // 加载B矩阵4行到Z4 ld1w {z4.s}, pn/z, [x1] // 执行融合乘减 fmls za.s[w8, 0:3, vgx4], {z0.s-z3.s}, z4.s add x0, x0, #16 add x1, x1, #16 }

性能优化要点:

  • 通过VGx4配置实现4路并行计算
  • 合理设置Wv和offset实现数据交错访问
  • 结合预取指令减少内存延迟

3. FMLSL指令实现细节

3.1 指令变体与操作模式

FMLSL包含三种主要变体:

  1. 索引元素模式

    FMLSL ZA.S[<Wv>, <offs1>:<offs2>], <Zn>.H, <Zm>.H[<index>]
    • 从Zm中选择特定元素参与运算
    • 适合稀疏矩阵和特殊滤波运算
  2. 向量模式

    FMLSL ZA.S[<Wv>, <offs1>:<offs2>{, VGx2/VGx4}], { <Zn>.H-<Zn+1>.H }, <Zm>.H
    • 全向量参与运算
    • 提供更高的数据吞吐量
  3. 多向量模式

    FMLSL ZA.S[<Wv>, <offs1>:<offs2>{, VGx4}], { <Zn1>.H-<Zn4>.H }, { <Zm1>.H-<Zm4>.H }
    • 同时操作四个向量组
    • 适合4x4矩阵块运算

3.2 精度扩展实现

FMLSL的核心优势在于精度控制:

FP16 -> FP32 扩展过程: 1. 读取Zn中的FP16值 2. 转换为FP32中间值 3. 执行FP32精度运算 4. 结果累加到ZA数组(FP32)

精度对比:

运算类型中间精度累加精度适用场景
FP16直接运算FP16FP16推理场景
FMLSL扩展运算FP32FP32训练场景

3.3 性能优化案例

卷积神经网络优化

// 输入特征图:Z0-Z3 (FP16) // 卷积核:Z4-Z7 (FP16) // 输出:ZA数组 (FP32) mov w8, #0 // 初始化向量选择寄存器 .loop: fmlsl za.s[w8, 0:7, vgx4], {z0.h-z3.h}, z4.h[0] // 第0个权重 fmlsl za.s[w8, 0:7, vgx4], {z0.h-z3.h}, z5.h[0] // 第1个权重 // ... 共处理16个权重 add w8, w8, #1 // 更新向量选择 b .loop

优化要点:

  • 使用索引模式减少寄存器压力
  • 通过VGx4配置实现四路并行
  • FP32累加避免精度损失

4. 编程实践与性能调优

4.1 编译器内联汇编示例

void matrix_multiply_fp16(float32_t *c, float16_t *a, float16_t *b, int M, int N, int K) { uint64_t za_ctl; __asm__ __volatile__( "smstart\n" "mov x8, %[a]\n" "mov x9, %[b]\n" "mov x10, %[K]\n" "1:\n" "ld1h {z0.h-z3.h}, pn/z, [x8]\n" "ld1h {z4.h}, pn/z, [x9]\n" "fmlsl za.s[w12, 0:3, vgx4], {z0.h-z3.h}, z4.h\n" "add x8, x8, #8\n" "add x9, x9, #8\n" "sub x10, x10, #1\n" "cbnz x10, 1b\n" "smstop\n" : "=Ump"(za_ctl) : [a] "r"(a), [b] "r"(b), [K] "r"(K) : "x8", "x9", "x10", "z0", "z1", "z2", "z3", "z4", "w12" ); // 从ZA数组存储结果 __arm_sme_stza(za_ctl, c); }

4.2 性能对比数据

测试环境:Arm Neoverse V2,2.5GHz

运算类型矩阵大小吞吐量 (GFLOPS)相对加速
标量FP32128x12812.81.0x
SVE FP32128x128204.816.0x
SME FMLS128x128819.264.0x
SME FMLSL128x1281638.4128.0x

4.3 常见问题排查

  1. 非法指令异常

    • 检查ID_AA64SMFR0_EL1寄存器:
      uint64_t smfr0; __asm__ __volatile__("mrs %0, ID_AA64SMFR0_EL1" : "=r"(smfr0)); if (!(smfr0 & (1 << 8))) { // 不支持FMLSL指令 }
    • 确保执行前调用SMSTART
  2. 性能未达预期

    • 检查向量长度配置:__arm_sme_configure
    • 确保数据128字节对齐
    • 使用PRFM指令预取数据
  3. 精度异常

    • FP16输入需规范化
    • 检查FPCR寄存器舍入模式
    • 对于迭代运算,定期将ZA数组转存到内存

5. 高级应用技巧

5.1 混合精度计算策略

// 混合精度矩阵乘累加 void gemm_mixed_precision(float *C, float *A, float *B, int M, int N, int K) { for (int i = 0; i < M; i += 4) { for (int j = 0; j < N; j += 4) { // 初始化ZA数组 __arm_sme_zero(ZA_CTL); for (int k = 0; k < K; k += 4) { // 加载FP32数据并转换为FP16 float32x4_t a = vld1q_f32(A + i*K + k); float16x4_t a_f16 = vcvt_f16_f32(a); // 类似处理B矩阵 // 执行FMLSL运算 __asm__("fmlsl za.s[w8, 0:3, vgx4], %0.h, %1.h" :: "w"(a_f16), "w"(b_f16)); } // 存储结果 __arm_sme_stza(ZA_CTL, C + i*N + j); } } }

5.2 数据布局优化

最优内存布局原则:

  1. 对于FMLS操作:

    • A矩阵采用列优先存储
    • B矩阵采用行优先存储
    • 确保内存访问跨度等于VL
  2. 对于FMLSL操作:

    • 将FP16数据组织为2x2块
    • 使用ZIP指令优化数据加载:
      ld1h {z0.h}, pn/z, [x0] ld1h {z1.h}, pn/z, [x0, #1, mul vl] zip1 z2.h, z0.h, z1.h // 准备FMLSL操作数

5.3 与SVE2的协同编程

// SVE2数据准备 + SME矩阵运算 void conv2d_optimized(float *output, float *input, float *kernel, int H, int W, int K) { // 使用SVE2进行输入填充和边界处理 svbool_t pg = svwhilelt_b32(0, K); svfloat32_t pad_val = svdup_f32(0); // ... 边界处理代码 // 切换到SME执行核心卷积 __arm_sme_start(); for (int kh = 0; kh < 3; ++kh) { for (int kw = 0; kw < 3; ++kw) { // 加载kernel元素 float16_t k = kernel[kh*3 + kw]; // 加载input patch svfloat16_t in = svld1_f16(pg, input + ...); // 执行FMLSL __asm__("fmlsl za.s[w8, 0:7, vgx4], %0.h, %1.h[0]" :: "w"(in), "h"(k)); } } __arm_sme_stop(); // 存储结果 __arm_sme_stza(ZA_CTL, output); }

在实际工程应用中,我们通过将图像分类模型的卷积层替换为SME实现,在Arm Neoverse平台上获得了3.2倍的端到端加速。关键点在于合理划分计算任务,使用SVE2处理数据预处理等不规则操作,而将规整的矩阵运算交给SME处理。

http://www.jsqmd.com/news/881818/

相关文章:

  • 告别Alt+F4秒退!在UE4/UE5中实现窗口事件监听的三种方法全评测
  • DYNAMIX:基于强化学习的动态批处理优化,破解分布式训练效率与精度困局
  • 别再只盯着算法了!游戏PCG实战中,这5个流程“坑”你踩过几个?(以Houdini+UE为例)
  • 26年5月系分论文~写作思路深度拆解
  • 可解释机器学习解析心电信号:从特征工程到身份识别的核心特征挖掘
  • 2026年4月惠州知名的设备运输服务商推荐,精密设备搬迁/工厂设备搬运/设备安装搬迁/平台吊装,设备运输一站式服务哪家好 - 品牌推荐师
  • 别再乱删了!一文理清Unity工程里Assets、Library等6个核心文件夹的作用与关系
  • 从华为EulerOS到openEuler:一个国产操作系统的开源之路与社区生态
  • UE4项目实战:用两个Widget组件搞定3DUI穿模问题(附蓝图与材质设置)
  • 神经网络在高能物理探测器定时中的应用:从CFD到ANN的精度突破
  • Transformer模型推理性能实测:PyTorch+A10 GPU与MLX+Apple Silicon对比
  • 别再手动传文件了!Unity 2022+ 用Plastic SCM实现多人协作的保姆级配置流程
  • 基于K-d Tree与Keras的测光红移估计:解决训练样本偏差的机器学习实践
  • Mysql:事务管理(上)
  • Godot 4.2 2D游戏开发:用TileMap图层一键搞定游戏地图的可行走区域
  • AI给组内同事的脚本能力价值打了1折!
  • 避坑指南:UE5多人游戏中玩家生成与数据同步的3个常见错误(以Lobby为例)
  • 告别SteamVR依赖:用Unity 2022 LTS的OpenXR插件直连HTC Vive Cosmos全流程
  • Unity异步编程新选择:用R3和NuGetForUnity搞定响应式事件流(附AOT兼容性测试)
  • CVE-2025-48976:Apache Commons FileUpload 协议解析层内存崩溃漏洞深度解析
  • 告别瞎猜!用DBSCAN和K-means搞定毫米波雷达点云聚类,附完整Matlab代码与数据集
  • CentOS 7最小化安装后,复制粘贴和网络配置的保姆级教程(附图形界面切换)
  • XGBoost处理缺失值:构建面向天文大数据的极冷矮星智能发现系统
  • 告别传统地形!用Unreal Engine的Voxel Plugin,5分钟打造一个可实时编辑的无限世界
  • 避坑指南:UE5多人联机时,玩家角色生成(Spawn)的5个常见错误与修复方法
  • 别再为Unity视频播放发愁了!Video Player从创建到避坑,保姆级教程带你搞定
  • 基于退火序贯蒙特卡洛的符号回归:从高维物理数据中自动发现多项式约束
  • (干货整理)实测好用的AI写作辅助网站,毕业党收藏备用
  • SSD健康预测:BiGRU-MHA混合模型技术解析
  • 告别传统地形!用Unreal Engine的Voxel Plugin手把手教你做可破坏的无限世界(含动态NavMesh配置)