dropbox / djinni

A tool for generating cross-language type declarations and interface bindings.
Apache License 2.0
2.88k stars 488 forks source link

iOS vs Android performance #424

Closed MouhamadKawas closed 5 years ago

MouhamadKawas commented 5 years ago

Hi, I am using Djinni to generate a cross-platform core for Android and iOS

The iOS build is good and the performance is as expected. However, the Android performance is very slow compared to the iOS knowing that they are using the exact same code.

We have tried the Android build on the newest Android devices, Galaxy S8+ for example, and still the performance is very slow

I'm not sure if this is a Djinni related issue, but I only want to make sure that there are no issues in building the project.

Here is the .gyp file which we are using to build the iOS project

{
    "targets": [
        {
            "target_name": "libMedicusCore_jni",
            "type": "shared_library",
            "dependencies": [
              "./deps/djinni/support-lib/support_lib.gyp:djinni_jni",
              "./deps/sqlite3.gyp:sqlite3",
              "./deps/fmt.gyp:fmt",
            ],
            "ldflags": [ "-llog", "-lz", "-Wl,--build-id,--gc-sections,--exclude-libs,ALL" ],
            'conditions': [
              ['OS=="android" and OS!="ios"',
                {
                  "libraries": ["libcurl.a"],
                  "ccflags": ["-O3"],
                }
              ],
              ['OS!="android" and OS=="ios"',
                {
                  "libraries": [],
                  "ccflags": ["-O3"],
                }
              ],
            ],
            "sources": [
              "./deps/djinni/support-lib/jni/djinni_main.cpp",
              "<!@(python deps/djinni/example/glob.py generated-src/jni   '*.cpp')",
              "<!@(python deps/djinni/example/glob.py generated-src/cpp   '*.cpp')",
              "<!@(python deps/djinni/example/glob.py MedicusCore/clips '*.c')",
              "<!@(python deps/djinni/example/glob.py core_src '*.cpp')",
              "<!@(python deps/djinni/example/glob.py MedicusCore/libs/ '*.cpp' '*.cc')",
            ],
            'xcode_settings': {
              'OTHER_CFLAGS!' : ['-lcurl'],
            },
            "include_dirs": [
              "generated-src/jni",
              "generated-src/cpp",
              "MedicusCore/Core1/include",
              "MedicusCore/Core2/include",
              "MedicusCore/Engine/include",
              "MedicusCore/Metro/include",
              "MedicusCore/Certa/include",
              "MedicusCore/AppointmentManagement/include",
              "MedicusCore/WomenHealth/include",
              "MedicusCore/MedicationsReminders/include",
              "MedicusCore/Certa/include",
              "MedicusCore/Coaching/include",
              "MedicusCore/Localization/include",
              "MedicusCore/Wellbeing/include",
              "MedicusCore/HR/include",
              "MedicusCore/libs/",
              "MedicusCore/libs/jwt/json/",
              "MedicusCore/libs/base64/",
              "MedicusCore/libs/restclient/",
              "MedicusCore/libs/orm/",
              "MedicusCore/clips/",
              "deps/curl",
            ],
        },
        {
            "target_name": "libMedicusCore_objc",
            "type": 'static_library',
            "dependencies": [
              "./deps/djinni/support-lib/support_lib.gyp:djinni_objc",
              "./deps/sqlite3.gyp:sqlite3",
              "./deps/fmt.gyp:fmt",
            ],
            'conditions': [
              ['OS=="android" and OS!="ios"',
                {
                  "libraries": ["libcurl.a"],
                  "ccflags": ["-O3"],
                }
              ],
              ['OS!="android" and OS=="ios"',
                {
                  "libraries": [],
                  "ccflags": ["-O3"],
                }
              ],
            ],
            'direct_dependent_settings': {

            },
            "sources": [
              "<!@(python deps/djinni/example/glob.py generated-src/objc  '*.cpp' '*.mm' '*.m')",
              "<!@(python deps/djinni/example/glob.py generated-src/cpp   '*.cpp')",
              "<!@(python deps/djinni/example/glob.py MedicusCore/clips '*.c')",
              "<!@(python deps/djinni/example/glob.py core_src '*.cpp')",
              "<!@(python deps/djinni/example/glob.py MedicusCore/libs/ '*.cpp' '*.cc')",
            ],
            "include_dirs": [
              "generated-src/objc",
              "generated-src/cpp",
              "MedicusCore/Core1/include",
              "MedicusCore/Core2/include",
              "MedicusCore/Engine/include",
              "MedicusCore/Metro/include",
              "MedicusCore/Certa/include",
              "MedicusCore/AppointmentManagement/include",
              "MedicusCore/WomenHealth/include",
              "MedicusCore/MedicationsReminders/include",
              "MedicusCore/Certa/include",
              "MedicusCore/Coaching/include",
              "MedicusCore/Localization/include",
              "MedicusCore/Wellbeing/include",
              "MedicusCore/HR/include",
              "MedicusCore/libs/",
              "MedicusCore/libs/leveldb",
              "MedicusCore/libs/jwt/json/",
              "MedicusCore/libs/base64/",
              "MedicusCore/libs/restclient/",
              "MedicusCore/libs/orm/",
              "MedicusCore/clips/",
              "deps/curl",
            ],
        },
    ],
}

