[Huawei Developers] Freemind R:
Prerequisites

Android Studio 3.6

Android SDK

Kotlin 1.3.72

Required knowledge

C programming language

Multithreading programming

Integration steps

Add the native build support to your build.gradle file

externalNativeBuild {
cmake {
cppFlags ""
arguments "-DANDROID_STL=c++_shared"
}
}
ndk {
abiFilters "arm64-v8a","armeabi-v7a"
}

Download the SDK package from this link and decompress it

Copy the header files in the SDK to the resource library.

In the /app directory in the Android Studio project, create an include folder. Copy the files in the /include directory of the SDK to the newly created include folder.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707093614.12081242473519842013354821535031:50510714023543:2800:F4ED2486BAA1415B7632178BA887453235789F7C30C3EFD9BC9C79F64523ABEB.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707093614.12081242473519842013354821535031:50510714023543:2800:F4ED2486BAA1415B7632178BA887453235789F7C30C3EFD9BC9C79F64523ABEB.png[/IMG]

Copy the .so files in the SDK to the resource library.

Create a libs folder in the /app directory and create arm64-v8a folder and armeabi-v7a folder in /app/libs directory.

Copy the libdispatch.so and libBlockRuntime.so in lib64 directory of the SDK to libs/arm64-v8a directory of Android Studio.

Copy the libdispatch.so and libBlockRuntime.so in the lib directory of the SDK to the libs/armeabi-v7a directory of Android Studio.

Create or modify the CMakeLists.txt file in the app/src/main/cpp directory as follows

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
native-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

target_include_directories(
native-lib
PRIVATE
${CMAKE_SOURCE_DIR}/../../../include)

find_library( # Sets the name of the path variable.
log-lib

# Specifies the name of the NDK library that
# you want CMake to locate.
log )

add_library(
dispatch
SHARED
IMPORTED)

set_target_properties(
dispatch
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/libdispatch.so)

add_library(
BlocksRuntime
SHARED
IMPORTED)

set_target_properties(
BlocksRuntime
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/libBlocksRuntime.so)

add_custom_command(
TARGET native-lib POST_BUILD
COMMAND
${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/libdispatch.so
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/
COMMAND
${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../../../libs/${ANDROID_ABI}/libBlocksRuntime.so
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/
)

target_compile_options(native-lib PRIVATE -fblocks)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
native-lib
dispatch
BlocksRuntime
# Links the target library to the log library
# included in the NDK.
${log-lib} )

From Android Studio, select Build → Linked C++ projects

Download the NDK if not configured and install it then sync with your projects

PI Formula

We will use the two below formula to calculate PI number

Nilakantha series

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707100003.72802534676449076982568067610614:50510714023543:2800:B8E4068259930DC662ECBBA010B8CF38FDCA09EEE32A6AE933368E2124039BA9.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707100003.72802534676449076982568067610614:50510714023543:2800:B8E4068259930DC662ECBBA010B8CF38FDCA09EEE32A6AE933368E2124039BA9.png[/IMG]

Coding steps

Open your application class and add the below code to load the native library when the application is created

companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}

On your demo activity, remember to add the external functions as below

/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
private external fun doubleFromJNI(): Double
private external fun doubleFromJNI2(): Double

Then defined these functions in app/src/main/native-lib.cpp as below ( I will explain the dispatch functions later)

extern "C"
JNIEXPORT jdouble JNICALL
Java_com_pushdemo_jp_huawei_activity_AccelerateDemoActivity_doubleFromJNI(JNIEnv *env,
jobject thiz) {
dispatch_autostat_enable(env);
return dispatch1();
}

extern "C"
JNIEXPORT jdouble JNICALL
Java_com_pushdemo_jp_huawei_activity_AccelerateDemoActivity_doubleFromJNI2(JNIEnv *env,
jobject thiz) {
dispatch_autostat_enable(env);
return dispatch2();
}

For each formula, we will implement each function to calculate and divide them into subthread to execute to save time

For Nilakantha series, we will divide into 2 subthreads, and values of i set as follows:

[2, 6, 10, 14, ...]

[4, 8, 12, 16, ...]

double calcPiByStep(long start, long end, int step)
{
double total = 0.0;
int sign;
for (long i = start; i <= end; i += step)
{
long frag = i * (i + 1) * (i + 2);
sign = i % 4 == 0 ? -1 : 1;
double val = 4.0 * sign / frag;
total += val;
}
return total;
}

Then we will implement the dispatch1 function to summarize the result. First, create the concurrent queue, the serial queue, and the group queue. Then asynchronously add the subtask calcPiByStep to the concurrent queue, and associate the subtask with the group queue.

double dispatch1()
{
int i;
int step = 4;
long start = 2;
long limit = 1000000000;
__block double pi_total = 3;

dispatch_queue_t concurr_q = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t serial_q = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_group_t group = dispatch_group_create();

for (i = 0; i < step; i += 2) {
dispatch_group_async(group, concurr_q, ^{
double pi = calcPiByStep(start + i, limit, step);
dispatch_sync(serial_q, ^{
pi_total += pi;
});
});
}

dispatch_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
dispatch_release(serial_q);

return pi_total;
}

For Gregory and Leibniz series, we will divide into 4 subthreads, and values of i set as follows:

[0, 4, 8, 12, ...]

[1, 5, 9, 13, ...]

[2, 6, 10, 14, ...]

[3, 7, 11, 15, ...]

double calcPiByStep2(long start, long end, int step)
{
double total = 0.0;
int sign;
for (long i = start; i <= end; i+= step)
{
long frag = 2 * i + 1;
sign = i % 2 == 0 ? 1 : -1;
total += 4.0 * sign / frag;
}
return total;
}

Then we will execute 4 subthreads concurrently as below

double dispatch2() {
__block double pi = 0;
int mod = 4;
int i = 0;
long limit = 1000000000;

dispatch_queue_t serial = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_apply(mod, DISPATCH_APPLY_AUTO, ^(size_t i) {
double _sum = calcPiByStep2(i, limit, mod);
dispatch_sync(serial, ^{
pi += _sum;
});
});

dispatch_release(serial);
return pi;
}

Result

For HMS devices, the result is quite fast. It took around 1.7 seconds to execute the dispatch1 and 1.4 seconds to execute the dispatch2

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707105058.50689458432168565141315336715921:50510714023543:2800:6D91450C47C181645E973D77016F92EA0C033412F7AA1A26306D829B4DEF0DE8.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707105058.50689458432168565141315336715921:50510714023543:2800:6D91450C47C181645E973D77016F92EA0C033412F7AA1A26306D829B4DEF0DE8.jpg[/IMG]

But for non-HMS devices, the calculation took longer times: around 6.7 seconds for dispatch1 and 3.5 seconds for dispatch2

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707110950.31667738663827588734926594690086:50510714023543:2800:B395E0D9AB95C4FFD98B0CD9121C981505E5BB1AA9352705D1516AABBAA044DA.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/043/403/889/5190081000043403889.20200707110950.31667738663827588734926594690086:50510714023543:2800:B395E0D9AB95C4FFD98B0CD9121C981505E5BB1AA9352705D1516AABBAA044DA.jpg[/IMG]

Conclusion

The performance depends on the chipset. For HMS devices (using Kirin chip), the performance is good but for non-HMS devices (using other chip), the performance needs to be improved.