Skip to content

Commit 92b9de1

Browse files
IvanKobzarevfacebook-github-bot
authored andcommitted
Test application for profiling, CMake params for debug symbols (pytorch#28406)
Summary: Reason: To have one-step build for test android application based on the current code state that is ready for profiling with simpleperf, systrace etc. to profile performance inside the application. ## Parameters to control debug symbols stripping Introducing /CMakeLists parameter `ANDROID_DEBUG_SYMBOLS` to be able not to strip symbols for pytorch (not add linker flag `-s`) which is checked in `scripts/build_android.sh` On gradle side stripping happens by default, and to prevent it we have to specify ``` android { packagingOptions { doNotStrip "**/*.so" } } ``` which is now controlled by new gradle property `nativeLibsDoNotStrip ` ## Test_App `android/test_app` - android app with one MainActivity that does inference in cycle `android/build_test_app.sh` - script to build libtorch with debug symbols for specified android abis and adds `NDK_DEBUG=1` and `-PnativeLibsDoNotStrip=true` to keep all debug symbols for profiling. Script assembles all debug flavors: ``` └─ $ find . -type f -name *apk ./test_app/app/build/outputs/apk/mobilenetQuant/debug/test_app-mobilenetQuant-debug.apk ./test_app/app/build/outputs/apk/resnet/debug/test_app-resnet-debug.apk ``` ## Different build configurations Module for inference can be set in `android/test_app/app/build.gradle` as a BuildConfig parameters: ``` productFlavors { mobilenetQuant { dimension "model" applicationIdSuffix ".mobilenetQuant" buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_MOBILENET_QUANT')) addManifestPlaceholders([APP_NAME: "PyMobileNetQuant"]) buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-mobilenet\"") } resnet { dimension "model" applicationIdSuffix ".resnet" buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_RESNET18')) addManifestPlaceholders([APP_NAME: "PyResnet"]) buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-resnet\"") } ``` In that case we can setup several apps on the same device for comparison, to separate packages `applicationIdSuffix`: 'org.pytorch.testapp.mobilenetQuant' and different application names and logcat tags as `manifestPlaceholder` and another BuildConfig parameter: ``` ─ $ adb shell pm list packages | grep pytorch package:org.pytorch.testapp.mobilenetQuant package:org.pytorch.testapp.resnet ``` In future we can add another BuildConfig params e.g. single/multi threads and other configuration for profiling. At the moment 2 flavors - for resnet18 and for mobilenetQuantized which can be installed on connected device: ``` cd android ``` ``` gradle test_app:installMobilenetQuantDebug ``` ``` gradle test_app:installResnetDebug ``` ## Testing: ``` cd android sh build_test_app.sh adb install -r test_app/app/build/outputs/apk/mobilenetQuant/debug/test_app-mobilenetQuant-debug.apk ``` ``` cd $ANDROID_NDK python simpleperf/run_simpleperf_on_device.py record --app org.pytorch.testapp.mobilenetQuant -g --duration 10 -o /data/local/tmp/perf.data adb pull /data/local/tmp/perf.data python simpleperf/report_html.py ``` Simpleperf report has all symbols: ![Screenshot 2019-10-22 11 06 21](https://user-images.githubusercontent.com/6638825/67315740-0bc50100-f4bc-11e9-8f9e-2499be13d63e.png) Pull Request resolved: pytorch#28406 Differential Revision: D18386622 Pulled By: IvanKobzarev fbshipit-source-id: 3a751192bbc4bc3c6d7f126b0b55086b4d586e7a
1 parent 52456b2 commit 92b9de1

File tree

20 files changed

+425
-10
lines changed

20 files changed

+425
-10
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0.0
495495
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-overflow")
496496
endif()
497497

498-
if(ANDROID)
498+
if(ANDROID AND (NOT ANDROID_DEBUG_SYMBOLS))
499499
if(CMAKE_COMPILER_IS_GNUCXX)
500500
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")
501501
else()

android/.gitignore

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,5 @@ gradle/wrapper
66
.idea/*
77
.externalNativeBuild
88
build
9-
pytorch_android/src/main/cpp/libtorch_include/x86/**
10-
pytorch_android/src/main/cpp/libtorch_include/x86_64/**
11-
pytorch_android/src/main/cpp/libtorch_include/armeabi-v7a/**
12-
pytorch_android/src/main/cpp/libtorch_include/arm64-v8a/**
13-
pytorch_android/src/main/jniLibs/x86/**
14-
pytorch_android/src/main/jniLibs/x86_64/**
15-
pytorch_android/src/main/jniLibs/armeabi-v7a/**
16-
pytorch_android/src/main/jniLibs/arm64-v8a/**
9+
pytorch_android/src/main/cpp/libtorch_include/**
10+
pytorch_android/src/main/jniLibs/**

android/build_test_app.sh

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/bin/bash
2+
set -eux
3+
4+
PYTORCH_DIR="$(cd $(dirname $0)/..; pwd -P)"
5+
6+
PYTORCH_ANDROID_DIR=$PYTORCH_DIR/android
7+
WORK_DIR=$PYTORCH_DIR
8+
9+
echo "PYTORCH_DIR:$PYTORCH_DIR"
10+
echo "WORK_DIR:$WORK_DIR"
11+
12+
echo "ANDROID_HOME:$ANDROID_HOME"
13+
if [ ! -z "$ANDROID_HOME" ]; then
14+
echo "ANDROID_HOME not set; please set it to Android sdk directory"
15+
fi
16+
17+
if [ ! -d $ANDROID_HOME ]; then
18+
echo "ANDROID_HOME not a directory; did you install it under $ANDROID_HOME?"
19+
exit 1
20+
fi
21+
22+
GRADLE_PATH=gradle
23+
GRADLE_NOT_FOUND_MSG="Unable to find gradle, please add it to PATH or set GRADLE_HOME"
24+
25+
if [ ! -x "$(command -v gradle)" ]; then
26+
if [ -z "$GRADLE_HOME" ]; then
27+
echo GRADLE_NOT_FOUND_MSG
28+
exit 1
29+
fi
30+
GRADLE_PATH=$GRADLE_HOME/bin/gradle
31+
if [ ! -f "$GRADLE_PATH" ]; then
32+
echo GRADLE_NOT_FOUND_MSG
33+
exit 1
34+
fi
35+
fi
36+
echo "GRADLE_PATH:$GRADLE_PATH"
37+
38+
ABIS_LIST="armeabi-v7a,arm64-v8a,x86,x86_64"
39+
CUSTOM_ABIS_LIST=false
40+
if [ $# -gt 0 ]; then
41+
ABIS_LIST=$1
42+
CUSTOM_ABIS_LIST=true
43+
fi
44+
45+
echo "ABIS_LIST:$ABIS_LIST"
46+
47+
LIB_DIR=$PYTORCH_ANDROID_DIR/pytorch_android/src/main/jniLibs
48+
INCLUDE_DIR=$PYTORCH_ANDROID_DIR/pytorch_android/src/main/cpp/libtorch_include
49+
mkdir -p $LIB_DIR
50+
rm $LIB_DIR/*
51+
mkdir -p $INCLUDE_DIR
52+
53+
for abi in $(echo $ABIS_LIST | tr ',' '\n')
54+
do
55+
echo "abi:$abi"
56+
57+
OUT_DIR=$WORK_DIR/build_android_$abi
58+
59+
rm -rf $OUT_DIR
60+
mkdir -p $OUT_DIR
61+
62+
pushd $PYTORCH_DIR
63+
python $PYTORCH_DIR/setup.py clean
64+
65+
ANDROID_ABI=$abi BUILD_PYTORCH_MOBILE=1 VERBOSE=1 ANDROID_DEBUG_SYMBOLS=1 $PYTORCH_DIR/scripts/build_android.sh -DANDROID_CCACHE=$(which ccache)
66+
67+
cp -R $PYTORCH_DIR/build_android/install/lib $OUT_DIR/
68+
cp -R $PYTORCH_DIR/build_android/install/include $OUT_DIR/
69+
70+
echo "$abi build output lib,include copied to $OUT_DIR"
71+
72+
LIB_LINK_PATH=$LIB_DIR/$abi
73+
INCLUDE_LINK_PATH=$INCLUDE_DIR/$abi
74+
75+
rm -f $LIB_LINK_PATH
76+
rm -f $INCLUDE_LINK_PATH
77+
78+
ln -s $OUT_DIR/lib $LIB_LINK_PATH
79+
ln -s $OUT_DIR/include $INCLUDE_LINK_PATH
80+
81+
done
82+
83+
# To set proxy for gradle add following lines to ./gradle/gradle.properties:
84+
# systemProp.http.proxyHost=...
85+
# systemProp.http.proxyPort=8080
86+
# systemProp.https.proxyHost=...
87+
# systemProp.https.proxyPort=8080
88+
89+
if [ "$CUSTOM_ABIS_LIST" = true ]; then
90+
NDK_DEBUG=1 $GRADLE_PATH -PnativeLibsDoNotStrip=true -PABI_FILTERS=$ABIS_LIST -p $PYTORCH_ANDROID_DIR clean test_app:assembleDebug
91+
else
92+
NDK_DEBUG=1 $GRADLE_PATH -PnativeLibsDoNotStrip=true -p $PYTORCH_ANDROID_DIR clean test_app:assembleDebug
93+
fi
94+
95+
find $PYTORCH_ANDROID_DIR -type f -name *apk
96+
97+
find $PYTORCH_ANDROID_DIR -type f -name *apk | xargs echo "To install apk run: $ANDROID_HOME/platform-tools/adb install -r "
98+
99+
popd
100+

android/gradle.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@ ANDROID_MAVEN_GRADLE_PLUGIN_VERSION=2.1
2222
# Gradle internals
2323
org.gradle.internal.repository.max.retries=1
2424
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1024m
25+
26+
android.useAndroidX=true
27+
android.enableJetifier=true
28+
29+
nativeLibsDoNotStrip=false

android/pytorch_android/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ android {
4242
} else {
4343
pickFirst '**/libfbjni.so'
4444
}
45+
if (nativeLibsDoNotStrip) {
46+
doNotStrip "**/*.so"
47+
}
4548
}
4649

