Skip to content

Commit ae3eb51

Browse files
Krzysztof Parzyszekylc
authored andcommitted
[Hexagon] Implement model launcher (apache#8986)
* [Hexagon] Implement model launcher This implements a launcher that allows execution of ML models compiled into a shared library on Hexagon DSP. It consists of two parts: the Hexagon-side skel library and `launcher_android` to be used from `adb shell`. The launcher does not implement any performance-related optimizations, it's built on top of the `graph_executor` from TVM runtime, and so it executes a single layer at a time. This launcher should not be used to measure performance (because if will be highly suboptimal), its main purpose is to help in validating correctness. * Address review comments: explanations and elaborations in README.md * Rename cmake variables to be same as for TVM - `HEXAGON_SDK_ROOT` -> `USE_HEXAGON_SDK` - `HEXAGON_ARCH` -> `USE_HEXAGON_ARCH` * Address more review comments * Error out in cmake when USE_HEXAGON_SDK/USE_HEXAGON_ARCH are undefined * Change FATAL_ERROR to SEND_ERROR in cmake file
1 parent 45b0299 commit ae3eb51

File tree

11 files changed

+1320
-0
lines changed

11 files changed

+1320
-0
lines changed

cmake/modules/HexagonSDK.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ function(find_hexagon_sdk_root HEXAGON_SDK_PATH HEXAGON_ARCH)
7676
# - HEXAGON_SDK_VERSION
7777
# - HEXAGON_SDK_INCLUDES
7878
# - HEXAGON_QURT_INCLUDES
79+
# - HEXAGON_QURT_LIBS
7980
# - HEXAGON_RPCMEM_ROOT
8081
# - HEXAGON_REMOTE_ROOT
8182
# - HEXAGON_QAIC_EXE
@@ -95,6 +96,8 @@ function(find_hexagon_sdk_root HEXAGON_SDK_PATH HEXAGON_ARCH)
9596
set_parent(HEXAGON_QURT_INCLUDES
9697
"${HEXAGON_SDK_ROOT}/libs/common/qurt/${HEXARCH_DIR}/include/posix"
9798
"${HEXAGON_SDK_ROOT}/libs/common/qurt/${HEXARCH_DIR}/include/qurt")
99+
set_parent(HEXAGON_QURT_LIBS
100+
"${HEXAGON_SDK_ROOT}/libs/common/qurt/${HEXARCH_DIR}/lib")
98101
set_parent(HEXAGON_RPCMEM_ROOT "${HEXAGON_SDK_ROOT}/libs/common/rpcmem")
99102
set_parent(HEXAGON_REMOTE_ROOT
100103
"${HEXAGON_SDK_ROOT}/libs/common/remote/ship/android_Release_aarch64")
@@ -111,6 +114,8 @@ function(find_hexagon_sdk_root HEXAGON_SDK_PATH HEXAGON_ARCH)
111114
set_parent(HEXAGON_QURT_INCLUDES
112115
"${HEXAGON_SDK_ROOT}/rtos/qurt/${HEXARCH_DIR}/include/posix"
113116
"${HEXAGON_SDK_ROOT}/rtos/qurt/${HEXARCH_DIR}/include/qurt")
117+
set_parent(HEXAGON_QURT_LIBS
118+
"${HEXAGON_SDK_ROOT}/rtos/qurt/${HEXARCH_DIR}/lib/pic")
114119
set_parent(HEXAGON_RPCMEM_ROOT "${HEXAGON_SDK_ROOT}/ipc/fastrpc/rpcmem")
115120
set_parent(HEXAGON_REMOTE_ROOT # libadsprpc.so
116121
"${HEXAGON_SDK_ROOT}/ipc/fastrpc/remote/ship/android_aarch64")
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
cmake_minimum_required(VERSION 3.2)
19+
project(HexagonLauncher C CXX)
20+
21+
if(NOT "${FASTRPC_LIBS}" STREQUAL "SKEL" AND
22+
NOT "${FASTRPC_LIBS}" STREQUAL "STUB")
23+
message(SEND_ERROR "Please set FASTRPC_LIBS to either SKEL or STUB")
24+
endif()
25+
26+
if(NOT DEFINED USE_HEXAGON_SDK)
27+
message(SEND_ERROR "Please set USE_HEXAGON_SDK to the location of Hexagon SDK")
28+
endif()
29+
if (NOT DEFINED USE_HEXAGON_ARCH)
30+
message(SEND_ERROR "Please set USE_HEXAGON_ARCH to the Hexagon architecture version")
31+
endif()
32+
33+
include(../../../../cmake/modules/HexagonSDK.cmake)
34+
35+
find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}")
36+
37+
include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_REMOTE_ROOT})
38+
39+
set(QAIC_EXE "${HEXAGON_QAIC_EXE}")
40+
foreach(INCDIR IN LISTS HEXAGON_SDK_INCLUDES HEXAGON_REMOTE_ROOT)
41+
list(APPEND QAIC_FLAGS "-I${INCDIR}")
42+
endforeach()
43+
44+
set(LAUNCHER_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
45+
set(CMAKE_SKIP_RPATH TRUE)
46+
47+
# Qaic for the domain header.
48+
#
49+
# Don't add paths to these filenames, or otherwise cmake may spontaneously
50+
# add -o option to the qaic invocation (with an undesirable path).
51+
set(LAUNCHER_RPC_IDL "launcher_rpc.idl")
52+
set(LAUNCHER_RPC_H "launcher_rpc.h")
53+
set(LAUNCHER_RPC_SKEL_C "launcher_rpc_skel.c")
54+
set(LAUNCHER_RPC_STUB_C "launcher_rpc_stub.c")
55+
56+
add_custom_command(
57+
OUTPUT ${LAUNCHER_RPC_SKEL_C} ${LAUNCHER_RPC_STUB_C}
58+
"${LAUNCHER_SRC}/${LAUNCHER_RPC_H}"
59+
COMMAND ${QAIC_EXE} ${QAIC_FLAGS}
60+
"${LAUNCHER_SRC}/${LAUNCHER_RPC_IDL}"
61+
COMMAND ${CMAKE_COMMAND} -E rename "${LAUNCHER_RPC_H}"
62+
"${LAUNCHER_SRC}/${LAUNCHER_RPC_H}"
63+
MAIN_DEPENDENCY "${LAUNCHER_SRC}/${LAUNCHER_RPC_IDL}"
64+
)
65+
66+
67+
if("${FASTRPC_LIBS}" STREQUAL "SKEL")
68+
# Skel libraries.
69+
#
70+
if (NOT DEFINED TVM_RUNTIME_HEXAGON)
71+
message(SEND_ERROR "Please set TVM_RUNTIME_HEXAGON=/path/to/libtvm_runtime.a")
72+
endif()
73+
74+
include_directories(SYSTEM ${HEXAGON_QURT_INCLUDES})
75+
include_directories(
76+
"${LAUNCHER_SRC}"
77+
"${LAUNCHER_SRC}/../../../../include"
78+
"${LAUNCHER_SRC}/../../../../3rdparty/dlpack/include"
79+
"${LAUNCHER_SRC}/../../../../3rdparty/dmlc-core/include"
80+
)
81+
link_directories(${HEXAGON_QURT_LIBS})
82+
83+
add_definitions(-D_MACH_I32=int)
84+
add_definitions(-DDMLC_CXX11_THREAD_LOCAL=0)
85+
add_definitions(-DDMLC_USE_LOGGING_LIBRARY=<tvm/runtime/logging.h>)
86+
87+
# Extra compile flags (both C and C++).
88+
set(EXTRA_COMP_FLAGS
89+
"-O3"
90+
"-m${USE_HEXAGON_ARCH}"
91+
)
92+
string(REGEX REPLACE ";" " " EXTRA_COMP_FLAGS_STR "${EXTRA_COMP_FLAGS}")
93+
set(CMAKE_C_FLAGS "${EXTRA_COMP_FLAGS_STR} ${CMAKE_C_FLAGS}")
94+
set(CMAKE_CXX_FLAGS "${EXTRA_COMP_FLAGS_STR} ${CMAKE_CXX_FLAGS}")
95+
96+
set(EXTRA_LINK_FLAGS
97+
"-lposix"
98+
"-lqurt"
99+
"-Wl,--export-dynamic"
100+
"-Wl,--whole-archive ${TVM_RUNTIME_HEXAGON} -Wl,--no-whole-archive"
101+
"-Wl,--defsym=HEAP_SIZE=0x40000000"
102+
)
103+
string(REGEX REPLACE ";" " " EXTRA_LINK_FLAGS_STR "${EXTRA_LINK_FLAGS}")
104+
105+
set(SKEL_SRCS
106+
"launcher_core.cc"
107+
"launcher_hexagon.cc"
108+
)
109+
add_library(launcher_rpc_skel SHARED
110+
"${LAUNCHER_SRC}/${LAUNCHER_RPC_H}"
111+
"${LAUNCHER_RPC_SKEL_C}"
112+
"${SKEL_SRCS}"
113+
)
114+
115+
# Extra linker flags for linking shared libraries.
116+
set_target_properties(launcher_rpc_skel PROPERTIES
117+
LINK_FLAGS ${EXTRA_LINK_FLAGS_STR}
118+
)
119+
else()
120+
# Stub libraries.
121+
#
122+
if (NOT DEFINED TVM_RUNTIME_ANDROID)
123+
message(SEND_ERROR "Please set TVM_RUNTIME_ANDROID=/path/to/libtvm_runtime.so")
124+
endif()
125+
126+
include_directories(SYSTEM
127+
"${HEXAGON_SDK_INCLUDES}"
128+
"${HEXAGON_RPCMEM_ROOT}/inc"
129+
)
130+
include_directories(
131+
"${LAUNCHER_SRC}"
132+
"${LAUNCHER_SRC}/../../../../include"
133+
"${LAUNCHER_SRC}/../../../../3rdparty/dlpack/include"
134+
"${LAUNCHER_SRC}/../../../../3rdparty/dmlc-core/include"
135+
)
136+
link_directories(${HEXAGON_REMOTE_ROOT})
137+
138+
add_definitions(-DDMLC_USE_LOGGING_LIBRARY=<tvm/runtime/logging.h>)
139+
140+
set(STUB_SRCS
141+
"launcher_android.cc"
142+
"launcher_core.cc"
143+
"launcher_main.cc"
144+
"launcher_util.cc"
145+
)
146+
147+
add_executable(launcher_android
148+
"${STUB_SRCS}"
149+
"${LAUNCHER_RPC_STUB_C}"
150+
)
151+
target_link_libraries(launcher_android cdsprpc log)
152+
153+
set_target_properties(launcher_android PROPERTIES
154+
LINK_FLAGS "${TVM_RUNTIME_ANDROID}"
155+
)
156+
endif()
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<!--- Licensed to the Apache Software Foundation (ASF) under one -->
2+
<!--- or more contributor license agreements. See the NOTICE file -->
3+
<!--- distributed with this work for additional information -->
4+
<!--- regarding copyright ownership. The ASF licenses this file -->
5+
<!--- to you under the Apache License, Version 2.0 (the -->
6+
<!--- "License"); you may not use this file except in compliance -->
7+
<!--- with the License. You may obtain a copy of the License at -->
8+
9+
<!--- http://www.apache.org/licenses/LICENSE-2.0 -->
10+
11+
<!--- Unless required by applicable law or agreed to in writing, -->
12+
<!--- software distributed under the License is distributed on an -->
13+
<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
14+
<!--- KIND, either express or implied. See the License for the -->
15+
<!--- specific language governing permissions and limitations -->
16+
<!--- under the License. -->
17+
# Hexagon Graph Launcher
18+
19+
## Compilation
20+
21+
The launcher consists of two parts: part running on Hexagon, and part running
22+
on Android. They need to be compiled separately. Since some source files are
23+
shared between these two parts, make sure to delete all object files between
24+
compilations. Compile the Hexagon code first.
25+
26+
The supported Snapdragon architectures are 855, 865, and 888.
27+
28+
### Prerequisites
29+
30+
1. Android NDK version r19c or later.
31+
2. Hexagon SDK version 4.0.0 or later.
32+
33+
Android NDK can be downloaded from https://developer.android.com/ndk.
34+
Hexagon SDK is available at //developer.qualcomm.com/software/hexagon-dsp-sdk.
35+
36+
### Compilation of the Hexagon part
37+
38+
1. Build the static version of TVM runtime for Hexagon. Use Hexagon clang
39+
from the Hexagon SDK. This step is the same as building the shared version,
40+
except at the cmake step, add `-DBUILD_STATIC_RUNTIME=ON`. The compilation
41+
step should create `libtvm_runtime.a`.
42+
43+
2. Create a subdirectory for the build files, and run `cmake` with the
44+
following variables set:
45+
- `FASTRPC_LIBS=SKEL`
46+
- `USE_HEXAGON_SDK` to the path to the Hexagon SDK
47+
- `CMAKE_C_COMPILER=hexagon-clang`
48+
- `CMAKE_CXX_COMPILER=hexagon-clang++`
49+
- `USE_HEXAGON_ARCH` to one of v65, v66, v68
50+
- `TVM_RUNTIME_HEXAGON=/path/to/libtvm_runtime.a` _statically_ linked
51+
TVM runtime
52+
53+
Make sure to provide the path to launcher's `CMakeLists.txt` directory
54+
in `cmake` invocation.
55+
56+
3. Run `make`. This will create `liblauncher_rpc_skel.so`.
57+
58+
### Compilation of the Android part
59+
60+
1. Build TVM runtime for Android, using clang for AArch64 from the Android
61+
NDK. Unlike in the Hexagon case, this should be the dynamic library (which
62+
is the default), i.e. `libtvm_runtime.so`.
63+
64+
2. Create a subdirectory for the build files (different from the one used for
65+
Hexagon files), and run `cmake` with the following variables set:
66+
- `FASTRPC_LIBS=STUB`
67+
- `USE_HEXAGON_SDK` to the path to the Hexagon SDK
68+
- `CMAKE_C_COMPILER=aarch64-linux-android28-clang` (or later)
69+
- `CMAKE_CXX_COMPILER=aarch64-linux-android28-clang++` (or later)
70+
- `USE_HEXAGON_ARCH` to one of v65, v66, v68 (same as for the Hexagon part)
71+
- `TVM_RUNTIME_ANDROID=/path/to/libtvm_runtime.so` dynamically or
72+
statically linked TVM runtime
73+
74+
3. Run `make`. This will create `launcher_android`.
75+
76+
## Execution
77+
78+
From the Android shell, do
79+
```
80+
./launcher_android --in_config input.json --out_config output.json
81+
```
82+
83+
You may need to add the location of `libtvm_runtime.so` to `LD_LIBRARY_PATH`.
84+
See below for more information about the setup and launcher's inputs.
85+
86+
### Preparation steps
87+
88+
Copy the following binaries to the device:
89+
- `liblauncher_rpc_skel.so`: created by the compilation step for Hexagon,
90+
- `libgcc.so`: take this one from the Hexagon toolchain,
91+
- `launcher_android`: created by the compilation step for Android,
92+
- `libtvm_runtime.so`: built for Android.
93+
94+
These are only the binaries related to the launcher itself. To run a model
95+
copy the shared object with the model and the model JSON file over to the
96+
device (both are obtained from relay). Also, copy all input files for the
97+
model as well.
98+
99+
The following snippet illustrates how to obtain the shared object and the
100+
JSON file from a TFLite model (using Inception V3 as an example):
101+
102+
```
103+
# Skipped imports, etc.
104+
105+
with open("inception_v3.tflite", "rb") as f:
106+
tflite_model_buf = f.read()
107+
tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buf, 0)
108+
109+
shape_dict = { "input": [1,299,299,3] }
110+
dtype_dict = { "input": "float32" }
111+
112+
mod, params = relay.frontend.from_tflite(
113+
tflite_model, shape_dict=shape_dict, dtype_dict=dtype_dict
114+
)
115+
116+
target = tvm.target.hexagon('v68', link_params=True)
117+
with tvm.transform.PassContext(opt_level=3):
118+
lib = relay.build(mod, target, target_host=target, params=params, mod_name="default")
119+
120+
# Save model.so and model.json:
121+
with open('model.json', 'w') as f:
122+
f.write(lib.get_graph_json())
123+
lib.get_lib().save('model.so')
124+
```
125+
126+
The final thing is to prepare a JSON configuration file for the launcher.
127+
The JSON has two attributes describing the model: `model-library` and
128+
`model-json`, and an attribute `inputs`, which is a list of records, one
129+
for each input file.
130+
An input file record has three attributes: `file`, `shape`, and `dtype`.
131+
132+
Below is an example of the input config file for Inception V3:
133+
```
134+
{
135+
"model-library": "inceptionv3-float32.so",
136+
"model-json": "inceptionv3-float32.json",
137+
"inputs" : [
138+
{
139+
"file": "panda_299x299_fp.dat",
140+
"shape": [1,299,299,3],
141+
"dtype": "float32"
142+
}
143+
]
144+
}
145+
```
146+
147+
The launcher will then create the output JSON file (with the name given via
148+
`--out_config`) containing information about the execution time and the model
149+
outputs. The output JSON file has three attributes: "pcycles", "usecs" that
150+
contain the execution duration in terms of processor cycles and microseconds
151+
respectivaly, and an attribute `outputs`, which is a list of output file records
152+
whose syntax is identical to the input file records in the input file.
153+
A sample output JSON from running the Inception V3 model may look like
154+
```
155+
{
156+
"pcycles": 112965680178,
157+
"usecs": 79532302,
158+
"outputs": [
159+
{
160+
"file": "output0.dat",
161+
"shape": [1, 1001],
162+
"dtype": "float32"
163+
}
164+
]
165+
}
166+
```
167+
168+
# Disclaimer
169+
170+
The launcher does not perform any correctness verification. In order to verify
171+
correctness, the user needs to copy the output files from the device and
172+
verify their contents.
173+
174+
This launcher is intended for use with prototyping and does not utilize any
175+
performance acceleration, as such the measured performance may be very poor.

0 commit comments

Comments
 (0)