前言

在前面的文章中我们介绍了NEON的基础,NEON技术的全景,指令及NEON intrinsic指令,相信大家能通过前面的学习写一些简单的NEON程序。但要想写好一个性能高的NEON程序,远不止你以为的那么简单,所以接下来我会给大家在NEON编程中一些优化技巧,助力程序性能起飞。

数据处理

最经典的处理图像的RGB数据,24-bit的RGB图画,像素在内存里的排列布局是R, G, B, R, G, B...,假如你想做一个简单的图像数据处理,比如把R和B通道交流,你该怎么高效的运用NEON协处理器呢?

首要从存储空间线性加载RGB数据到D寄存器,然后交流R和B数据。 可是这种线性加载的数据进行R和B通道的数据交流十分费事,需求首要掩码mask,然后移位并兼并掩码数据。这种杂乱的运算明显并不高效。线性加载RGB数据 ,如下图:

NEON本身已支持多种数据结构的加载和存储指令来处理这种状况,这些指令能把数据从存储区加载还能把这些值分隔存储到不同的寄存器中,你能够运用VLD3加载来把RGB数据分隔存储。运用结构化的加载指令加载RGB数据,如下图:

然后运用VLD3分隔加载的数据就能便利的运用指令(VSWP d0, d2)来进行R和B通道的交流了,然后把成果再写入内存,当然也要运用interleave交错方式的存储,即VST3存储指令。交流寄存器d0和d2然后存储,如下图:

降低数据依赖性

要尽量减少指令间的相关性,包括结构相关、数据相关控制相关,保证流水线执行效率更高;

ARMv7-A平台注意,NEON指令通常比ARM标准指令集需要更多的指令周期。

原文:On ARMv7-A platform, NEON instructions usually take more cycles than ARM instructions. To reduce instruction latency, it’s better to avoid using the destination register of current instruction as the source register of next instruction.

因此为了减少指令延时,最好避免将当前指令的目的寄存器当作下条指令的源寄存器。

剩余元素处理

当输入的数据宽度不是向量宽度的整数倍时,我们需要考虑结尾如何高效的编写,如把元素补齐到向量宽度的整数倍的修正处理、堆叠处理办法和单个元素处理办法。本质上就是保证对齐,以便数据处理的高效。

Larger Arrays更大的数组

主动将源数组数据补齐到需要的长度的整数倍,这样就能在最终一次数据处理时也依照向量长度处理而不会把接近的数据损坏。

 注:

  • 分配更大的数组需求更多的存储空间,这会添加相当大的空间可能会包括十分多的短数组;
  • 在数组后边补齐的数据元素需要初始化为一个不会影响到成果的值,例如你要做加法,那这个新元素需要初始化为0以影响计算成果。
  • 一些状况下,或许无法初始化填充的数据,不管填充什么都会影响计算的成果;
 //r0 是输入的数组指针;//r1 是输出数组指针;//r2 是数组数据的长度;//假定数组长度大于0,是向量长度的整数倍,而且大于或许等于数组的长度;
add r2, r2, #7 //数据长度加上向量长度-1
lsr r2, r2, #3 //把数组长度变成向量个数,即除以向量8
loop:
subs r2, r2, #1 // 削减循环计数器个数
vld1.8 {d0}, [r0]! // 从数组加载8个元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个向量地址;
... //处理在d0寄存器的数据
vst1.8 {d0}, [r1]! //把8个成果元素保存到输出数组,更新地址r1到下一个向量
bne loop //假如r2不等于0,持续循环

Overlap data elements

这种做法是在处理尾部数据的时候,从后往前提取一个向量的数据进行计算,这样会出现一部分数据重复计算。

 注:

  • 堆叠处理只适用于处理的数组长度不会跟着每次迭代而改动的状况,但不适用于每次结果动态改动的状况,如累加计算,这样堆叠部分的数据会被核算两次;
  • 数组内元素的个数至少大于一次完好迭代的向量大小;
