Skip to content

Commit dcebd4d

Browse files
authored
[CI][Hexagon] Add Hexagon Tests to pipeline (#10302)
* Add hexagon tests to CI Hexagon * Fix CRT libs * cleanup and fix Jenkins * Address @areusch comments
1 parent 6c6e873 commit dcebd4d

File tree

7 files changed

+95
-112
lines changed

7 files changed

+95
-112
lines changed

Jenkinsfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ ci_wasm = "tlcpack/ci-wasm:v0.71"
5252
ci_i386 = "tlcpack/ci-i386:v0.74"
5353
ci_qemu = "tlcpack/ci-qemu:v0.10"
5454
ci_arm = "tlcpack/ci-arm:v0.07"
55+
ci_hexagon = "tlcpack/ci-hexagon:v0.01"
5556
// <--- End of regex-scanned config.
5657

5758
// Parameters to allow overriding (in Jenkins UI), the images
@@ -381,6 +382,34 @@ stage('Build') {
381382
} else {
382383
Utils.markStageSkippedForConditional('BUILD: QEMU')
383384
}
385+
},
386+
'BUILD: Hexagon': {
387+
if (!skip_ci && is_docs_only_build != 1) {
388+
node('CPU') {
389+
ws(per_exec_ws('tvm/build-hexagon')) {
390+
init_git()
391+
sh (
392+
script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_config_build_hexagon.sh",
393+
label: 'Create Hexagon cmake config',
394+
)
395+
try {
396+
make(ci_hexagon, 'build', '-j2')
397+
sh (
398+
script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_build_hexagon_api.sh",
399+
label: 'Build Hexagon API',
400+
)
401+
sh (
402+
script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_python_hexagon.sh",
403+
label: 'Run Hexagon tests',
404+
)
405+
} finally {
406+
junit 'build/pytest-results/*.xml'
407+
}
408+
}
409+
}
410+
} else {
411+
Utils.markStageSkippedForConditional('BUILD: Hexagon')
412+
}
384413
}
385414
}
386415

tests/python/contrib/test_hexagon/conftest.py

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
HEXAGON_TOOLCHAIN = "HEXAGON_TOOLCHAIN"
2828
TVM_TRACKER_HOST = "TVM_TRACKER_HOST"
2929
TVM_TRACKER_PORT = "TVM_TRACKER_PORT"
30-
ANDROID_TRACKER_KEY = "ANDROID_TRACKER_KEY"
3130
ANDROID_REMOTE_DIR = "ANDROID_REMOTE_DIR"
31+
ANDROID_SERIAL_NUMBER = "ANDROID_SERIAL_NUMBER"
3232

3333

3434
@tvm.testing.fixture
@@ -49,83 +49,26 @@ def _compose(args, decs):
4949
def requires_hexagon_toolchain(*args):
5050
_requires_hexagon_toolchain = [
5151
pytest.mark.skipif(
52-
os.environ.get("HEXAGON_TOOLCHAIN") == None,
53-
reason="HEXAGON_TOOLCHAIN environment variable is required to run this test.",
52+
os.environ.get(HEXAGON_TOOLCHAIN) == None,
53+
reason=f"Missing environment variable {HEXAGON_TOOLCHAIN}.",
5454
),
5555
]
5656

5757
return _compose(args, _requires_hexagon_toolchain)
5858

5959

6060
@tvm.testing.fixture
61-
def android_tracker_key():
62-
return os.environ["ANDROID_TRACKER_KEY"]
61+
def android_serial_number():
62+
return os.getenv(ANDROID_SERIAL_NUMBER, default=None)
6363

6464

6565
@tvm.testing.fixture
6666
def tvm_tracker_host():
67-
return os.environ["TVM_TRACKER_HOST"]
67+
return os.getenv(TVM_TRACKER_HOST, default=None)
6868

6969

