历史上的今天
今天是:2025年01月13日(星期一)
2020年01月13日 | ARM NEON 编程系列1 - 导论
2020-01-13 来源:eefocus
前言
本系列博文用于介绍ARM CPU下NEON指令优化。
博文github地址:github
相关代码github地址:github
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 { std::uniform_real_distribution std::numeric_limits std::numeric_limits 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 const std::vector { 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 const std::vector std::vector { 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 const std::vector std::vector { 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 std::vector std::vector std::vector //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。具体指令的作用会在后续博文中说明。
史海拾趣
|
监控技术从上个世纪80年代进入我国以来,随着安防需求的急剧增加一直在飞速发展,从技术层面上来看,已经经历了多个不同的发展阶段。随着计算机技术的发展和网络的普及,目前,视频监控已经发展到了网络多媒体监控系统。 新一 ...… 查看全部问答> |
|
我的平台:CE5.0 + S3C2442;准备学习USB驱动的开发,但是感觉USB驱动比较复杂,理解比较困难,所以我就偷懒的想请各位有经验的同志能帮忙给分析一下USB驱动的架构,什么HOST(function、clients)、Device(function、clients);OHCI、USBD、HCD等等, ...… 查看全部问答> |
|
ZIGBEEzigbee模块MC13213 38元一个了 超值呀,芯片市场价都要20元了真是亏本卖了http://item.taobao.com/item.htm?id=8233075094… 查看全部问答> |
|
在F107上,个人打算使用OTG下host模式完成U盘的读写操作 目前有几个问题想请教大家: 1. STM32仅仅提供了OTG操作的库函数,关于OTG的上层协议没有任何的涉及对吧?提供的demo还是bin格式的; 2. 如果我打算完成host通信,是否存在两条路: ...… 查看全部问答> |
|
DIY步进电机的初步任务规划 将任务划分为如下部分,每个部分如下: 1.电源部分把我们用的市电~220V变为LM3S811所需要的电压和步进电机所欲要的电压,这个模块要求不高可以一个人完成。 2.按键和显示部分难度也不大,显示可 ...… 查看全部问答> |




