Dear all,
The pdf that comes with the snapdragon LLVM specifies the usage of the llvm via ndk-build, so at this moment it is not very clear to me how to make the transition from gcc to snapdragonclang using cmake.
The current setup uses:
- -- android-ndk-r8e/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++
- -- android-ndk-r8e/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
However I would like to switch to the snapdragonclang toolchain. As far as I understand that would be
- -- /android-ndk-r8e/toolchains/arm-linux-androideabi-snapdragonclang3.3.1/snapdragon-clang
- -- /android-ndk-r8e/toolchains/arm-linux-androideabi-snapdragonclang3.3.1/snapdragon-clang++
When running cmake, the following file is used:
-DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake ( https://code.google.com/p/android-cmake/source/browse/toolchain/android.toolchain.cmake)
I scanned through this file and I do not see there how to point to the snapdragon llvm, or whether it is supported. Perhaps since this file is more generic and the snapdragon llvm is made by qualcomm.
I originally call cmake like this:
cmake $TRACE_OPT -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G "Eclipse CDT4 - Unix Makefiles" -DOPT_NEON="ON" -DANDROID_ABI="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_FORCE_ARM_BUILD=ON -DANDROID_STL=gnustl_static ../$SOURCE_FOLDER
So I modified it to:
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G "Eclipse CDT4 - Unix Makefiles" -DOPT_NEON="ON" -DANDROID_ABI="armeabi-v7a with NEON" -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_FORCE_ARM_BUILD=ON -DANDROID_STL=gnustl_static -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.7 -DCMAKE_C_COMPILER=/development/android-ndk-r8e/toolchains/arm-linux-androideabi-snapdragonclang3.3.1/snapdragon-clang -DCMAKE_CXX_COMPILER=/development/android-ndk-r8e/toolchains/arm-linux-androideabi-snapdragonclang3.3.1/snapdragon-clang++ ../$SOURCE_FOLDER
where I specify the C and C++ compilers. Although by doing this, I leave other variables unspecified, namely:
<UNSET_VARIABLES> CMAKE_ASM_COMPILER, CMAKE_STRIP, CMAKE_AR, CMAKE_LINKER, CMAKE_NM, CMAKE_OBJCOPY, CMAKE_OBJDUMP, CMAKE_RANLIB
So I try:
NDK_TOOLCHAIN=4.7 make VERBOSE=1
and I get:
CMAKE_AR-NOTFOUND cr ../../../libs/armeabi-v7a/libmodule.a output.o
Error running link command: No such file or directory
Question 1: Should I link all the <UNSET_VARIABLES> to the binaries in:
android-ndk-r8e/toolchains/arm-linux-androideabi-snapdragonclang3.3.1/Snapdragon_LLVM_for_Android_3.3.1/bin/ ?
(llvm-as, llvm-ar, clang, etc)
Question 2: Does it even make sense to try and reuse android.toolchain.cmake ? Or is it just better to define a separate cmake file? (I would still need to know which compiler, assembler, linker to point to.)
Question 3: Is it truly enough to extract the toolchain into $NDK_ROOT/toolchains ? Or do I need to run some script so that the ndk becomes 'aware' that the snapdragon llvm is there? I ask this because probably ndk-build takes care of some updates via the setup.mk file. But again, it is not clear to me how this can be mapped to cmake.
Thanks in advance and sorry for the long post.
Hi,
ndk-build is the recommended way for using Snapdragon LLVM compiler with Android NDK. Is this something you could try instead of cmake?
To use Snapdragon LLVM you can use the following command line:
NDK_TOOLCHAIN_VERSION=snapdragonclang3.3.1 ndk-build -C <some_project>
More responses inline:
Hi Mandeep,
Thanks for your answer.
I will try the ndk-build eventually, but not for the time being. The reason for this is I wanted a quick check of the improvement in performance. I managed to hack it a bit together, but it seems that it would be too much work to do it properly at the moment (given our current setup), and the first results were not that promising anyway. Again this is no related only to the compiler, but also probably to the code itself.
I only have a question remaining, though. Is there a particular reason why the sructure of the LLVM is different than the clang compilers that come with the android ndk?
Thanks again for your help.
Francisco
If by structure you mean the directory structure, it was different in 3.3.x. We have modified the structure in the latest 3.4 release (that came out this week) to match Google's LLVM and GCC compilers.
Hi Raja,
Thanks. I have downloaded the 3.4 version and will give it a try.
A general question:
I see that in some posts and sites it is claimed that you can see an improvement in performance up to 10% by switching compiler. However I wonder if this is done 'just' by switching compiler, or there are other steps involved; namely ordering neon instructions, or limiting the data to specific sizes, etcetera.
Is there a description on how this compilers tailors the code for a beter performance on the krait?
regards,
Francisco
When measuring the performance impact of using a new compiler, it is important to remember, as with cars – “your mileage may vary”.
Software performance is complex and involves the interplay of many factors including algorithm, workload, and target hardware. A new compiler that is tuned for the target hardware can provide a significant performance boost when it matches specific functions. In the jpeg example that you referred to earlier, the 10% gain was achieved without modifying the source code through the compiler doing a better job of “auto-vectorizing” some of the loops in the source code. Snapdragon’s Krait implementation of the NEON vector unit (VeNum) is unusual among ARM chips in that it is 128 bits wide in hardware; most ARM implementations (if they include NEON) are 64 bits wide. This is one thing that the compiler team has focused on by making sure more loops are vectorized and they better utilize the wider path in hardware.
In rare cases where there is a perfect match, a performance gain can be dramatically more than the 10% in the jpeg example. In some other rare cases performance might even regress with a new compiler. From a whole program perspective, it is more important how the optimizations balance out and if the optimizations benefit critical functions such as improving frames per second or battery life.
We look forward to hearing your experience with Snapdragon LLVM.
If you find a specific case where you feel the compiler should be generating better code we would be happy to investigate this. To do this we will need the problem reduced to a test case along with a data set that exhibits the behavior. Note, it is important that the test case be measurable and reproducible.
It is possible to use the toolchain with cmake if you use a more up-to-date version of the android.toolchain.cmake (available from https://github.com/taka-no-me/android-cmake) and apply a couple small changes around lines 647-691 and 1038-1044 (see below) and then specify
-D=arm-linux-androideabi-snapdragon-clang3.4
on your cmake command line.***************
*** 644,650 ****
macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath )
foreach( __toolchain ${${__availableToolchainsLst}} )
if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" )
! string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" )
else()
set( __gcc_toolchain "${__toolchain}" )
endif()
--- 633,639 ----
macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath )
foreach( __toolchain ${${__availableToolchainsLst}} )
if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" )
! string( REGEX REPLACE "androideabi-.*clang3[.][0-9]$" "androideabi-4.8" __gcc_toolchain "${__toolchain}" )
else()
set( __gcc_toolchain "${__toolchain}" )
endif()
*** 688,699 ****
endif()
if( NOT __availableToolchains )
file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
! if( __availableToolchains )
list(SORT __availableToolchainsLst) # we need clang to go after gcc
endif()
__LIST_FILTER( __availableToolchainsLst "^[.]" )
__LIST_FILTER( __availableToolchainsLst "llvm" )
- __LIST_FILTER( __availableToolchainsLst "renderscript" )
__GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
__GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
--- 677,688 ----
endif()
if( NOT __availableToolchains )
file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" )
! if( __availableToolchainsLst )
list(SORT __availableToolchainsLst) # we need clang to go after gcc
endif()
__LIST_FILTER( __availableToolchainsLst "^[.]" )
+ __LIST_FILTER( __availableToolchainsLst "^renderscript" ) # broken in r9
__LIST_FILTER( __availableToolchainsLst "llvm" )
__GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 )
__GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" )
# clang
if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" )
! set( ANDROID_COMPILER_IS_CLANG 1 )
! execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE )
! string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}")
elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" )
! string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}")
! string( REGEX REPLACE "androideabi-.*clang${ANDROID_CLANG_VERSION}$" "androideabi-4.8" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
! # check for the snapdragon clang
! if( ${ANDROID_TOOLCHAIN_NAME} MATCHES "snapdragon-clang3[.][0-9]?$")
! set (_android_ndk_clang_prefix "llvm-Snapdragon_LLVM_for_Android_" )
! else()
! set (_android_ndk_clang_prefix "llvm-")
! endif()
! if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${_android_ndk_clang_prefix}${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" )
! message( FATAL_ERROR "Could not find the Clang compiler driver" )
! endif()
! set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${_android_ndk_clang_prefix}${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" )
! set( ANDROID_COMPILER_IS_CLANG 1 )
! unset(_android_ndk_clang_prefix)
else()
! set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" )
! unset( ANDROID_COMPILER_IS_CLANG CACHE )
endif()
string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" )
if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" )
Hope this helps!