Improving time-critical code performance with JNI

Analysis of usage of JNI for mobile devices with OS android is provided. JNI-workflow is explored including usage of code examples which realizes Java calls C and C++ parts of programs. Improving of performance due to replacing time-critical parts of code with JNI analogs is shown. Наведено аналіз в...

Ausführliche Beschreibung

Gespeichert in:
Bibliographische Detailangaben
Veröffentlicht in:Математичні машини і системи
Datum:2016
Hauptverfasser: Kazymyr, V. V., Karpachev, I. I.
Format: Artikel
Sprache:English
Veröffentlicht: Інститут проблем математичних машин і систем НАН України 2016
Schlagworte:
Online Zugang:https://nasplib.isofts.kiev.ua/handle/123456789/113588
Tags: Tag hinzufügen
Keine Tags, Fügen Sie den ersten Tag hinzu!
Назва журналу:Digital Library of Periodicals of National Academy of Sciences of Ukraine
Zitieren:Improving time-critical code performance with JNI / V.V. Kazymyr, I.I. Karpachev // Математичні машини і системи. — 2016. — № 2. — С. 72-77. — Бібліогр.: 4 назв. — англ.

Institution

Digital Library of Periodicals of National Academy of Sciences of Ukraine
id nasplib_isofts_kiev_ua-123456789-113588
record_format dspace
spelling Kazymyr, V. V.
Karpachev, I. I.
2017-02-10T17:29:34Z
2017-02-10T17:29:34Z
2016
Improving time-critical code performance with JNI / V.V. Kazymyr, I.I. Karpachev // Математичні машини і системи. — 2016. — № 2. — С. 72-77. — Бібліогр.: 4 назв. — англ.
1028-9763
https://nasplib.isofts.kiev.ua/handle/123456789/113588
004.03
Analysis of usage of JNI for mobile devices with OS android is provided. JNI-workflow is explored including usage of code examples which realizes Java calls C and C++ parts of programs. Improving of performance due to replacing time-critical parts of code with JNI analogs is shown.
Наведено аналіз використання JNI для мобільних пристроїв з ОС Android. Дослідження JNI-процесу проведено з наданням прикладів коду, що реалізує Java-виклики С і C ++ частин програм. Показано підвищення продуктивності за рахунок заміни критичних частин коду JNI аналогами.
Приведен анализ использования JNI для мобильных устройств с ОС Android. Исследование JNI-процесса проведено с предоставлением примеров кода, реализующего Java-вызовы С и C ++ частей программ. Показано повышение производительности за счет замены критических частей кода JNI аналогами.
en
Інститут проблем математичних машин і систем НАН України
Математичні машини і системи
Інформаційні і телекомунікаційні технології
Improving time-critical code performance with JNI
Покращення критичних частин програми за допомогою JNI
Улучшение критических участков программы с помощью JNI
Article
published earlier
institution Digital Library of Periodicals of National Academy of Sciences of Ukraine
collection DSpace DC
title Improving time-critical code performance with JNI
spellingShingle Improving time-critical code performance with JNI
Kazymyr, V. V.
Karpachev, I. I.
Інформаційні і телекомунікаційні технології
title_short Improving time-critical code performance with JNI
title_full Improving time-critical code performance with JNI
title_fullStr Improving time-critical code performance with JNI
title_full_unstemmed Improving time-critical code performance with JNI
title_sort improving time-critical code performance with jni
author Kazymyr, V. V.
Karpachev, I. I.
author_facet Kazymyr, V. V.
Karpachev, I. I.
topic Інформаційні і телекомунікаційні технології
topic_facet Інформаційні і телекомунікаційні технології
publishDate 2016
language English
container_title Математичні машини і системи
publisher Інститут проблем математичних машин і систем НАН України
format Article
title_alt Покращення критичних частин програми за допомогою JNI
Улучшение критических участков программы с помощью JNI
description Analysis of usage of JNI for mobile devices with OS android is provided. JNI-workflow is explored including usage of code examples which realizes Java calls C and C++ parts of programs. Improving of performance due to replacing time-critical parts of code with JNI analogs is shown. Наведено аналіз використання JNI для мобільних пристроїв з ОС Android. Дослідження JNI-процесу проведено з наданням прикладів коду, що реалізує Java-виклики С і C ++ частин програм. Показано підвищення продуктивності за рахунок заміни критичних частин коду JNI аналогами. Приведен анализ использования JNI для мобильных устройств с ОС Android. Исследование JNI-процесса проведено с предоставлением примеров кода, реализующего Java-вызовы С и C ++ частей программ. Показано повышение производительности за счет замены критических частей кода JNI аналогами.
issn 1028-9763
url https://nasplib.isofts.kiev.ua/handle/123456789/113588
citation_txt Improving time-critical code performance with JNI / V.V. Kazymyr, I.I. Karpachev // Математичні машини і системи. — 2016. — № 2. — С. 72-77. — Бібліогр.: 4 назв. — англ.
work_keys_str_mv AT kazymyrvv improvingtimecriticalcodeperformancewithjni
AT karpachevii improvingtimecriticalcodeperformancewithjni
AT kazymyrvv pokraŝennâkritičnihčastinprogramizadopomogoûjni
AT karpachevii pokraŝennâkritičnihčastinprogramizadopomogoûjni
AT kazymyrvv ulučšeniekritičeskihučastkovprogrammyspomoŝʹûjni
AT karpachevii ulučšeniekritičeskihučastkovprogrammyspomoŝʹûjni
first_indexed 2025-11-26T00:10:44Z
last_indexed 2025-11-26T00:10:44Z
_version_ 1850595628669730816
fulltext 72 © Kazymyr V.V., Karpachev I.I., 2016 ISSN 1028-9763. Математичні машини і системи, 2016, № 2 НОВІ ІНФОРМАЦІЙНІ І ТЕЛЕКОМУНІКАЦІЙНІ ТЕХНОЛОГІЇ UDC 004.03 V.V. KAZYMYR * , I.I. KARPACHEV * IMPROVING TIME-CRITICAL CODE PERFORMANCE WITH JNI * Chernihiv National University of Technology, Chernihiv, Ukraine Анотація. Наведено аналіз використання JNI для мобільних пристроїв з ОС Android. Дослідження JNI-процесу проведено з наданням прикладів коду, що реалізує Java-виклики С і C ++ частин про- грам. Показано підвищення продуктивності за рахунок заміни критичних частин коду JNI анало- гами. Ключові слова: JNI, мобільний пристрій, критичний по часу виконання код, продуктивність коду. Аннотация. Приведен анализ использования JNI для мобильных устройств с ОС Android. Исследо- вание JNI-процесса проведено с предоставлением примеров кода, реализующего Java-вызовы С и C ++ частей программ. Показано повышение производительности за счет замены критических ча- стей кода JNI аналогами. Ключевые слова: JNI, мобильное устройство, критический по времени код, продуктивность кода. Abstract. Analysis of usage of JNI for mobile devices with OS android is provided. JNI-workflow is ex- plored including usage of code examples which realizes Java calls C and C++ parts of programs. Improv- ing of performance due to replacing time-critical parts of code with JNI analogs is shown. Keywords: JNI, mobile device, time-critical code, code-performance. 1. Introduction One of Java's greatest advantages is that its design allows for cross-platform capability. This fea- ture, however, is also a bug with regard to other aspects of programming. It is constrained in its interaction with the local machine, and thus the local machine instructions cannot be utilized to achieve the full performance potential of the machine. To ameliorate this weakness, there is the Java Native Interface, a Java platform that interacts with the machine on the local level. It can be employed to allow the use of legacy code and more interaction with the hardware for efficient performance. This article explores the JNI workflow, provides code examples of how Java calls in both C and C++, and introduces the Android Native Development Kit (NDK), which compiles the C/C++ code into applications that can run on an Android device. 2. JNI overview The Java Native Interface (JNI) is the native programming interface for Java that is part of the JDK. By writing programs using the JNI, developer ensures that the code is completely portable across all platforms. The JNI allows Java code that runs within a Java Virtual Machine (VM) to operate with applications and libraries written in other languages, such as C, C++, and assembly. JNI is used to write native methods to handle those situations when an application cannot be written entirely in the Java programming language. For example, developer may need to use native methods and the JNI in the following situations [1]: 1. The standard Java class library may not support the platform-dependent features needed by the application. 2. An existing library or application written in another programming language may be al- ready available and developer wishes to make it accessible to Java applications. ISSN 1028-9763. Математичні машини і системи, 2016, № 2 73 Fig. 1. JNI Architecture 3. Developer may want to implement a small portion of time-critical code in a lower- level programming language, such as assembly, and then having Java application call these functions. Programming through the JNI framework lets developer to use native methods to do many operations. Native methods may represent legacy applications or they may be written explicitly to solve a problem that is best handled outside of the Java programming environment. The JNI framework lets native methods utilize Java objects in the same way that Java code uses these objects. A native method can create Java objects, including arrays and strings, and then inspect and use these objects to perform its tasks. A native method can also inspect and use ob- jects created by Java application code. A native method can even update Java objects that it creat- ed or that were passed to it, and these updated objects are available to the Java application. Thus, both the native language side and the Java side of an application can create, update, and access Java objects and then share these objects between them. Native methods can also easily call Java methods. Often, developer will already have an implemented library of Java methods. The native method does not need to repeat functionality already incorporated in existing Java methods. The native method, using the JNI framework, can call the existing Java method, pass it the required parameters, and get the results back when the method completes. The JNI enables the advantages of the Java programming language from the native meth- ods. In particular, developer can catch and throw exceptions from the native method and have these exceptions handled in the Java application. Native methods can also get information about Java classes. By calling special JNI functions, native methods can load Java classes and obtain class information. Finally, native methods can use the JNI to perform runtime type checking. It is easy to see that the JNI serves as the glue between Java and native applications. The figure 1 shows how the JNI ties the C side of an application to the Java side. 3. Boosting performance with JNI Mobile JNI or Java Native Interface is the interface between the Java code run- ning in a JVM and the native code run- ning outside the JVM. It works both ways that is developer can use JNI to call native code from Java programs and to call Java code from the native code. The native code normally resides within a library (.so file) and is typically written in C/C++ [2]. The main reason to use JNI in a Java program is to bypass performance bottlenecks – execute heavy number crunching in native code and get rid of the overhead that the instruction interpretation in the JVM introduces. On Android, in order to prevent fragmentation, developers are only allowed to use the fol- lowing libraries in the native code: – libc (C library) headers; – libm (math library) headers; – JNI interface headers; – libz (Zlib compression) headers; – liblog (Android logging) header; – OpenGL ES 1.1 (3D graphics library) headers (since 1.6); 74 ISSN 1028-9763. Математичні машини і системи, 2016, № 2 – A Minimal set of headers for C++ support. The following example demonstrates how to transform a time consuming Java method with a lot of number crunching into a native declared method where the real work is performed in native code. Here is the time consuming Java method: public double compare(int[] sourceData,int[] targetData, double tar- getError) { double error = 0.0D; for (int index = 0; index < targetData.length; index++) { int c1 = sourceData[index]; int c2 = targetData[index]; int b = (c1 >> 16 & 255) - (c2 >> 16 & 255); int g = (c1 >> 8 & 255) - (c2 >> 8 & 255); int r = (c1 & 255) - (c2 & 255); error += r * r + g * g + b * b; if (error > targetError) return error; } return error; } The sourceData and targetData arguments represent the pixels of two Bitmaps. In short the method calculates the sum of the square distance in color between two images, pixel by pixel. If compare two 200×200 pixels images the for-loop will run 40000 times. This is a typical candidate for when to use JNI. This is what the function will look like when written in C: static jdouble compareNative(JNIEnv *env, jobject thiz, jintArray sourceArr , jobject targetArr, jdouble targetError){ jdouble error = 0.0; int index, c1, c2, b, g, r = 0; jint *sarr, *tarr; sarr = (*env)->GetIntArrayElements(env, sourceArr, NULL); tarr = (*env)->GetIntArrayElements(env, targetArr, NULL); if (sarr == NULL || tarr == NULL) return targetError; int size = (*env)->GetArrayLength(env, sourceArr) ; for (index = 0; index < size; index++) { c1 = sarr[index]; c2 = tarr[index]; b = (c1 >> 16 & 255) - (c2 >> 16 & 255); g = (c1 >> 8 & 255) - (c2 >> 8 & 255); r = (c1 & 255) - (c2 & 255); error += r * r + g * g + b * b; if (error > targetError){ (*env)->ReleaseIntArrayElements(env, sourceArr, sarr, 0); (*env)->ReleaseIntArrayElements(env, targetArr, tarr, 0); return error; } } (*env)->ReleaseIntArrayElements(env, sourceArr, sarr, 0); (*env)->ReleaseIntArrayElements(env, targetArr, tarr, 0); return error; } All native functions must have the JNIEnv (a reference to the virtual machine itself) and the jobject (a reference to the “this pointer” of the Java object where the native method call comes from) as the first two arguments. Then it is possible to add custom arguments. ISSN 1028-9763. Математичні машини і системи, 2016, № 2 75 It is necessary to find a way to make the virtual machine direct the calls to the native de- clared Java method to the native C function. This is done using the registerNatives function of the JNIEnv. If developer uses the boilerplate C code from above two things are to be done: 1. Setting the classpath variable to the full class name of the Java class (including package name). Replacing the dots with slashes. 2. For each native declared method in Java, inserting a JNINativeMethod struct into the methods[] array. For this example it will look like this static const char *classPathName = "com/jayway/MyComparator"; static JNINativeMethod methods[] = { // nameOfNativeMethod, methodSignature, methodPointer {"compare", "([I[ID)D", (void*)compareNative }, }; The first parameter is the name of the native declared Java method, the second is the sig- nature of the native declared Java method and the last parameter is the function pointer to the C function to execute when the native declared Java function is executed. The signature of a Java method can be determined using the javap tool from SUN’s Java SDK or developer can create it using the following table, Java VM Type Signatures. To make things really simple when developing JNI code Google has released the Android Native Development Kit (NDK). It is easy to setup and use. In short, developer creates a folder named jni in the Android project. Here all the c-files together with an Android.mk file are put. In the Android.mk developer specifies which c-files are to be compiled. In the Android NDK/apps folder a directory named after the project (perhaps my-app) is created. In this directory developer adds an Application.mk file. In the Application.mk, variable APP_PROJECT_PATH is necessary to set to the path of the Android project. After some simple benchmarking it is clear that the native declared method executed about 2–3 times faster than the original method executing within Dalvik. For larger images the im- provement might be even bigger (Fig. 2 and table 1) since a call to a native declared method takes more time than calling a normal Java method. Execution time was measured using Linux's perf tool. Each reported value is the average of 10 independent runs. Table 1. Different data sizes benchmarking results http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/method.html http://developer.android.com/sdk/ndk/1.6_r1/index.html http://developer.android.com/sdk/ndk/1.6_r1/index.html 76 ISSN 1028-9763. Математичні машини і системи, 2016, № 2 Fig. 2. Execution time and payload dependency when using JNI 4. JNI Performance overheads The main disadvantage of using JNI is calling a native method can be slower than making a nor- mal Java method call. There are some cases will be described below. Native methods will not be inlined by the JVM. Nor will they be just-in-time compiled for this specific machine – they are already compiled [3]. A Java array may be copied for access in native code, and later copied back. The cost can be linear in the size of the array. It was measured JNI copying of a 100,000 array to average about 75 microseconds on Windows desktop, and 82 microseconds on Mac. Fortunately, direct access may be obtained via GetPrimitiveArrayCritical or NewDirectByteBuffer. If the method is passed an object, or needs to make a callback, then the native method will likely be making its own calls to the JVM. Accessing Java fields, methods and types from the native code requires something similar to reflection. Signatures are specified in strings and que- ried from the JVM. This is both slow and error-prone [4]. Java Strings are objects, have length and are encoded. Accessing or creating a string may require an O(n) copy. In Bresenham's algorithm c implementation, a number of different techniques are used to copy an array that contains 1,000 elements. The copy operations are performed using various na- tive and nonnative methods. To make it easier to compare the performance of these different techniques, the program performs each copy 10,000 times. The first two copy techniques don't use any native code; the rest call C functions. These C functions are written using different JNI usage patterns to illustrate the costs associated with dif- ferent coding techniques. Note that some of these C functions don't perform the full array copy; they're included to highlight the costs of particular operations. Table 2 shows the benchmark re- sults for the different methods. Table 2. Array Copy Results Copy Method Time Arraycopy 234 ms Assign 984 ms Dumbnativecopy 1,609 ms Nativedonothing 1,125 ms Nativedoabsolutelynothin g 63 ms Nativecritical 578 ms Nativecriticalmemcpy 422 ms Nativepullonly 391 ms 5. Summary Using information presented above it was defined, that replacing critical parts of code with JNI analog could show significant dif- ference in performance. There are two main reasons for this: technical restrictions of JVM and fast nature of C code. In spite the fact that there is speed issue on the very low java level, especially on mobile devices, modern CPU power enough for coupe with most of the issues. http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetPrimitiveArrayCritical_ReleasePrimitiveArrayCritical http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#NewDirectByteBuffer ISSN 1028-9763. Математичні машини і системи, 2016, № 2 77 REFERENCES 1. Reinholtz K. Java will be faster than C++ / K. Reinholtz // ACM Sigplan Notices (ICDMA). – 2000. – P. 25 – 28. 2. Zorn B. The Measured Cost of Conservative Garbage Collection Software / B. Zorn // Software – Prac- tice & Experience. – 1993. – Vol. 23, Issue 7. – P. 733 – 756. 3. Schanzer E. Performance Considerations for Run-Time Technologies in the NET Framework / E. Schanzer. – Germany: Microsoft Developer Network article, 2012. – P. 71 – 93. 4. Cowell-Shah C.W. Nine Language Performance Round-up: Benchmarking Math & File I/O [Електронний ресурс] / C.W. Cowell-Shah // OSnews.com. – 2004. – Режим доступу: http://www.osnews.com/story/5602. Стаття надійшла до редакції 13.05.2016 http://www.osnews.com/story/5602