ARM NEON编程系列1-导论
ARM NEON 编程系列1 - 导论
前言
本系列博文用于介绍ARM CPU下NEON指令优化。
NEON历史
ARM处理器的历史可以阅读文献[2],本文假设读者已有基本的ARM CPU下编程的经验,本文面向需要了解ARM平台下通过NEON进行算法优化的场景。
ARM CPU最开始只有普通的寄存器,可以进行基本数据类型的基本运算。自ARMv5开始引入了VFP(Vector Floating Point)指令,该指令用于向量化加速浮点运算。自ARMv7开始正式引入NEON指令,NEON性能远超VFP,因此VFP指令被废弃。
NEON用途
类似于Intel CPU下的MMX/SSE/AVX/FMA指令,ARM CPU的NEON指令同样是通过向量化计算来进行速度优化,通常应用于图像处理、音视频处理等等需要大量计算的场景。
Hello world
下面给一个最基本的例子来说明NEON的作用:
注意:
- 代码采用C++11编写,后续博客代码均以C++11编写,不再重述)
- 此系列博客采用neon2sse.h将NEON指令翻译成SSE指令以使得代码可以在x86/x64 CPU上运行。本文所有代码均在windows vs2013以及android-ndk-r11c下编译测试通过。
完整代码地址:基本NEON优化示例代码
//填充随机数
static void fill_random_value(std::vector<float>& vec_data)
{
std::uniform_real_distribution<float> distribution(
std::numeric_limits<float>::min(),
std::numeric_limits<float>::max());
std::default_random_engine generator;
std::generate(vec_data.begin(), vec_data.end(), [&]() { return distribution(generator); });
}
//判断两个vector是否相等
static bool is_equals_vector(const std::vector<float>& vec_a,
const std::vector<float>& vec_b)
{
if (vec_a.size() != vec_b.size())
{
return false;
}
for (size_t i = 0; i < vec_a.size(); i++)
{
if (vec_a[i] != vec_b[i])
{
return false;
}
}
return true;
}
//正常的vector相乘 (注意:需要关闭编译器的自动向量化优化)
static void normal_vector_mul(const std::vector<float>& vec_a,
const std::vector<float>& vec_b,
std::vector<float>& vec_result)
{
assert(vec_a.size() == vec_b.size());
assert(vec_a.size() == vec_result.size());
//compiler may optimized auto tree vectorize (test this diabled -ftree-vectorize)
for (size_t i = 0; i < vec_result.size();i++)
{
vec_result[i] = vec_a[i] * vec_b[i];
}
}
//NRON优化的vector相乘
static void neon_vector_mul(const std::vector<float>& vec_a,
const std::vector<float>& vec_b,
std::vector<float>& vec_result)
{
assert(vec_a.size() == vec_b.size());
assert(vec_a.size() == vec_result.size());
int i = 0;
//neon process
for (; i < (int)vec_result.size() - 3 ; i+=4)
{
const auto data_a = vld1q_f32(&vec_a[i]);
const auto data_b = vld1q_f32(&vec_b[i]);
float* dst_ptr = &vec_result[i];
const auto data_res = vmulq_f32(data_a, data_b);
vst1q_f32(dst_ptr, data_res);
}
//normal process
for (; i < (int)vec_result.size(); i++)
{
vec_result[i] = vec_a[i] * vec_b[i];
}
}
//测试函数
//FuncCostTimeHelper是一个计算时间消耗的helper类
static int test_neon()
{
const int test_round = 1000;
const int data_len = 10000;
std::vector<float> vec_a(data_len);
std::vector<float> vec_b(data_len);
std::vector<float> vec_result(data_len);
std::vector<float> vec_result2(data_len);
//fill random value in vecA & vecB
fill_random_value(vec_a);
fill_random_value(vec_b);
//check the result is same
{
normal_vector_mul(vec_a, vec_b, vec_result);
neon_vector_mul(vec_a, vec_b, vec_result2);
if (!is_equals_vector(vec_result,vec_result2))
{
std::cerr << "result vector is not equals!" << std::endl;
return -1;
}
}
//test normal_vector_mul
{
FuncCostTimeHelper time_helper("normal_vector_mul");
for (int i = 0; i < test_round;i++)
{
normal_vector_mul(vec_a, vec_b, vec_result);
}
}
//test neon_vector_mul
{
FuncCostTimeHelper time_helper("neon_vector_mul");
for (int i = 0; i < test_round; i++)
{
neon_vector_mul(vec_a, vec_b, vec_result2);
}
}
return 0;
}
int main(int, char*[])
{
return test_neon();
}
说明:
- 这段代码在关闭编译器的自动向量化优化之后,neon_vector_mul大约比normal_vector_mul速度快3倍左右。
- 这段代码中使用了3条NEON指令:vld1q_f32,vmulq_f32,vst1q_f32。具体指令的作用会在后续博文中说明。
- 此处仅作演示。
参考
欢迎关注公众号,不定期推送技术以及感想。
ARM NEON编程系列1-导论的更多相关文章
- ARM NEON 编程系列2 - 基本指令集
ARM NEON 编程系列2 - 基本指令集 前言 本系列博文用于介绍ARM CPU下NEON指令优化. 博文github地址:github 相关代码github地址:github NEON指令集 主 ...
- ARM裸编程系列---UART
S5PV210 UART说明 通用异步收发器缩写UART,这是UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTER.它被用来传送串行数据.当发送数据,CPU将 ...
- ARM NEON指令集优化理论与实践
ARM NEON指令集优化理论与实践 一.简介 NEON就是一种基于SIMD思想的ARM技术,相比于ARMv6或之前的架构,NEON结合了64-bit和128-bit的SIMD指令集,提供128-bi ...
- ARM的体系结构与编程系列博客——ARM处理器系列介绍
ARM处理器系列介绍 现在到了3月,过年过得过于舒服了.系列博客也停更了近半月,我果然是个慢(lan)性(gui)子,那么趁着到校的第一天晚上,就写一篇博客来继续我的系列博客了!众所周知,ARM处理器 ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- 猫哥网络编程系列:HTTP PEM 万能调试法
注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
- 猫哥网络编程系列:详解 BAT 面试题
从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...
- 【linux草鞋应用编程系列】_6_ 重定向和VT100编程
一.文件重定向 我们知道在linux shell 编程的时候,可以使用文件重定向功能,如下所示: [root@localhost pipe]# echo "hello world&q ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
随机推荐
- Mac下的利器们介绍
先说说一些快捷键吧,从windows下过来还不很习惯: ctrl + 开关 关机等提示 ctrl+shift+开关 关闭显示器 cmd+option+v 相当于剪贴 cmd+tab,对于最小化了的窗口 ...
- <老友记>学习笔记
这是六个人的故事,从不服输而又有强烈控制欲的monica,未经世事的千金大小姐rachel,正直又专情的ross,幽默风趣的chandle,古怪迷人的phoebe,花心天真的joey——六个好友之间的 ...
- Qt GUI@学习日志
day 1: Qt中类: 理解一个类最好还是从其类代码实现上看. 由此图可看出需要好好研究那几个重要的类:Qt/QEvent/QObject/QWidget/. QApplication: (比较复杂 ...
- 如果将彩色图像和灰度图像一起放进 CNN 中去,会是什么结果?
如果将彩色图像和灰度图像一起放进 CNN 中去,会是什么结果? 今天,坑爹的实验,我处理 SUN397 的时候,忘记去掉灰度图了,结果,利用微调后的 model 提取 feature,悲剧的发现,无论 ...
- linux下shell显示-bash-4.1#不显示路径解决方法
在linux shell中不显示路径了,显示为-bash-4.1#用起来很不方便. 如何改为显示路径的shell呢? 步骤如下: vim ~/.bash_profile (不用管.bash_profi ...
- C#→关于System.Data.Linq下的Table<TEntity> 泛型类 的问题
Table<TEntity>表示表格记录,它是一个泛型集合类,它的元素就是表格实体对象.它提供一组方法,对元素进行添加删除操作,并可以通过DataContext将这些操作保存到数据库. 表 ...
- jquery 使用attr() 函数对复选框无效的原因,javascript那些事儿——properties和attributes
复选框是网站开发的时候经常用到的网页标签之一,常见的在页面上对复选框的操作包括取值和修改复选框的状态.在jquery中,常见的操作标签的值得函数为attr,然而在操作复选框的时候,通常采用的却是pro ...
- jQuery 核心 - noConflict() 方法,jQuery 文档操作 - detach() 方法
原文地址:http://www.w3school.com.cn/jquery/manipulation_detach.asp 实例 使用 noConflict() 方法为 jQuery 变量规定新 ...
- Suricata+Barnyard2+Base的IDS前端Snorby
搭建基于Suricata+Barnyard2+Base的IDS前端Snorby 4.Barnyard2:http://www.securixlive.com/barnyard2/download.ph ...
- ntko office 5.0.1.0注册码
如何手工卸载和安装NTKOOFFICE文档控件?(NTKOOFFICE文档控件) 1.何时进行手工卸载和安装; 一般情况下应该让客户端自动控件,这样当服务器控件版本更新时,客户端可以获得自动升级方面的 ...