转自 NEON优化:性能优化经验总结-CSDN博客

NEON优化:性能优化经验总结
1. 什么是 NEON
        Arm Adv SIMD 历史
2. 寄存器
3. NEON 命名方式
4. 优化技巧
5. 优化 NEON 代码(Armv7-A内容,但区别不大)
        5.1 优化 NEON 汇编代码
        5.1.1 Cortex-A 处理器之间的 NEON 管道差异
        5.1.2 内存访问优化
 

Reference:

  1. NEON优化:性能优化经验总结
  2. NEON官方内联函数
  3. Arm NEON programming quick reference
  4. Learn the architecture - Neon programmers’ guide

如果觉得直接在 NEON 上编译不太方便,可在SSE上编译后转NEON,可参考:https://github.com/DLTcollab/sse2neon

1. 什么是 NEON

NEON 技术是用于 Arm Cortex-A 系列处理器的先进 SIMD(单指令多数据)架构。它可以加速多媒体和信号处理算法,如视频编码器/解码器、2D/3D图形、游戏、音频和语音处理、图像处理、电话和声音。

NEON 指令执行“打包 SIMD”处理:

  • 寄存器被认为是相同数据类型元素的向量
  • 数据类型支持:带符号/无符号 8 88 位,16 1616 位,32 3232 位,64 6464 位,ARM 32 3232位平台上的单精度浮点数,ARM 64 6464位平台上的单精度浮点数和双精度浮点数。
  • 指令在所有通道中执行相同的操作

Arm Adv SIMD 历史

 

2. 寄存器

Armv7-A 和 AArch32 具有相同的通用 ARM 寄存器 - 16 1616 x 32 3232 位 通用ARM寄存器(R0-R15),以及 32 x 64 位 NEON寄存器(D0-D31)。这些寄存器也可以看作是 16 × 128 位寄存器(Quad-word, Q0-Q15)。每个 Q0-Q15 寄存器映射到一对 D寄存器,如下图所示。
 

相比之下,AArch64 具有 31 3131 个 64 6464 位 通用ARM寄存器 和 1 11 个具有不同名称的特殊寄存器(零寄存器/栈指针寄存器(XZR/SP)),这取决于使用它的上下文。这些寄存器可以被看作是 31 3131 个 64 6464 位寄存器(X0-X30) 或 31 3131 个32 3232 位寄存器(W0-W30)(高32位被忽略)。
AArch64 具有 32 3232 x 128 128128 位 NEON 寄存器(V0-V31,Vector Registers)(整个的寄存器被叫做V寄存器,即用来做向量化的寄存器,Vector Registers,但用作128位寄存器时,还是可以称作 Q寄存器,这样很明显更有指向性)。这些寄存器也可以看作是 32 3232 位 Sn寄存器(Single-word Registers) 或 64 6464 位 Dn寄存器(Double-word Registers) 或 16 1616 位的 H寄存器(Half-precision Registers)。
 

(也就是说,V 寄存器有 128 位,D 寄存器 64 位,S寄存器 32 位,可以将 V 寄存器拆开使用)

3. NEON 命名方式

变量命名方式:

  • baseWxLxN_t
    • base:是基础数据类型
    • W:是基础类型的宽度
    • L:是向量的长度
    • N:是向量数组的个数
  • 如 uint8x16_tuint8x16x3_t

函数命名方式:

  • ret v[p][q][r]name[u][n][q](args)
    • ret:返回值类型
    • v:表示vector
    • q:饱和运算,溢位后,为自动限制在数据类型的最大范围内
    • r:圆整操作
    • name:SIMD指令名称
    • u:unsigned
    • n:narrow
    • q:做后缀表示128位满位宽寄存器运算 quarter*32

