objective-c-C与vDSP与NEON的比较 – NEON怎么能像C一样慢?
NEON怎么会像C一样慢?
我一直在尝试构建一个快速的直方图函数,通过为它们分配一个值 – 即它们最接近的范围阈值,将输入值分成范围.这是应用于图像的东西,因此它必须快速(假设图像阵列为640×480,因此300,000个元素).直方图范围数是倍数(0,25,50,75,100).输入将是浮点数,最终输出显然是整数 我通过打开一个新的空项目(没有app委托)并仅使用main.m文件在xCode上测试了以下版本.除了Accelerate之外,我删除了所有链接库. 这是C实现:如果那时旧版本很多,但这里是最终的优化逻辑.花了11秒和300毫秒. int main(int argc,char *argv[]) { NSLog(@"starting"); int sizeOfArray=300000; float* inputArray=(float*) malloc(sizeof(float)*sizeOfArray); int* outputArray=(int*) malloc(sizeof(int)*sizeOfArray); for (int i=0; i<sizeOfArray; ++i) { inputArray[i]=88.5; } //Assume range is [0,100] int lcd=25; for (int j=0; j<1000; ++j)// just to get some good time interval { for (int i=0; i<sizeOfArray; ++i) { //a 60.5 would give a 50. An 88.5 would give 100 outputArray[i]=roundf(inputArray[i]/lcd)*lcd; } } NSLog(@"done"); } 这是vDSP实现.即使有一些繁琐的浮动到整数来回,它只花了6秒!差不多50%! //vDSP implementation int main(int argc,char *argv[]) { NSLog(@"starting"); int sizeOfArray=300000; float* inputArray=(float*) malloc(sizeof(float)*sizeOfArray); float* outputArrayF=(float*) malloc(sizeof(float)*sizeOfArray);//vDSP requires matching of input output int* outputArray=(int*) malloc(sizeof(int)*sizeOfArray); //rounded value to the nearest integere float* finalOutputArrayF=(float*) malloc(sizeof(float)*sizeOfArray); int* finalOutputArray=(int*) malloc(sizeof(int)*sizeOfArray); //to compare apples to apples scenarios output for (int i=0; i<sizeOfArray; ++i) { inputArray[i]=37.0; //this will produce an final number of 25. On the other hand 37.5 would produce 50. } for (int j=0; j<1000; ++j)// just to get some good time interval { //Assume range is [0,100] float lcd=25.0f; //divide by lcd vDSP_vsdiv(inputArray,1,&lcd,outputArrayF,sizeOfArray); //Round to nearest integer vDSP_vfixr32(outputArrayF,outputArray,sizeOfArray); // MUST convert int to float (cannot just cast) then multiply by scalar - This step has the effect of rounding the number to the nearest lcd. vDSP_vflt32(outputArray,sizeOfArray); vDSP_vsmul(outputArrayF,finalOutputArrayF,sizeOfArray); vDSP_vfix32(finalOutputArrayF,finalOutputArray,sizeOfArray); } NSLog(@"done"); } 这是霓虹灯的实现.这是我的第一次好玩!它比vDSP慢,花了9秒300毫秒,对我来说没有意义. vDSP比NEON更好地优化,或者我做错了. //NEON implementation int main(int argc,char *argv[]) { NSLog(@"starting"); int sizeOfArray=300000; float* inputArray=(float*) malloc(sizeof(float)*sizeOfArray); float* finalOutputArrayF=(float*) malloc(sizeof(float)*sizeOfArray); for (int i=0; i<sizeOfArray; ++i) { inputArray[i]=37.0; //this will produce an final number of 25. On the other hand 37.5 would produce 50. } for (int j=0; j<1000; ++j)// just to get some good time interval { float32x4_t c0,c1,c2,c3; float32x4_t e0,e1,e2,e3; float32x4_t f0,f1,f2,f3; //ranges of histogram buckets float32x4_t buckets0=vdupq_n_f32(0); float32x4_t buckets1=vdupq_n_f32(25); float32x4_t buckets2=vdupq_n_f32(50); float32x4_t buckets3=vdupq_n_f32(75); float32x4_t buckets4=vdupq_n_f32(100); //midpoints of ranges float32x4_t thresholds1=vdupq_n_f32(12.5); float32x4_t thresholds2=vdupq_n_f32(37.5); float32x4_t thresholds3=vdupq_n_f32(62.5); float32x4_t thresholds4=vdupq_n_f32(87.5); for (int i=0; i<sizeOfArray;i+=16) { c0= vld1q_f32(&inputArray[i]);//load c1= vld1q_f32(&inputArray[i+4]);//load c2= vld1q_f32(&inputArray[i+8]);//load c3= vld1q_f32(&inputArray[i+12]);//load f0=buckets0; f1=buckets0; f2=buckets0; f3=buckets0; //register0 e0=vcgtq_f32(c0,thresholds1); f0=vbslq_f32(e0,buckets1,f0); e0=vcgtq_f32(c0,thresholds2); f0=vbslq_f32(e0,buckets2,thresholds3); f0=vbslq_f32(e0,buckets3,thresholds4); f0=vbslq_f32(e0,buckets4,f0); //register1 e1=vcgtq_f32(c1,thresholds1); f1=vbslq_f32(e1,f1); e1=vcgtq_f32(c1,thresholds2); f1=vbslq_f32(e1,thresholds3); f1=vbslq_f32(e1,thresholds4); f1=vbslq_f32(e1,f1); //register2 e2=vcgtq_f32(c2,thresholds1); f2=vbslq_f32(e2,f2); e2=vcgtq_f32(c2,thresholds2); f2=vbslq_f32(e2,thresholds3); f2=vbslq_f32(e2,thresholds4); f2=vbslq_f32(e2,f2); //register3 e3=vcgtq_f32(c3,thresholds1); f3=vbslq_f32(e3,f3); e3=vcgtq_f32(c3,thresholds2); f3=vbslq_f32(e3,thresholds3); f3=vbslq_f32(e3,thresholds4); f3=vbslq_f32(e3,f3); vst1q_f32(&finalOutputArrayF[i],f0); vst1q_f32(&finalOutputArrayF[i+4],f1); vst1q_f32(&finalOutputArrayF[i+8],f2); vst1q_f32(&finalOutputArrayF[i+12],f3); } } NSLog(@"done"); } PS:这是我在这个规模上的第一个基准测试,所以我试着保持简单(大循环,设置代码不变,使用NSlog打印开始/结束时间,只加速框架链接).如果这些假设中的任何一个对结果产生重大影响,请批评. 谢谢 解决方法
首先,这不是“NEON”本身.这是内在的.使用clang或gcc下的内在函数几乎不可能获得良好的NEON性能.如果您认为需要内在函数,则应手写汇编程序.
vDSP没有比NEON“更好地优化”. iOS上的vDSP使用NEON处理器. vDSP使用NEON比使用NEON要好得多. 我还没有挖掘你的内在函数代码,但最有可能(事实上几乎可以肯定)导致麻烦的是你正在创建等待状态.用汇编语言编写(和内在函数只是用焊接手套编写的汇编程序),就像用C语言编写一样.你不要循环使用它.你不比较相同.你需要一种新的思维方式.在汇编中,你可以一次做多件事(因为你有不同的逻辑单元),但是你必须以这样的方式安排事情,使所有这些东西可以并行运行.良好的装配使所有这些管道都充满了.如果您可以阅读您的代码并且它非常有意义,那么它可能是废话汇编代码.如果你从不重复自己,那可能就是废话汇编代码.在您被允许阅读之前,您需要仔细考虑进入哪个寄存器以及有多少个周期. 如果它像音译C一样简单,那么编译器会为你做到这一点.你说“我要在NEON中写这个”的那一刻你会说“我认为我可以编写比编译器更好的NEON”,因为编译器也使用它.也就是说,通常可以编写比编译器更好的NEON(特别是gcc和clang). 如果你已经准备好潜入这个世界(这是一个非常酷的世界),你就会有一些阅读.这是我推荐的一些地方: > http://www.coranac.com/tonc/text/asm.htm(你真的想花一些时间用这个) >针对您的具体问题,他在此解释:http://hilbert-space.de/?p=22 >关于你的具体问题还有一些问题:Arm Neon Intrinsics vs hand assembly > http://robnapier.net/blog/fast-bezier-intro-701 所有这一切…总是始终重新考虑您的算法.通常答案不是如何快速计算循环,而是如何不经常调用循环. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Swift对象实例方法名混淆的解决
- 我不明白这个短语是如何用c#计算的
- 使用AXMLPrinter2.jar+BAT批处理文件批量反编译XML
- sqlite3 常用命令与 SQL 基本语句
- xml – 需要JSON字段和JAXB
- c# – 获取用户默认浏览器的UserAgent
- VB.NET vs. C#, round 2: Pounding on performance--VB.NET
- Flex及AS3的百多条小知识(2)
- Cocos2d-x 2.x android 集成admob广告(三)banner+inters
- ruby-on-rails – Google Maps for Rails – 使用AJAX更新标