Limit CPU cores for ndkBuild with Cmake and Ninja
Asked Answered
C

4

9

Before, when I was using ndkBuld for building native code on Android I was able to pass an argument to make to define a number of CPU cores to be used. If I wanted to utilize 4 cores I could add something like this

externalNativeBuild {
    ndkBuild {
        arguments "-j4", "APP_SHORT_COMMANDS=true"
        abiFilters "armeabi-v7a"
    }
}

Can somebody give an advice how can I do something similar with Cmake and Ninja? Is there some equivalent parameter for cmake configuration?

externalNativeBuild {
    cmake {
        arguments "-DANDROID_STL=c++_static"
        abiFilters getAbis()
    }
}

Thanks.

Campestral answered 27/7, 2018 at 12:4 Comment(0)
C
0

Ok it seems it is a bug / missing feature in NDK. I've talked to some "NDK Googlers" and they were not able to help me either. Hopefully it will be supported in later versions of NDK / AS.

Here are the issues you can track the progress:

https://github.com/android-ndk/ndk/issues/983

and

https://issuetracker.google.com/issues/137878831

Campestral answered 4/9, 2019 at 15:19 Comment(0)
I
9

controlling ninja parallelism

Ninja also support the same parameter:

$ ninja --help
usage: ninja [options] [targets...]

[...]

options:
  [...]

  -j N     run N jobs in parallel [default=10, derived from CPUs available]

  [...]

controlling ninja parallelism differentiating compile and link jobs

Now, if you want more granularity. For example, if you would like to limit the number of simultaneous link jobs, or compile jobs, or both.

Starting with CMake 3.11, it is now possible to limit the number of compile and/or link jobs.

You could then configure your project with these options:

-DCMAKE_JOB_POOL_COMPILE:STRING=compile
-DCMAKE_JOB_POOL_LINK:STRING=link
'-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'

Now, if your project end up spawning other child processed that are themselves building projects using ninja, you would have to:

  • use the fork of ninja that include Job Server support like it is done in make. Binaries are also available in the associated GitHub releases. See https://github.com/kitware/ninja#readme

  • make sure sub-project are also configured with the same -DCMAKE_JOB_ options

in the context of externalNativeBuild

This means you could try something like this:

externalNativeBuild {
    cmake {
        arguments "-DANDROID_STL=c++_static -DCMAKE_JOB_POOL_COMPILE:STRING=compile -DCMAKE_JOB_POOL_LINK:STRING=link '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'"
        abiFilters getAbis()
    }
}
Intendance answered 28/7, 2018 at 2:38 Comment(13)
Can you suggest the solution in the context of Android gradle build file? If I put the arguments into the externalNativeBuild { cmake { arguments section I got the following error: Error while executing process D:\Android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build D:\...\.externalNativeBuild\cmake\fullDebug\arm64-v8a --target JniInterface} ninja: error: build.ninja:113: unknown pool name 'compile' For the other solution. I know ninja can accept -j parameter but I'm not running ninja directly and adding -Dj X as an argument for cmake doesn't do anything...Campestral
Considering that -jN is an option specific to the build-tool ninja, specifying -Dj X (or -Dj=X) will not work. The error unknown pool name 'compile' probably indicates that you configured the project by only passing the option '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2' and forgot to pass -DCMAKE_JOB_POOL_COMPILE:STRING=compile and -DCMAKE_JOB_POOL_LINK:STRING=linkIntendance
I updated the answer to suggest a possible approach using externalNativeBuildIntendance
No I've put all of the arguments there before. Anyway putting it the way you suggests is not working either Build command failed. Error while executing process D:\...\cmake.exe with arguments {-HD:\...\sdk -BD:\...\arm64-v8a -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-21 -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\...\arm64-v8a -DCMAKE_BUILD_TYPE=Debug ... -DCMAKE_MAKE_PROGRAM=D:\...\ninja.exe -GAndroid Gradle - Ninja -DANDROID_STL=c++_static -DCMAKE_JOB_POOL_COMPILE:STRING=compile -DCMAKE_JOB_POOL_LINK:STRING=link '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2'}Campestral
whole error message was too long so I've removed paths and some unimportant arguments. But I don't think that should be a problem for youCampestral
If the arguments reported are effectively the one passed through the command line, having -GAndroid Gradle - Ninja without quotes seems suspicious. Is there any other relevant messages ?Intendance
The error occurs during gradle sync already. But there is nothing else relevant to the issue.Campestral
Do you confirm that the issue started with the addition of the -DCMAKE_JOB_* options ? If you remove them, is the build completing ? Or at least starting normally ? May be you could try to remove the ' single quote, this needs to be done when running the command from the command line to avoid the ; from being interpreted. If your case, it may be not be needed.,Intendance
yes, without the -DCMAKE_JOB_* attributes build is running normally successfully creating APK at the end. Quotes in '-DCMAKE_JOB_POOLS:STRING=compile=5;link=2' makes no difference. I've tried it without them and the result was the sameCampestral
Let us continue this discussion in chat.Intendance
Could you let us know the result of the discussion? I'm facing the same problems.Bahner
Looks like the chat archive is not available, or it didn't happen (this happened a while back). That said, if you don't have any luck with setting the -DCMAKE_JOB_ , you could look into setting the CMAKE_BUILD_PARALLEL_LEVEL environment variable [1]. Note: independently of the approach, if you are using ExternalProject module (IOW if ninja project end up building an other one ninja based project), you must use the fork of ninja supporting job server [2]) [1] cmake.org/cmake/help/latest/envvar/… [2] github.com/kitware/ninja#readmeIntendance
As it was stated - make sure you are using at least cmake 3.11. These pool features are NOT available until that version.Brno
N
2

I was able to fix this by adding:

if (PARALLEL_COMPILE_JOBS)
  set(CMAKE_JOB_POOL_COMPILE compile_job_pool${CMAKE_CURRENT_SOURCE_DIR})
  string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_COMPILE ${CMAKE_JOB_POOL_COMPILE})
  set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_COMPILE}=${PARALLEL_COMPILE_JOBS})
endif ()
  if (PARALLEL_COMPILE_JOBS)
    message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Limiting compiler jobs to ${PARALLEL_COMPILE_JOBS}")
endif ()

to my base CMakeLists.txt, and then in my build.gradle I added to cmake arguments: "-DPARALLEL_COMPILE_JOBS=8" to specify max 8 parallel clang++ compile processes. This works on current Android Studio cmake (3.10) and ninja (1.8.2) versions

Nogging answered 8/4, 2020 at 16:38 Comment(0)
A
1

I created a workaround: wrap the ninja executable used by Android Studio with a script that calls ninja with all given parameter plus "-j1" at the end.

  1. Locate the ninja executable used by Android Studio. Something like, for example, somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
  2. Rename it to something else, like ninja_orig
  3. Create a shell script (and add execution permission to it) to replace the original ninja executable at somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja with the following content:
    #!/bin/sh
    somefolder/Android/Sdk/cmake/3.10.2.4988404/bin/ninja_orig $@ -j1
    
Angiology answered 4/12, 2019 at 10:43 Comment(0)
C
0

Ok it seems it is a bug / missing feature in NDK. I've talked to some "NDK Googlers" and they were not able to help me either. Hopefully it will be supported in later versions of NDK / AS.

Here are the issues you can track the progress:

https://github.com/android-ndk/ndk/issues/983

and

https://issuetracker.google.com/issues/137878831

Campestral answered 4/9, 2019 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.