4. 优化技巧

  • 热点函数涉及到大量 IO 读写操作时,数据的内存地址尽量与 NEON 数组或系统位数对齐,如32位对齐,可降低访问开销;

  • 重点优先搞 NEON 指令并行计算,能大幅降低开销;

  • 大部分的 NEON 问题会出在存取、移动指令的滥用、混乱使用上;

  • for 循环:

    • 如 for (b = 0; b < num; b++):
    • 可改成 for (b = 0; b < num - 3; b += 4);
    • 或者 for (b = num - 1; b >= 3; b -= 4);
    • 需注意结尾不能整除的几个还是用非SIMD方式计算:
    • 原始:for (i = 0; i < size; i++);
    • 并行:for (i = 0; i < size - 3; i += 4);
    • 扫尾:for (; i < size; i ++)。
  • 数组索引取值:
    • 数组索引以及索引内部涉及运算的,尽量换成指针偏移加减来做;
    • 避免大范围索引跳跃,减少 cache miss
  • 内存使用:
    • 优先用局部变量,而非 malloc 堆内存,减少 cache miss;
    • 针对具体变量类型,手动 for 循环并行拷贝值,可能比 memcpy() 函数更高效,因为 memcpy 内部还涉及大量判断,以保证平台兼容性;
    • 用NEON指令时,4 路运算的数组(128位=16字节),内存地址最好要 16 字节对齐。
  • 指令运算
    • 矩阵乘场景,在不大幅增加寄存器变量的前提下,外部的A也最好并行多读几路数据进来,跟B的各列运算,减少B各列的读取次数;
    • 乘加指令,add 和 mul 可以合并为 mla,一条指令完成乘加操作。
  • C 语言编码级考虑
    • C 语言中一条事件的处理函数尽可能在一个源文件中(便于编译器自动向量化);
    • switch 比 if else 快,而且代码整洁。
  • 深入理解计算机系统
    • 组织代码结构,善用 CPU 缓存,数据段/代码段连续可以提高 CPU 缓存命中率
    • 极简函数时,尽量 inline 展开,减少函数调用栈的开销;
    • 消除不必要的存储器引用,如 for 循环中 *dest = *dest - nums[i],可用中间变量替换 *dest,for 循环后再赋值给 *dest,可减少 for 内的一次读写操作;
    • 简单的循环展开,编译器可以自己完成,优化选项 O2 及以上,或者命令 -funroll-loops(O2 及以上自带),可调用 gcc 进行循环展开;
    • 能用整型不用浮点,整数乘法/加法和浮点加法,只用一个周期,浮点乘法需要2个周期。
  • NEON 与 SSE 在寄存器处理数据时有一些区别在 NEON 中,通常需要先将要处理的数据加载到 NEON 寄存器,然后执行 SIMD 操作。这与 SSE 有一些不同,因为 SSE 寄存器(XMM 寄存器)可以直接与内存交互(这一步可能格外耗时,需要特别注意)。在 NEON 中,加载数据到 NEON 寄存器通常包括以下步骤:
    • 从内存加载数据到通用寄存器(通常是ARM通用寄存器)。
    • 将数据从通用寄存器传送到 NEON 寄存器。

然后,您可以在 NEON 寄存器上执行 SIMD 操作,例如矢量加法、矢量乘法等。

 这与 SSE 不同,因为 SSE 寄存器可以直接从内存加载数据,而不需要中间步骤。这可以在 SSE 指令中实现,而不需要将数据先加载到通用寄存器中。

总之,NEON 需要额外的步骤来加载数据到寄存器,然后才能进行 SIMD 操作,而 SSE 可以更直接地在寄存器中操作数据。这是因为不同架构和指令集设计的差异。

5. 优化 NEON 代码(Armv7-A内容,但区别不大)

5.1 优化 NEON 汇编代码

考虑处理器如何集成 NEON 技术的实现定义方面,因为针对特定处理器优化的指令序列可能在不同的处理器上具有不同的时序特征,即使 NEON 指令周期时序相同。

为了从手写的 NEON 代码中获得最佳性能,有必要了解一些底层硬件特性。特别是,程序员应该意识到流水线和调度问题、内存访问行为和调度危害。

5.1.1 Cortex-A 处理器之间的 NEON 管道差异

