前言

指令集并行是CPU的优化加速的一个方向,在ARM芯片主要是利用NEON指令集实现指令集并行

NEON简介

NEON就是高级SIMD,单指令多数据,适用于图像、音频等数据处理。ARMv6就叫SIMD,ARMv7开始叫NEON,aarch64又有点不一样,下文只针对ARMv7或者ARMv8 aarch32的NEON进行

NEON有32个64位长的寄存器(D0-D31,每个D可以装2个浮点数据),也可以看做为16个128位长的寄存器(Q0-Q15,每个Q可以装4个浮点数据),所以一句指令最多可以同时实现4个乘法操作,理论速度可以提升4倍

如何使用NEON

三种使用NEON的方法

库函数

官方给了2个库可以使用,OpenMax DL和Ne10,后者在github上有,也是我用来参考学习的主要对象

汇编函数

用汇编语句编写.s文件

在C/C++代码中嵌入汇编语句(inline assembly)

内联函数(intrinsics function)

在C代码中直接嵌入内联函数用以实现功能,但是性能会取决于编译器和具体设备

汇编函数基础

想要高效利用NEON的话,汇编是避不开的。下面是ARM汇编相关的准备知识

参考资料

汇编基础原理

b、bx、bl指令

arm汇编指令

GNU ARM Assembler Quick Reference

特殊寄存器

TODO: sb、ip是干嘛的

汇编函数文件directive(指令、伪操作)

常见directive(指令、伪操作)

参数

说明

.text

后面那些指令都属于.text段

.syntax

unified

说明下面的指令是ARM和THUMB通用格式

TODO:不太懂

.align

4

4字节对齐

.balign

4

TODO:不太懂

.global

xx_func

函数xx_func可以被外部文件调用访问

.thumb_func

指明一个函数是thumb指令集的函数

TODO:不太懂

编译调用汇编函数

编译汇编文件neon.s的命令需要加选项-mfpu=neon: arm-linux-gnueabihf-gcc -mfpu=neon -c neon.s -o neon.o

主文件main.o链接neon.o的命令: arm-linux-gnueabihf-gcc neon.o main.o -o test

相关编译参数

堆栈读取参数

TODO:汇编读取多参数

参考链接

ARM汇编基础指令

ldr

ldr R0, [R1]! @将内存地址为R1的数据加载到R0,并将R1指向下一个位置

ldr R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。

str

str R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。

b 无条件跳转

b label_fun

bl 带返回的跳转,保存当前位置到lr,用于子函数调用

bl label_fun @bx lr或者mov pc, lr实现返回

bx 跳转并切换状态,一般用于子函数返回

bx lr

bgt 比较跳转,如果经过之前某句操作后状态寄存器是大于(great than)就跳转

cmp r0, #5

bgt label_foo

and 按位与

and r3, r2, #3 @ r3 = r2 % 4

asr 右移

asr r2, r2, #2 @ r2 = r2 >> 2

cbz 比较跳转,如果为零就跳到后面的指令

cbz r3, label_foo

sub 减命令

sub r0, r1, r2 @ r0 = r1 - r2

subs 减命令,并更新状态寄存器

同sub一样,多的更新状态寄存器功能可以配合bgt

NEON矢量读取命令vld1

vld1.32 {d0}, [r1]@从内存地址r1开始读取2个32位数据到d0里,因为d能存2个32位浮点数

vld1.32 {q0}, [r1]@从内存地址r1开始读取4个32位数据到q0里,因为q能存2个32位浮点数

NEON矢量存储命令vst1

vst1.32 {d0}, [r1]@将d0里的2个32位浮点数写到内存地址r1里

vst1.32 {q0}, [r1]@将q0里的4个32位浮点数写到内存地址r1里

NEON矢量加命令vadd

图文并茂,不用多说 vadd.i16 d3, d0, d1 @ d3 = d0 + d1

NEON简单对比实验

github链接记得点赞

C语言实现 void mul_float_c(float *dst, float *src1, float *src2, int count)

{

int i = 0, j = 0;

for (j = 0; j < count; j++)

for (i = 0; i < 4; i++)

*(dst++) = *(src1++) * *(src2++);

}

汇编实现assembly .text

.syntax unified

.align 4

.global mul_float_neon

.thumb

.thumb_func

mul_float_neon:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@ r0: *dst & current dst entry's address浮点型指针,存储结果

@ r1: *src1 & current src1 entry's address浮点型指针,操作对象1

@ r2: *src2 & current src2 entry's address浮点型指针,操作对象2

@ r3: count,循环次数

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

.loop:

cbz r3, .return

subs r3, r3, #1

vld1.32 {q0}, [r1]!

vld1.32 {q1}, [r2]! @ for current set

@ calculate values for current set

vmul.f32 q3, q0, q1 @ q3 = q0 + q1

@ store the result for current set

vst1.32 {q3}, [r0]!

b .loop

.return:

mov r0, #0

bx lr

C语言内嵌汇编实现inline assembly void mul_float_neon_inline(float *dst, float *src1, float *src2, int count)

{

asm volatile(

".loop:\n"

"cbz %[count], .return\n"

"subs %[count], %[count], #1\n"

"vld1.32 {q0}, [%[src1]]!\n"

"vld1.32 {q1}, [%[src2]]! @ for current set\n"

"vmul.f32 q3, q0, q1 @ q3 = q0 + q1\n"

"vst1.32 {q3}, [%[dst]]!\n"

"b .loop\n"

".return:\n"

// "mov %[dst], #0\n"//不需要函数的返回跳转

// "bx lr\n"

: // 解释返回参数,如[ dst ] "+r"(dst),有个加号

: [ dst ] "r"(dst), [ src1 ] "r"(src1), [ src2 ] "r"(src2), [ count ] "r"(count)// 解释输入参数

: "memory", "q0", "q1", "q3");// 不太懂,但是要加

}