//r0 是输入的数组指针;
//r1 是输出数组指针;
//r2 是数组数据的长度;
//假定数据操作幂等,而且数组长度大于等于一个向量巨细长度。ands r3, r2, #7 //计算每次处理完好个向量后剩下元素个数,运用与操作
beq loopsetup //剩下元素个数为0,则数组长度是整数个向量大小,不必堆叠核算,独自处理第一个元素部分
vld1.8 {d0}, [r0], r3 //加载数组第一个向量,然后更新数组大小为剩下元素个数r3内
... //处理d0寄存器内的输入数据
vst1.8 {d0}, [r1], r3 //坚持8个元素到输出数组,更新指针,然后开端处理循环
loopsetup:
lsr r2, r2, #3 //数组长度除以8,计算循环迭代次数,若干元素跟第一次迭代的堆叠
loop:
subs r2, r2, #1 //削减循环计数器个数
vld1.8 {d0}, [r0]! //从数组加载8个元素,从地址r0到寄存器d0,然后更新地址寄存器r0到下一个向量地址;
... //处理在d0寄存器的数据
vst1.8 {d0}, [r1]! //把8个成果元素保存到输出数组,更新地址r1到下一个向量
bne loop //假如r2不等于0,持续循环

 Process leftovers as single elements

这种做法利用NEON向量可以只加载/存储一个元素的功能,虽然使用向量指令,但是每个结果独立计算和存储。这是一种很不推荐的方法。每次的向量计算只使用一个元素,浪费了计算资源(NEON指令相比于标量指令的执行周期要长)。

注:

  • 这种办法比前面的两种办法速度要慢,每个元素的处理都需求独自进行;
  • 这种的剩下元素处理办法需求两个迭代循环,第一个处理向量的循环,还有处理剩下元素的循环,这会添加代码大小;
  • NEON的单一元素加载只改动方针元素的值,而保存其他的元素不变,假如你向量计算的指令会在一个向量间重复计算,如VPADD,这些寄存器需求在第一个元素加载时初始化。

数据对齐

加载或许存储指令的地址应该对齐到cache line,这样内存的缓存命中率更高。这样就需求在Cortex-A8的处理器上至少16字对齐,假如你不能把输入和输出数组的开端地址对齐到16字节,你就必须处理开端和结尾数据处理的元素以使得后续的数据访问是对齐到cache line的。为了运用内存对齐,你在运用NEON指令时需求运用比如64或许128或许256等地址限定符来拟定加载和存储指令。

Reduce branches

NEON指令集没有跳转指令,当需要跳转时,我们需要借助ARM指令。在ARM处理器中,分支预测技术被广泛使用。但是一旦分支预测失败,代价还是很昂贵的。因此我们最好尽量减少跳转指令的使用。但是实际过程中总的要分支的吧,怎么整?唯有等效替换,比如用逻辑操作代替分支选择

if( flag )
{dst[x * 4]     = m;dst[x * 4 + 1] = m;dst[x * 4 + 2] = m;dst[x * 4 + 3] = m;
}
else
{dst[x * 4]     = n;dst[x * 4 + 1] = n;dst[x * 4 + 2] = n;dst[x * 4 + 3] = n;
}

NEON优化后:

//dst[x * 4]= (a&Eflag) | (b&~Eflag);//dst[x * 4 + 1] = (a&Eflag) | (b&~Eflag);//dst[x * 4 + 2] = (a&Eflag) | (b&~Eflag);//dst[x * 4 + 3] = (a&Eflag) | (b&~Eflag);VBSL qFlag, qA, qB // 指令含义参考之前文章

总结

本文是我个人从平时的学习积累和部分实际场景中总结出来的,由于本身的积累和深度不足,如果错误欢迎指正。本文算是给大家抛砖引玉,大家有好的手段和沉淀可以留言分享,路漫漫其修远兮,吾将上下而求索。性能调优之路博大精深,​不可一语道尽天机。