7070
@tvm.testing.fixture
7171
def tvm_tracker_port():
72-
return int(os.environ["TVM_TRACKER_PORT"])
73-
74-
75-
@tvm.testing.fixture
76-
def remote_path():
77-
dso_binary = "test_binary.so"
78-
return os.path.join(os.environ["ANDROID_REMOTE_DIR"], dso_binary)
79-
80-
81-
@tvm.testing.fixture
82-
def rpc_sess(android_tracker_key, tvm_tracker_host, tvm_tracker_port):
83-
from tvm import rpc
84-
85-
tracker = rpc.connect_tracker(tvm_tracker_host, tvm_tracker_port)
86-
remote = tracker.request(android_tracker_key, priority=0, session_timeout=600)
87-
return remote
88-
89-
90-
def requires_rpc_tracker_and_android_key(*args):
91-
"""Mark a test as requiring an RPC tracker to exist in
92-
the host environment to run."""
93-
_requires_rpc_tracker = [
94-
*tvm.testing.requires_rpc(),
95-
pytest.mark.skipif(
96-
os.environ.get(TVM_TRACKER_HOST) == None,
97-
reason="Missing environment variable, TVM_TRACKER_HOST",
98-
),
99-
pytest.mark.skipif(
100-
os.environ.get(TVM_TRACKER_PORT) == None,
101-
reason="Missing environment variable, TVM_TRACKER_PORT",
102-
),
103-
pytest.mark.skipif(
104-
os.environ.get(ANDROID_TRACKER_KEY) == None,
105-
reason="Missing environment variable, ANDROID_TRACKER_KEY",
106-
),
107-
pytest.mark.skipif(
108-
os.environ.get(ANDROID_REMOTE_DIR) == None,
109-
reason="Missing environment variable, ANDROID_REMOTE_DIR",
110-
),
111-
]
112-
113-
return _compose(args, _requires_rpc_tracker)
114-
115-
116-
def requires_rpc_tracker(*args):
117-
"""Mark a test as requiring an RPC tracker to exist in
118-
the host environment to run."""
119-
_requires_rpc_tracker = [
120-
*tvm.testing.requires_rpc(),
121-
pytest.mark.skipif(
122-
os.environ.get("TVM_TRACKER_HOST") == None,
123-
reason="Missing environment variable, TVM_TRACKER_HOST",
124-
),
125-
pytest.mark.skipif(
126-
os.environ.get("TVM_TRACKER_PORT") == None,
127-
reason="Missing environment variable, TVM_TRACKER_PORT",
128-
),
129-
]
130-
131-
return _compose(args, _requires_rpc_tracker)
72+
port = os.getenv(TVM_TRACKER_PORT, default=None)
73+
port = int(port) if port else None
74+
return port

tests/python/contrib/test_hexagon/rpc/conftest.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

tests/python/contrib/test_hexagon/rpc/test_launcher.md renamed to tests/python/contrib/test_hexagon/test_launcher.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
HexagonLauncher is a class to handle interactions with an Android phone which includes Hexagon DSP to run a TVMModule(function/operation/graph) on Hexagon. HexagonLauncher reuses minRPC implementation to setup an RPC connection from host (your local machine) to Hexagon target which is passed through Android RPC server.
2020