Cortex-A8 和 Cortex-A9 处理器共享相同的基本 NEON 管道,尽管在如何将其集成到处理器管道中存在一些差异。Cortex-A5 处理器包含一个完全兼容的简化 NEON 执行管道,但它是为尽可能最小和最低功耗的实现而设计的。

5.1.2 内存访问优化

TLB(Translation Lookaside Buffer) 是计算机系统中的一种硬件缓存用于加速虚拟地址到物理地址的转换过程。TLB 的每个条目称为 TLB entry(TLB条目)它存储了一组 虚拟地址 和相应的 物理地址 之间的映射关系。TLB 通常位于 CPU 内部,用于提高内存访问的速度。

当程序执行时,CPU 需要将虚拟地址(由程序使用)转换为物理地址(在内存中实际存储数据的地址)这个地址转换通常由操作系统的内存管理单元(MMU)来执行。MMU 将虚拟地址映射到物理地址,并在需要时将这些映射关系存储在 TLB 中,以便以后的访问可以更快地完成,而无需再次执行昂贵的地址转换操作。

TLB entry 通常包括以下信息:

  1. 虚拟地址(Virtual Address):程序使用的地址。
  2. 物理地址(Physical Address):在内存中实际存储数据的地址。
  3. 标志位(Flags):包括权限信息(例如,读、写、执行权限)和其他控制信息。

当 CPU 需要访问内存中的数据时,它首先查看 TLB 来查找虚拟地址和物理地址之间的映射关系。如果找到了匹配的 TLB entry,那么物理地址将用于访问内存,这将显著提高内存访问速度。如果没有找到匹配的 TLB entry,CPU 将向 MMU 请求执行地址转换,并将结果存储在 TLB 中以供将来使用。

总之,TLB entry 是 TLB 中存储的虚拟地址到物理地址映射的单元,用于加速计算机内存访问的过程。这有助于提高系统的性能和效率。

L1 和 L2 缓存的概念可以看这篇文章,描述的更清楚:寄存器、缓存、内存(虚拟、物理地址)、DDR、RAM的关系

NEON 单元很可能会处理大量数据,例如数字图像。一个重要的优化是确保算法以最适合缓存的方式访问数据。这样可以从 L1 和 L2 缓存中获得最大的命中率(hit rate)。考虑活动内存位置的数量也很重要。在 Linux 下,每个 4KB 的页面都需要一个单独的 TLB 条目。Cortex-A9 处理器有多个 32 3232 个元素的 micro-TLB 和一个 128 128128 个元素的主 TLB,之后它将开始使用 L1 缓存来加载页表条目(page table entry)。一种典型的优化是安排算法以适当的大小处理图像数据,以最大限度地提高缓存和 TLB 命中率。

支持 交错(interleaving) 和 反交错(de-interleaving) 的指令可以为性能改进提供很大的空间。VLD1 从内存加载寄存器,没有去交错。然而,其他 VLDn 操作使我们能够加载、存储和反交错包含两个、三个或四个相同大小的 8 88、16 1616 或 32 3232 位元素的结构。VLD2 加载两个或四个寄存器,去交错的偶数和奇数元素。例如,这可以用于分割左通道和右通道立体声音频数据,如下图所示。类似地,VLD3 可用于将 RGB 像素分割为单独的通道,相应地,VLD4 可用于 ARGB 或 CMYK 图像。
 

上图显示了用 VLD2.16(16字节) 从 R1 指向的内存中加载两个 NEON 寄存器。这在第一个寄存器中产生 4 44 个 16 1616 位元素,在第二个寄存器中产生 4 个 16位元素,相邻的成对左值和右值被分隔到每个寄存器中。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络摘星题库800题笔记 第2章 物理层

第2章 物理层2.1 物理层概述题组闯关1.采用以下哪种设备&#xff0c;可以使数字信号传输得更远 ( )。 A. 放大器 B. 中继器 C. 网桥 D. 路由器1.【参考答案】B 【解析】选项 A 放大器只是单纯地放大信号、抑制噪音和干扰。选项 B 中继器是把一根线缆中的电或者光信号传递给另一…