4750
useLibrary 'android.test.runner'

android/settings.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
include ':app', ':pytorch_android', ':fbjni', ':pytorch_android_torchvision', ':pytorch_host'
1+
include ':app', ':pytorch_android', ':fbjni', ':pytorch_android_torchvision', ':pytorch_host', ':test_app'
22

33
project(':fbjni').projectDir = file('libs/fbjni_local')
44
project(':pytorch_android_torchvision').projectDir = file('pytorch_android_torchvision')
55

66
project(':pytorch_host').projectDir = file('pytorch_android/host')
7+
project(':test_app').projectDir = file('test_app/app')
8+

android/test_app/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
local.properties
2+
**/*.iml
3+
.gradle
4+
gradlew*
5+
gradle/wrapper
6+
.idea/*
7+
.DS_Store
8+
build
9+
.externalNativeBuild

android/test_app/app/build.gradle

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
apply plugin: 'com.android.application'
2+
3+
repositories {
4+
jcenter()
5+
}
6+
7+
def props = new Properties()
8+
file("../gradle.properties").withInputStream { props.load(it) }
9+
10+
def buildConfigProps = { k -> "\"${props.get(k)}\"" }
11+
12+
android {
13+
compileSdkVersion 28
14+
buildToolsVersion "29.0.2"
15+
defaultConfig {
16+
applicationId "org.pytorch.testapp"
17+
minSdkVersion 21
18+
targetSdkVersion 28
19+
versionCode 1
20+
versionName "1.0"
21+
ndk {
22+
abiFilters ABI_FILTERS.split(",")
23+
}
24+
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME'))
25+
buildConfigField ("String", "LOGCAT_TAG", "@string/app_name")
26+
addManifestPlaceholders([APP_NAME: "@string/app_name"])
27+
}
28+
buildTypes {
29+
debug {
30+
minifyEnabled false
31+
}
32+
}
33+
flavorDimensions "model"
34+
productFlavors {
35+
mobNet2Quant {
36+
dimension "model"
37+
applicationIdSuffix ".mobNet2Quant"
38+
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_MOBNET2_QUANT'))
39+
addManifestPlaceholders([APP_NAME: "PyMobNet2Quant"])
40+
buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-mobnet2q\"")
41+
}
42+
resnet18 {
43+
dimension "model"
44+
applicationIdSuffix ".resneti18"
45+
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_RESNET18'))
46+
addManifestPlaceholders([APP_NAME: "PyResNet18"])
47+
buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-resnet18\"")
48+
}
49+
}
50+
packagingOptions {
51+
pickFirst '**/libfbjni.so'
52+
doNotStrip '**.so'
53+
}
54+
}
55+
56+
dependencies {
57+
implementation 'androidx.appcompat:appcompat:1.1.0'
58+
59+
implementation project(':pytorch_android')
60+
implementation project(':pytorch_android_torchvision')
61+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="org.pytorch.testapp">
4+
5+
<application
6+
android:allowBackup="true"
7+
android:label="${APP_NAME}"
8+
android:supportsRtl="true"
9+
android:theme="@style/AppTheme">
10+
11+
<activity android:name=".MainActivity">
12+
<intent-filter>
13+
<action android:name="android.intent.action.MAIN" />
14+
15+
<category android:name="android.intent.category.LAUNCHER" />
16+
</intent-filter>
17+
</activity>
18+
</application>
19+
</manifest>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*
2+
*/
3+
!.gitignore

0 commit comments

Comments
 (0)