2121
## Build Required Tools/Libraries
22-
Here are the steps that are taken to prepare a runtime on a Hexagon device to test any model.
22+
To build TVM for Hexagon and run tests you can follow these steps to prepare a runtime on a Hexagon device to test any model. Alternatively, you can skip these instructions and use docker image which has pre-installed required tools. Instructions for using docker image [here](#use-hexagon-docker-image).
2323

2424
- Build TVMRuntime library and C++ RPC server for Android.
2525
- Build minRPC server along with FastRPC for Hexagon.
2626
- Build TVM library with Hexagon support for host machine.
27-
- Build TVMRuntime library and C++ RPC server for host machine.
27+
- Build TVMRuntime library and RPC server for host machine.
2828

2929
Note: First, ensure to export Clang libraries to `LD_LIBRARY_PATH` and Hexagon toolchain to `HEXAGON_TOOLCHAIN`:
3030

@@ -58,14 +58,33 @@ cd tvm
5858
mkdir build
5959
cd build
6060
cmake -DUSE_LLVM="path to `llvm/bin/llvm-config`" \
61-
-DUSE_CPP_RPC=ON \
61+
-DUSE_RPC=ON \
6262
-DCMAKE_CXX_COMPILER="path to `clang++` executable" \
6363
-DCMAKE_CXX_FLAGS='-stdlib=libc++' \
6464
-DUSE_HEXAGON_SDK="path to Hexagon SDK" \
6565
-DUSE_HEXAGON_ARCH="choose from v65|v66|v68" \
6666
-DUSE_HEXAGON_DEVICE=sim ..
6767
```
6868

69+
## Use Hexagon Docker Image
70+
To use this docker image, install TVM and tools follow these steps.
71+
72+
```bash
73+
# Log in to docker image
74+
cd tvm
75+
./docker/bash.sh tlcpack/ci-hexagon:v0.01
76+
77+
# Build TVM
78+
./tests/scripts/task_config_build_hexagon.sh
79+
cd build
80+
cmake ..
81+
make -j2
82+
83+
# Build Hexagon API
84+
cd ..
85+
./tests/scripts/task_build_hexagon_api.sh
86+
```
87+
6988
## Testing Using HexagonLauncher
7089
Before starting a test you need to run an RPC tracker on your local machine and export HOST and PORT as environment variables. Also, you need to export Clang libraries to `LD_LIBRARY_PATH` and Hexagon toolchain to `HEXAGON_TOOLCHAIN` as explained above.
7190

tests/python/contrib/test_hexagon/rpc/test_launcher.py renamed to tests/python/contrib/test_hexagon/test_launcher.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import sys
1919
import pytest
2020
import numpy as np
21-
import os
21+
import logging
2222

2323
import tvm.testing
2424
from tvm import te
@@ -28,12 +28,11 @@
2828
from tvm.contrib.hexagon.build import HexagonLauncher
2929
import tvm.contrib.hexagon.hexagon as hexagon
3030

31-
from ..conftest import requires_rpc_tracker, requires_hexagon_toolchain
31+
from .conftest import requires_hexagon_toolchain
3232

3333

34-
@requires_rpc_tracker
3534
@requires_hexagon_toolchain
36-
def test_add(tvm_tracker_host, tvm_tracker_port, android_serial_number):
35+
def test_add(android_serial_number, tvm_tracker_host, tvm_tracker_port):
3736
dtype = "int8"
3837
A = tvm.te.placeholder((2,), dtype=dtype)
3938
B = tvm.te.placeholder((1,), dtype=dtype)
@@ -50,6 +49,9 @@ def test_add(tvm_tracker_host, tvm_tracker_port, android_serial_number):
5049
dso_binary_path = temp.relpath(dso_binary)
5150
func.save(dso_binary_path)
5251

52+
if not android_serial_number:
53+
pytest.skip("Skip hardware test since ANDROID_SERIAL_NUMBER is not set.")
54+
5355
launcher = HexagonLauncher(serial_number=android_serial_number)
5456
launcher.android_run_rpc(rpc_tracker_host=tvm_tracker_host, rpc_tracker_port=tvm_tracker_port)
5557
launcher.hexagon_setup()
@@ -76,9 +78,8 @@ def test_add(tvm_tracker_host, tvm_tracker_port, android_serial_number):
7678
launcher.close()
7779

7880

79-
@requires_rpc_tracker
8081
@requires_hexagon_toolchain
81-
def test_add_vtcm(tvm_tracker_host, tvm_tracker_port, android_serial_number):
82+
def test_add_vtcm(android_serial_number, tvm_tracker_host, tvm_tracker_port):
8283
dtype = "int8"
8384
A = tvm.te.placeholder((2,), dtype=dtype)
8485
B = tvm.te.placeholder((1,), dtype=dtype)
@@ -95,6 +96,9 @@ def test_add_vtcm(tvm_tracker_host, tvm_tracker_port, android_serial_number):
9596
dso_binary_path = temp.relpath(dso_binary)
9697
func.save(dso_binary_path)
9798

99+
if not android_serial_number:
100+
pytest.skip("Skip hardware test since ANDROID_SERIAL_NUMBER is not set.")
101+
98102
launcher = HexagonLauncher(serial_number=android_serial_number)
99103
launcher.android_run_rpc(rpc_tracker_host=tvm_tracker_host, rpc_tracker_port=tvm_tracker_port)
100104
launcher.hexagon_setup()
@@ -129,9 +133,8 @@ class TestMatMul:
129133
N = tvm.testing.parameter(32)
130134
K = tvm.testing.parameter(32)
131135

132-
@requires_rpc_tracker
133136
@requires_hexagon_toolchain
134-
def test_matmul(self, tvm_tracker_host, tvm_tracker_port, android_serial_number, M, N, K):
137+
def test_matmul(self, android_serial_number, tvm_tracker_host, tvm_tracker_port, M, N, K):
135138
X = te.placeholder((M, K), dtype="float32")
136139
Y = te.placeholder((K, N), dtype="float32")
137140
k1 = te.reduce_axis((0, K), name="k1")
@@ -148,6 +151,9 @@ def test_matmul(self, tvm_tracker_host, tvm_tracker_port, android_serial_number,
148151
dso_binary_path = temp.relpath(dso_binary)
149152
func.save(dso_binary_path)
150153

154+
if not android_serial_number:
155+
pytest.skip("Skip hardware test since ANDROID_SERIAL_NUMBER is not set.")
156+
151157
launcher = HexagonLauncher(serial_number=android_serial_number)
152158
launcher.android_run_rpc(
153159
rpc_tracker_host=tvm_tracker_host, rpc_tracker_port=tvm_tracker_port
@@ -185,9 +191,8 @@ def test_matmul(self, tvm_tracker_host, tvm_tracker_port, android_serial_number,
185191
tvm.testing.assert_allclose(zt.numpy(), ztcpu.numpy(), rtol=1e-4)
186192

187193

188-
@requires_rpc_tracker
189194
@requires_hexagon_toolchain
190-
def test_graph_executor(tvm_tracker_host, tvm_tracker_port, android_serial_number):
195+
def test_graph_executor(android_serial_number, tvm_tracker_host, tvm_tracker_port):
191196
dtype = "float32"
192197
data = relay.var("data", relay.TensorType((1, 64, 64, 3), dtype))
193198
weight = relay.var("weight", relay.TensorType((5, 5, 3, 8), dtype))
@@ -221,6 +226,9 @@ def test_graph_executor(tvm_tracker_host, tvm_tracker_port, android_serial_numbe
221226
)
222227
lowered.get_lib().save(dso_binary_path)
223228

229+
if not android_serial_number:
230+
pytest.skip("Skip hardware test since ANDROID_SERIAL_NUMBER is not set.")
231+
224232
launcher = HexagonLauncher(serial_number=android_serial_number)
225233
launcher.android_run_rpc(rpc_tracker_host=tvm_tracker_host, rpc_tracker_port=tvm_tracker_port)
226234
launcher.hexagon_setup()

tests/scripts/task_config_build_hexagon.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@ mkdir -p build
2323
cd build
2424
cp ../cmake/config.cmake .
2525

26+
echo set\(USE_SORT ON\) >> config.cmake
27+
echo set\(USE_RPC ON\) >> config.cmake
28+
echo set\(USE_MICRO ON\) >> config.cmake
29+
echo set\(USE_MICRO_STANDALONE_RUNTIME ON\) >> config.cmake
2630
echo set\(USE_LLVM "${CLANG_LLVM_HOME}/bin/llvm-config"\) >> config.cmake
27-
echo set\(USE_CPP_RPC ON\) >> config.cmake
2831
echo set\(CMAKE_CXX_COMPILER "${CLANG_LLVM_HOME}/bin/clang++"\) >> config.cmake
2932
echo set\(USE_HEXAGON_SDK "${HEXAGON_SDK_PATH}"\) >> config.cmake
3033
echo set\(USE_HEXAGON_ARCH "v68"\) >> config.cmake
3134
echo set\(USE_HEXAGON_DEVICE "sim"\) >> config.cmake
35+
echo set\(USE_CCACHE OFF\) >> config.cmake
36+
echo set\(SUMMARIZE ON\) >> config.cmake

tests/python/contrib/test_hexagon/rpc/__init__.py renamed to tests/scripts/task_python_hexagon.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env bash
12
# Licensed to the Apache Software Foundation (ASF) under one
23
# or more contributor license agreements. See the NOTICE file
34
# distributed with this work for additional information
@@ -15,4 +16,13 @@
1516
# specific language governing permissions and limitations
1617
# under the License.
1718

18-
""" Testing infrastructure for Hexagon RPC"""
19+
set -e
20+
set -u
21+
22+
source tests/scripts/setup-pytest-env.sh
23+
24+
make cython3
25+
26+
# unset because hardware does not exist in CI.
27+
unset ANDROID_SERIAL_NUMBER
28+
run_pytest ctypes python-contrib-hexagon-no-hwardware tests/python/contrib/test_hexagon/test_launcher.py

0 commit comments

Comments
 (0)