大前端CPU优化技术--NEON编程优化技巧相关推荐

  1. 大前端CPU优化技术--NEON技术

    前言 在上一篇中我们讲了SIMD技术的基础和前世今生,可以结合上一篇文章一起看大前端CPU优化技术--SIMD技术.今天我们全局性地讲解下NEON技术​. 目前主流的移动设备以ARM v7和v8版本架 ...

  2. 大前端CPU优化技术--NEON指令介绍

    前言 ARM NEON 可以提升音视频,图像,计算机视觉等计算密集型程序的性能,在上一篇大前端CPU优化技术--NEON技术的介绍中,我们知道一些编译器可以将 C/C++ 代码自动转换为 NEON 指 ...

  3. 大前端CPU优化技术--NEON intrinsics进阶

    前言 今天我们继续介绍NEON intrinsics的指令知识,上篇大前端CPU优化技术--NEON intrinsics开篇中已经介绍了部分指令的作用.本篇文章除了介绍指令还会附上场景示例,方便大家 ...

  4. DL之DNN优化技术:DNN优化器的参数优化—更新参数的四种最优化方法(SGD/Momentum/AdaGrad/Adam)的案例理解、图表可视化比较

    DL之DNN优化技术:DNN优化器的参数优化-更新参数的四种最优化方法(SGD/Momentum/AdaGrad/Adam)的案例理解.图表可视化比较 目录 四种最优化方法简介 优化器案例理解 输出结 ...

  5. 浅谈大前端的代表技术及其影响,值得我们思考

    到底哪些是大前端的代表技术?从业务上来说,我认为终端 开发.网关设计.接口设计.桌面端的 工程化都可以算是大前端的业务范畴. 具体的技术,则是基于 HTML5.NodeJS 的通用技术,以及各平台的专 ...

  6. 大前端CPU优化技术--NEON自动向量化

    前言 ARM NEON技术是一种高级的单指令多数据的架构扩展的实现.它是一种64位和128位混合的SIMD技术,主要应用场景是音视频处理,图像视觉计算,信号处理应用等需要密集计算的场景. NEON技术 ...

  7. WordPress主题_大前端DUX主题7.1原版+优化-91apps.cn就要应用网

    大前端WordPress主题_DUX主题6.8原版+优化 支持专题功能.百度收录推送.人机验证,适用于垂直站点.科技博客.个人站,扁平化设计.简洁白色.超多功能配置.会员中心.直达链接.自动缩略图 D ...

  8. c语言编程优化界面_C编程优化技术

    c语言编程优化界面 As we all know that C programming is a widely used and most popular programming language a ...

  9. C/C++编译器并行优化技术:并行优化针对多核处理器和多线程环境进行优化,以提高程序的并行度

    目录标题 引言 数据并行:将数据集分割成多个子集,分配给多个线程或处理器并行处理. 延迟执行与乱序执行:对指令的执行顺序进行调整,提高指令流水线的利用率和性能. 延迟执行 乱序执行 任务并行:将程序分 ...

最新文章

  1. 魏哲巍:图神经网络的理论基础 | 青源 Talk 第 7 期
  2. w10系统老是自动息屏_大师解答win10系统无法自动关屏/待机和睡眠的恢复教程
  3. 如何正确有效表达:对不起,我们已经尽力了?
  4. 【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )
  5. 计算机辅助初中数学教学,初中数学教学论文 计算机辅助农村初中数学教学的几点想法...
  6. PIP(Python包管理工具)-Mac环境下安装
  7. 矩阵运算_如何理解矩阵对矩阵求导?
  8. 2018数学建模A题优秀论文:高温作业专用服装设计
  9. JMeter自动化测试工具超详细基础讲解(一)
  10. rpg制作大师_在线RPG大师班
  11. You-get 批量下载
  12. 新瑞鹏“狂飙”,宠物医疗是门好生意吗?
  13. 17.答题卡识别判卷
  14. Win10运行LoadRunner11录制脚本无法启动浏览器
  15. Tomcat下载安装教程
  16. os.rename和os.renames区别
  17. 已解决:error: cannot connect to daemon
  18. STM32F1系列HAL库配置系统时钟
  19. WebUploader 上传,仿淘宝宝贝发布
  20. linux修改vlan子接口mac地址,macvlan虚拟接口

热门文章

  1. windows安装hadoop教程,带截图
  2. CSS在Mac /Win上兼容显示
  3. win10 nginx部署前端项目(静态资源服务器和HTML)
  4. 人脸识别入门论文《Deep Facial Expression Recognition: A Survey》学习笔记
  5. 计算机电子科学技术产品,关于电子信息科学技术发展现状的思考
  6. 浏览器无法访问此网站,连接已被重置,无法加载
  7. 数据比赛资料(杂合)
  8. JAVA RPC(二)序列化协议杂谈
  9. 一台计算机英语美式发音,美式英语发音课程(视频+文本) 第69期:Want和Won't的发音对比...
  10. jQuery源码分析理解