And here is the Android CmakeLists.txt file:

cmake_minimum_required(VERSION 3.6)

set(curl_DIR ${CMAKE_SOURCE_DIR}/../../../deps/curl/android/)

add_library(curl STATIC IMPORTED)
set_target_properties(curl PROPERTIES IMPORTED_LOCATION
        ${curl_DIR}/${ANDROID_ABI}/libcurl.a)

file(GLOB medicuscore_sources
    ../../../deps/djinni/support-lib/jni/*.cpp
    ../../../generated-src/jni/*.cpp
    ../../../core_src/*.cpp
    ../../../MedicusCore/clips/*.c
    ../../../MedicusCore/libs/*.cpp
    ../../../MedicusCore/libs/base64/*.cpp
    ../../../MedicusCore/libs/restclient/*.cpp
    ../../../deps/fmt/*.cc
    ../../../deps/sqlite3/*.c
)

add_library(medicuscore SHARED ${medicuscore_sources})

# include directories for header files
include_directories(
    ../../../deps/djinni/support-lib/
    ../../../deps/djinni/support-lib/jni/
    ../../../generated-src/cpp/
    ../../../generated-src/jni/
    ../../../MedicusCore/Core1/include/
    ../../../MedicusCore/Core2/include/
    ../../../MedicusCore/Engine/include/
    ../../../MedicusCore/Metro/include/
    ../../../MedicusCore/Certa/include/
    ../../../MedicusCore/AppointmentManagement/include/
    ../../../MedicusCore/MedicationsReminders/include/
    ../../../MedicusCore/Certa/include
    ../../../MedicusCore/Coaching/include
    ../../../MedicusCore/Localization/include
    ../../../MedicusCore/WomenHealth/include/
    ../../../MedicusCore/Wellbeing/include/
        ../../../MedicusCore/HR/include/
    ../../../MedicusCore/libs/
    ../../../MedicusCore/libs/orm
    ../../../MedicusCore/libs/jdbc
    ../../../MedicusCore/libs/base64
    ../../../MedicusCore/libs/jwt
    ../../../MedicusCore/libs/jwt/json
    ../../../MedicusCore/libs/restclient
    ../../../MedicusCore/clips/
    ../../../deps/fmt/
    ../../../deps/sqlite3/
    PRIVATE ../../../deps/curl/
)
target_link_libraries(medicuscore z curl)

And here is the build.gradle file:

apply plugin: 'com.android.application'

android {
    signingConfigs {
        release {
            keyAlias 'key0'
            keyPassword '123456'
            storeFile file('/Users/firas/test3')
            storePassword '123456'
        }
    }
    compileSdkVersion 28
    defaultConfig {
        applicationId "ai.medicus.medicuscoreandroid"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                cppFlags "-D ANDROID_BUILD -std=c++14"
                arguments "-DANDROID_STL=c++_static", "-DANDROID_TOOLCHAIN=clang "
            }
        }
    }
    buildTypes {
        release {
            debuggable true
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            ndk {
                abiFilter "armeabi-v7a"
            }
            signingConfig signingConfigs.release
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['../../../deps/curl/android/']
            java {
                srcDirs = [
                        "../../../generated-src/java",
                        "src/main/java"
                ]
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
artwyman commented 5 years ago

Specifics of build files are outside the scope of Djinni, which just generates source code which should behave like any other C++ source code built for the platform.

The one expected performance differential between platforms is the cost of passing data across JNI from Java <-> C++, which is more expensive than passing data from ObjC <-> C++ due to the memory model differences. If your application relies on high-frequency calls across the boundary, or repeated data copying across the boundary, that might be a place to look for performance impact.

Beyond that, you might consider joining the Slack community mentioned in the README to discuss your performance issues with other mobile C++ developers who may have suggestions.