由于一些开销,将 OpenCL 与 Android JNI 一起使用会产生缓慢的代码
Using OpenCL with Android JNI produces slow code due to some overhead
我使用 OpenCL 和 OpenMP 在 android 上实现了一个算法。 OpenMP 实现 运行 比 OpenCL 慢大约 10 倍。
- OpenMP:~250 毫秒
- OpenCL:~25 毫秒
但总的来说,如果我从 java android 端测量时间,我得到大致相同的时间来调用和获取我的值。
例如:
Java代码:
// calls C implementation using JNI (Java Native Interface)
bool useOpenCL = true;
myFunction(bitmap, useOpenCL); // ~300 ms, timed with System.nanoTime() here, but omitted code for clarity
myFunction(bitmap, !useOpenCL); // ~300 ms, timed with System.nanoTime() here, but omitted code for clarity
C代码:
JNIEXPORT void JNICALL Java_com_xxxxx_myFunctionNative(JNIEnv * env, jobject obj, jobject pBitmap, jboolean useOpenCL)
{
// same before, setting some variables
clock_t startTimer, stopTimer;
startTimer = clock();
if ((bool) useOpenCL) {
calculateUsingOpenCL(); // runs in ~25 ms, timed here, using clock()
}
else {
calculateUsingOpenMP(); // runs in ~250 ms
}
stopTimer = clock();
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Time in ms: %f\n", 1000.0f* (float)(stopTimer - startTimer) / (float)CLOCKS_PER_SEC);
// same from here on, e.g.: copying values to java side
}
Java 代码在两种情况下大致同时执行,大约 300 毫秒。更准确地说,elapsedTime
对于 OpenCL 来说有点多,也就是说 OpenCL 平均速度较慢。
查看单个 运行 次的 OpenMP 和 OpenCL 实现,OpenCL 版本总体上应该快得多。但是由于某种原因,有一个开销我找不到。
我还比较了 OpenCL 与普通本机代码(无 OpenMP),我仍然得到了相同的结果,整体 运行 时间大致相同,即使 calculateUsingOpenCL
运行 在至少快 10 倍。
想法:
也许 GPU(在 OpenCL 的情况下)通常效率较低,因为它的可用内存较少。我们需要预分配的变量很少,每帧都会使用这些变量。因此,我们检查了 android 在两种情况下(OpenMP、OpenCL)绘制位图所花费的时间。在 OpenCL 的情况下,有时绘制位图会花费更长的时间(长 3 倍),但所花的时间不足以使程序的总体 运行 时间相等。
JNI 是否使用 GPU 来加速某些调用,这可能会导致 OpenCL 版本变慢?
编辑:
- 有没有可能Java垃圾回收是由OpenCL触发的,导致开销大?
事实证明,clock() 是不可靠的(在 Android 上),因此我们改用以下方法来测量时间。用这个方法就ok了
int64_t getTimeNsec() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
}
clock_t startTimer, stopTimer;
startTimer = getTimeNsec();
function_to_measure();
stopTimer = getTimeNsec();
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Runtime in milliseconds (ms): %f", (float)(stopTimer - startTimer) / 1000000.0f);
此处建议:
How to obtain computation time in NDK
我使用 OpenCL 和 OpenMP 在 android 上实现了一个算法。 OpenMP 实现 运行 比 OpenCL 慢大约 10 倍。
- OpenMP:~250 毫秒
- OpenCL:~25 毫秒
但总的来说,如果我从 java android 端测量时间,我得到大致相同的时间来调用和获取我的值。
例如:
Java代码:
// calls C implementation using JNI (Java Native Interface) bool useOpenCL = true; myFunction(bitmap, useOpenCL); // ~300 ms, timed with System.nanoTime() here, but omitted code for clarity myFunction(bitmap, !useOpenCL); // ~300 ms, timed with System.nanoTime() here, but omitted code for clarity
C代码:
JNIEXPORT void JNICALL Java_com_xxxxx_myFunctionNative(JNIEnv * env, jobject obj, jobject pBitmap, jboolean useOpenCL) { // same before, setting some variables clock_t startTimer, stopTimer; startTimer = clock(); if ((bool) useOpenCL) { calculateUsingOpenCL(); // runs in ~25 ms, timed here, using clock() } else { calculateUsingOpenMP(); // runs in ~250 ms } stopTimer = clock(); __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Time in ms: %f\n", 1000.0f* (float)(stopTimer - startTimer) / (float)CLOCKS_PER_SEC); // same from here on, e.g.: copying values to java side }
Java 代码在两种情况下大致同时执行,大约 300 毫秒。更准确地说,elapsedTime
对于 OpenCL 来说有点多,也就是说 OpenCL 平均速度较慢。
查看单个 运行 次的 OpenMP 和 OpenCL 实现,OpenCL 版本总体上应该快得多。但是由于某种原因,有一个开销我找不到。
我还比较了 OpenCL 与普通本机代码(无 OpenMP),我仍然得到了相同的结果,整体 运行 时间大致相同,即使 calculateUsingOpenCL
运行 在至少快 10 倍。
想法:
也许 GPU(在 OpenCL 的情况下)通常效率较低,因为它的可用内存较少。我们需要预分配的变量很少,每帧都会使用这些变量。因此,我们检查了 android 在两种情况下(OpenMP、OpenCL)绘制位图所花费的时间。在 OpenCL 的情况下,有时绘制位图会花费更长的时间(长 3 倍),但所花的时间不足以使程序的总体 运行 时间相等。
JNI 是否使用 GPU 来加速某些调用,这可能会导致 OpenCL 版本变慢?
编辑:
- 有没有可能Java垃圾回收是由OpenCL触发的,导致开销大?
事实证明,clock() 是不可靠的(在 Android 上),因此我们改用以下方法来测量时间。用这个方法就ok了
int64_t getTimeNsec() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
}
clock_t startTimer, stopTimer;
startTimer = getTimeNsec();
function_to_measure();
stopTimer = getTimeNsec();
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Runtime in milliseconds (ms): %f", (float)(stopTimer - startTimer) / 1000000.0f);
此处建议: How to obtain computation time in NDK