内联函数实现

内联函数官方在线文档 #include//要用neon内联函数必须要该头文件

void add_float_neon(float* dst, float* src1, float* src2, int count)

{

int i;

for (i = 0; i < count; i += 4)

{

float32x4_t in1, in2, out;

in1 = vld1q_f32(src1);

src1 += 4;

in2 = vld1q_f32(src2);

src2 += 4;

out = vaddq_f32(in1, in2);

vst1q_f32(dst, out);

dst +=4;

}

}

结果对比和分析 pi@raspberrypi:~/mnt/neon_test $ ./neon_test

mul_float_c used: 0.000095 s

mul_float_neon used: 0.000012 s

mul_float_neon_inline used: 0.000011 s

mul_float_neon_intrinsics used: 0.000059 s

mul_float_c and mul_float_neon result same!!!

mul_float_c and mul_float_inline result same!!!

mul_float_c and mul_float_intrinsics result same!!!

分别用C语言的for循环、neon的汇编实现、neon的内联汇编(inline assembly)、neon的内联函数(intrinsics function)这4种方式在A53上实现4*100次浮点运算,可以看出,最快的还是neon汇编实现,约10倍的速度提升,同时两种neon汇编的速度一样没啥区别,但是还是建议不用内联汇编,因为gdb没法debug,至于为什么会达到10倍的提升,一方面是neon的矢量乘法有4倍理论提升,还有就是读数据和存数据都是4倍提速。而neon的内联函数却只有不到2倍的速度提升,真辣鸡

TODO:上述实验数据是在编译优化参数为debug模式"-O0 -g"的情况下测出来的,但是release模式"-Ofast"会报错

总结

来,弄优化,学汇编,用NEON!手动狗头

neon 指令 c语言,NEON初步使用相关推荐

  1. neon 指令 c语言,Neon指令集优化快速入门教程

    Neon指令集优化快速入门教程 Neon指令集优化快速入门教程 文章目录 1. Neon是什么? 2.Neon为什么速度快 3. Neon基础概念 4. Neon的C语言接口 C语言程序中集成Neon ...

  2. NEON指令优化指南学习之一

    RM平台NEON指令的编译和优化 本文介绍了ARM平台基于ARM v7-A架构的ARM Cortex-A系列处理器(Cortex-A5, Cortex-A7,Cortex-A8, Cortex-A9, ...

  3. math-neon基于NEON指令的数学库

    这是一个开源的库,地址为https://code.google.com/p/math-neon/,根据项目介绍应该是利用neon指令实现的数学库:包括三角.对数.指数等基于浮点的运算实现,以及矩阵运算 ...

  4. 基于NEON指令的图像旋转加速【armv7】

    目录 前言 知识直通车 NEON转置指令 右旋90 4x4矩阵右旋实例 灰度图(单通道)右旋90 彩图(RGB三通道)右旋90 左旋90 4x4矩阵左旋实例 灰度图(单通道)左旋90 彩图(RGB三通 ...

  5. ARM和NEON指令 very gooooooood.............

    http://blog.csdn.net/chshplp_liaoping/article/details/12752749 在移动平台上进行一些复杂算法的开发,一般需要用到指令集来进行加速.目前在移 ...

  6. ARM和NEON指令 very nice

    在移动平台上进行一些复杂算法的开发,一般需要用到指令集来进行加速.目前在移动上使用最多的是ARM芯片. ARM是微处理器行业的一家知名企业,其芯片结构有:armv5.armv6.armv7和armv8 ...

  7. Android NDK开发之 ARM与NEON指令说明

    原文引自: http://blog.csdn.net/chshplp_liaoping/article/details/12752749 在移动平台上进行一些复杂算法的开发,一般需要用到指令集来进行加 ...

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

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

  9. ARM和NEON指令

    转载自:http://blog.csdn.net/chshplp_liaoping/article/details/12752749 在移动平台上进行一些复杂算法的开发,一般需要用到指令集来进行加速. ...

最新文章

  1. Java Web项目结构
  2. 谁登录了你的linux
  3. UA MATH563 概率论的数学基础 中心极限定理24 随机变量的特征函数
  4. ES6新特性之Promise
  5. 如何自行查询SAP Spartacus Organization Unit List的取数逻辑
  6. 2021年度训练联盟热身训练赛第一场 E Early Orders 思维 + 栈
  7. python 行为驱动_什么是行为驱动的Python?
  8. 应用安全测试的发展趋势
  9. G2 可视化引擎-统计图表
  10. caffe数据集——LMDB
  11. mysql必知必会的数据_MySQL必知必会---数据过滤
  12. ApiException
  13. Android 文字转语音之TextToSpeech
  14. starops 云效运维 文档_云效手册专有云版.pdf
  15. Kuangbin专题八生成树
  16. java 6面骰子_java 垒骰子
  17. 智能路由器OpenWrt 开发环境 及 编译分析(一)
  18. NVIDIA面经整理
  19. Android 9.0 设置讯飞语音引擎为默认tts语音播报引擎
  20. 处理器cpu测试工具

热门文章

  1. 李笑来《韭菜的自我修养》笔记
  2. python如何读取csv文件的某两行_Python 读取csv的某行
  3. 番外篇:STM32之GPIO口速率配置究竟代表什么
  4. DAY45(DAY46拓展):SOCKS 代理技术
  5. offer--刷题之路(持续更新)
  6. mysql 什么是主键_mysql – 主键应该是什么?
  7. 基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性
  8. GM、VP、FVP、CIO都是什么职位
  9. Java窗体实现飞机躲子弹游戏
  10. 浅谈BCrypt密码加解密的使用