在以下SO问题中:https: //stackoverflow.com/questions/2067955/fast-bitmap-blur-for-android-sdk @zeh声称Java模糊算法的端口到C的运行速度提高了40倍。
鉴于大部分代码仅包含计算,并且所有分配仅在实际算法编号处理之前“一次”完成-谁能解释为什么此代码运行速度快40倍?Dalvik JIT是否应该翻译字节码并大大减少与本机编译码速度的差距?
注意:我还没有确定x40的性能会自己提高,但是我在Android平台上遇到的所有严肃的图像处理算法都使用了NDK-因此,这支持了NDK代码运行得更快的观点。
对于对数据数组进行操作的算法,有两件事会极大地改变Java和C之类的语言之间的性能:
数组边界检查-Java将检查每个访问bmap [i],并确认i在数组边界之内。如果代码试图越界访问,您将得到一个有用的异常。C&C ++不会检查任何内容,只是信任您的代码。对越界访问的最佳响应是页面错误。更可能的结果是“意外行为”。
指针-您可以使用指针显着减少操作。
举一个普通的滤镜(类似于模糊,但是是一维)的无辜示例:
for(i=0; i<ndata-ncoef; ++i) {
z[i] = 0;
for(k=0; k<ncoef; ++k) {
z[i] += c[k] * d[i+k];
}
}
当您访问数组元素时,coef [k]为:
可以改善这些数组访问中的每一个,因为您知道索引是顺序的。编译器或JIT都无法知道索引是顺序的,因此无法完全优化(尽管它们一直在尝试)。
在C ++中,您将编写如下代码:
int d[10000];
int z[10000];
int coef[10];
int* zptr;
int* dptr;
int* cptr;
dptr = &(d[0]); // Just being overly explicit here, more likely you would dptr = d;
zptr = &(z[0]); // or zptr = z;
for(i=0; i<(ndata-ncoef); ++i) {
*zptr = 0;
*cptr = coef;
*dptr = d + i;
for(k=0; k<ncoef; ++k) {
*zptr += *cptr * *dptr;
cptr++;
dptr++;
}
zptr++;
}
当您第一次执行此类操作(并成功将其正确设置)时,您会惊讶地发现它的速度有多快。取索引并将索引与基地址相加的所有数组地址计算都将由增量指令代替。
对于诸如图像模糊之类的2D阵列操作,无害代码data [r,c]涉及两个值提取,一个乘法和一个和。因此,对于2D数组,指针的好处是可以删除乘法运算。
因此,该语言可以真正减少CPU必须执行的操作。代价是C ++代码难以阅读和调试。指针错误和缓冲区溢出是黑客的食粮。但是当涉及到原始数字磨削算法时,速度的提高很容易被忽略。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句