导入文件到iPhone实现

我们有时候开发需要加载一些自己的文件&#xff0c;这个时候就需要导入文件到iPhone等设备。在info里面open as source code&#xff0c;加入如下配置&#xff1a;<!-- 开启 iTunes / Finder 文件共享 --><key>UIFileSharingEnabled</key><true/>或者o…

Ubuntu Server系统安装磁盘分区方案

最近打算把家里的旧电脑利用起来&#xff0c;装上Ubuntu Server 24.04.3 LTS作为一个家用NAS服务器&#xff0c;但是给旧电脑安装系统时遇到了一些问题&#xff0c;遂记录下来 GPT分区与MBR分区 GPT 指的是 GUID Partition Table&#xff08;全局唯一标识分区表&#xff09;&am…

1小时 MySQL 数据库基础速通

目录 一、MySQL安装配置 1、下载mysql 2、下载mysql-shell 二、MySQL基本概念 1. 数据库&#xff08;Database&#xff09; 2. 表&#xff08;Table&#xff09; 3. 数据类型&#xff08;Data Type&#xff09; 4. 主键&#xff08;Primary Key&#xff09; 5. 索引&am…

HTTP应用层协议-长连接

HTTP应用层协议-长连接 关于 connection 报头 HTTP 中的 Connection 字段是 HTTP 报文头的一部分&#xff0c;它主要用于控制和管理客户端与服务器之间的连接状态 核心作用 • 管理持久连接&#xff1a;Connection 字段还用于管理持久连接&#xff08;也称为长连接&#xff09;…

2020/12 JLPT听力原文 问题一 4番

4番&#xff1a;ホテルの受付で女の人と男の人が話しています。女の人はどこでパソコンを使いますか。女&#xff1a;すみません、パソコンの貸出ってできますか。部屋で仕事をしたいんですけど。 男&#xff1a;申し訳ございません。貸出はしていないんですが、二階にビジネス…

《在 Spring Boot 中安全使用 Qwen API-KEY:环境变量替代明文配置的最佳实践》

《在 Spring Boot 中安全使用 Qwen API-KEY&#xff1a;环境变量替代明文配置的最佳实践》 想要的效果其实就是 把 Qwen API-KEY 放到系统环境变量中&#xff0c;然后在 application.yml 里通过占位符读取&#xff0c;而不写明文。 这样即便 application.yml 被提交到 Git&…

Nginx 反向代理与负载均衡架构

一、反向代理基础 实验目的&#xff1a;通过 Nginx 反向代理&#xff0c;将客户端请求按类型&#xff08;静态页面 / 动态 PHP 页面&#xff09;转发到不同的后端服务器&#xff08;RS1 处理静态资源&#xff0c;RS2 处理动态请求&#xff09;&#xff0c;实现 “客户端只与代…

【Mybatis入门】配置Mybatis(IDEA)

Mybatis和JDBC一样&#xff0c;是连接数据库的工具。它是一款优秀的持久层框架&#xff0c;主要用于 Java 语言中简化数据库操作&#xff0c;实现对象与数据库表之间的映射。Mybatis相比于JDBC的优势Mybatis消除了传统 JDBC 代码中繁琐的手动处理、参数设置、结果集解析等重复工…

多路转接之epoll 【接口】【细节问题】【LT与ET模式】【Reactor】

目录 一.接口 1.1epoll_creaet 1.2epoll_ctl 1.3epoll_wait 二.细节问题 2.1 工作原理 2.2 epoll的demo 2.3 epoll的优点 三. LT 与 ET模式 理解ET 四. reactor 一.接口 1.1epoll_creaet 注意返回值是一个文件描述符 创建一个epoll模型 1.2epoll_ctl 返回值&…

渗透测试现已成为 CISO 战略的核心

