我刚刚开始与NDK一起玩,以探索我所承诺的出色的性能提升。为了感觉到两者之间的区别,我尝试了一个愚蠢的数字处理任务(将Mandelbrot设置为位图),并将其与相同代码的Java版本进行了比较。令我大吃一惊的是,C版本的速度要慢得多(平均为5.0秒,而HTC One为1.6秒)。甚至更陌生,花费也不是因为进行本地呼叫的开销,而是实际的数字处理需要更长的时间。
这是不对的,可以吗?我错过了什么?
C版本(已删除调试计时器代码):
const int MAX_ITER = 63;
const float MAX_DEPTH = 16;
static uint16_t rgb565(int red, int green, int blue)
{
return (uint16_t)(((red << 8) & 0xf800) | ((green << 2) & 0x03e0) | ((blue >> 3) & 0x001f));
}
float zAbs(float re, float im) {
return re*re + im*im;
}
int depth(float cRe, float cIm) {
int i=0;
float re, im;
float zRe = 0.0f;
float zIm = 0.0f;
while ((zAbs(zRe, zIm) < MAX_DEPTH) && (i < MAX_ITER)) {
re = zRe * zRe - zIm * zIm + cRe;
im = 2.0f * zRe * zIm + cIm;
zRe = re;
zIm = im;
i++;
}
return i;
}
extern "C"
void Java_com_example_ndktest_MainActivity_renderFractal(JNIEnv* env, jobject thiz, jobject bitmap, float re0, float im0, float b)
{
AndroidBitmapInfo info;
void* pixels;
int ret;
long t0 = currentTimeInMilliseconds();
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
LOGE("Bitmap format is not RGB_565 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
int w = info.width;
int h = info.height;
float re, im;
int z = 0;
uint16_t* px = (uint16_t*)pixels;
for(int y=0; y<h; y++) {
im = im0 + b*((float)y/(float)h);
for(int x=0; x<info.width; x++) {
re = re0 + b*((float)x/(float)w);
z = depth(re, im);
px[y*w + x] = rgb565(0, z*4, z * 16);
}
}
AndroidBitmap_unlockPixels(env, bitmap);
}
Java版本:
private static final int MAX_ITER = 63;
private static final float MAX_DEPTH = 16;
static int rgb565(int red, int green, int blue)
{
return ((red << 8) & 0xf800) | ((green << 2) & 0x03e0) | ((blue >> 3) & 0x001f);
}
static float zAbs(float re, float im) {
return re*re + im*im;
}
static int depth(float cRe, float cIm) {
int i=0;
float re, im;
float zRe = 0.0f;
float zIm = 0.0f;
while ((zAbs(zRe, zIm) < MAX_DEPTH) && (i < MAX_ITER)) {
re = zRe * zRe - zIm * zIm + cRe;
im = 2.0f * zRe * zIm + cIm;
zRe = re;
zIm = im;
i++;
}
return i;
}
static void renderFractal(Bitmap bitmap, float re0, float im0, float b)
{
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pixels = new int[w * h];
bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
float re, im;
int z = 0;
for(int y=0; y<h; y++) {
im = im0 + b*((float)y/(float)h);
for(int x=0; x<w; x++) {
re = re0 + b*((float)x/(float)w);
z = depth(re, im);
pixels[y*w + x] = rgb565(0, z*4, z * 16);
}
}
bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
}
最佳答案
如评论中所述,这是因为NDK代码是为armeabi目标而不是armeabi-v7a目标构建的。前者旨在用于广泛的硬件,包括不带浮点硬件的设备,因此它可以在软件中进行所有浮点计算。
为armeabi-v7a构建可启用VFP指令,因此任何严重依赖浮点计算的事物都将大大加快速度。
如果您是专门为armeabi-v7a打造的,则将排除相当广泛的设备选择,即使是相对较新的设备(例如Samsung Galaxy Ace)。这些设备具有VFP支持,但是CPU基于ARMv6指令集而不是ARMv7。没有“带VFP的ARMv7之前的CPU”构建目标,因此您必须针对armeabi进行构建,或者使用自定义构建规则并仔细选择支持的设备。
另一方面,通过在armeabi-v7a库中指定硬浮动ABI(-mhard-float
–需要NDK r9b),可能会提高性能。
FWIW是即时编译器(例如Dalvik中的即时编译器)的卖点之一,就是它们可以识别系统功能并适当地调整代码生成。
关于android - NDK性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19981969/