随着数字供应链的扩展以及生成式人工智能在关键系统中的嵌入&#xff0c;安全领导者正在重新思考其网络安全策略。Emerald Research 最近对 225 位安全领导者进行的一项调查发现&#xff0c;68% 的人担心第三方软件和组件带来的风险。虽然大多数受访者表示他们正在满足监管要求…

音视频学习(五十三):音频重采样

概述 音频重采样&#xff08;sample rate conversion, SRC&#xff09;是把采样率从 Fs_in 变换为 Fs_out 的过程。常见场景有格式转换&#xff08;44.1→48 kHz&#xff09;、采样率匹配&#xff08;播放链路统一采样率&#xff09;、以及通信中语音采样率升降&#xff08;8 k…

【C#】正则表达式

一、核心优势&#xff1a;用一小段规则搞定大量复杂的字符串匹配&#xff0c;查找和替换&#xff0c;并且可移植可复用。使用正则表达式的好处&#xff1a;1. 强大且灵活&#xff1a;可以一次性匹配非常复杂的规则&#xff0c;比如验证邮箱、提取特定的格式日志、解析URL&#…

【[特殊字符][特殊字符] 协变与逆变:用“动物收容所”讲清楚 PHP 类型的“灵活继承”】

你有没有遇到过这样的问题&#xff1a;“为什么子类方法可以返回 Cat&#xff0c;而父类只写了返回 Animal&#xff1f;” “为什么参数反而能从 CatFood 变成更宽泛的 Food&#xff1f;”这些看似“违反直觉”的设计&#xff0c;其实背后有一个优雅的编程概念&#xff1a;协变…

cesium/resium 修改子模型材质

我是 www.v2ex.com/t/1151549 的作者&#xff0c;在csdn这边补全一些更多的信息 相关工具 主项目插件版本&#xff1a; "cesium": "^1.131.0",、"resium": "^1.19.0-beta.1"、"three": "^0.178.0"、"react…

nvm install 14.21.3 时npm 无法下载和识别

错误&#xff1a;C:\Users\H3C>nvm install 14.21.3 Downloading node.js version 14.21.3 (64-bit)... Complete Downloading npm... Creating C:\Users\H3C\AppData\Local\Temp\nvm-install-939491942\temp Downloading npm version 6.14.18... Error while downloading h…

【网络运维】Linux:LNMP 项目实践

LNMP 项目实践 简介&#xff1a;什么是 LAMP/LNMP LAMP&#xff1a;LinuxApacheMysql/MariadbPHP/Python/Perl。 LNMP&#xff1a;LinuxNginxMysql/MariadbPHP/Python/Perl。 Linux&#xff1a;操作系统&#xff0c;提供程序运行基础。Apache/Nginx&#xff1a;Web 服务器&…

用 Docker 安装并启动 MySQL:从零到实战的完整指南

用 Docker 安装并启动 MySQL&#xff1a;从零到实战的完整指南MySQL 是目前最流行的关系型数据库之一&#xff0c;广泛应用于各类应用系统中。使用 Docker 部署 MySQL 可以极大简化环境配置&#xff0c;保证开发、测试和生产环境的一致性。本文将详细介绍如何使用 Docker 安装、…

动态规划----1.爬楼梯

70. 爬楼梯 - 力扣&#xff08;LeetCode&#xff09; /** 1阶:1步,即1种; 2阶:1步1步或直接2步,即2种 f(1) 1,f(2) 2 3阶:由1阶迈2步,或2阶迈一步; 4阶:由2阶迈2步,或3阶1步; n阶:由n-2阶迈2步,或n-1阶迈1步 f(n) f(n - 1) f(n - 2) */ class Solution {/**1阶:1步,即1种…

special topic 11 (1)

preface 虽然我知道专业课必须得学&#xff0c;但是要学的东西&#xff0c;好多&#xff0c;我对专业课很害怕&#xff0c;稍微往后挪一挪&#xff0c;今天学了两个强化网课之后再学专业课吧。今天的目标是学完 11 到 14.任重道远&#xff0c;加油&#xff01;从今天开始尽量早…