This is an automated email from the ASF dual-hosted git repository.

masahi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 7cfaa88  [Hexagon] Enable running CI tests via simulator (#10473)
7cfaa88 is described below

commit 7cfaa88e6c18edc0a41e1a984d3cb9d8659a1c2c
Author: Krzysztof Parzyszek <[email protected]>
AuthorDate: Sat Mar 5 15:11:12 2022 -0600

    [Hexagon] Enable running CI tests via simulator (#10473)
---
 Jenkinsfile                                        |  4 ++
 python/tvm/contrib/hexagon/hexagon.py              |  4 +-
 tests/python/contrib/test_hexagon/conftest.py      | 15 +++++++
 tests/python/contrib/test_hexagon/test_launcher.py | 51 +++++++++++++++++-----
 tests/scripts/task_python_hexagon_simulator.sh     | 40 +++++++++++++++++
 5 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 6550be0..9d38a0e 100755
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -442,6 +442,10 @@ stage('Build') {
               script: "${docker_run} ${ci_hexagon} 
./tests/scripts/task_python_hexagon.sh",
               label: 'Run Hexagon tests',
             )
+            sh (
+              script: "${docker_run} ${ci_hexagon} 
./tests/scripts/task_python_hexagon_simulator.sh",
+              label: 'Run Hexagon tests on simulator',
+            )
           } finally {
             junit 'build/pytest-results/*.xml'
           }
diff --git a/python/tvm/contrib/hexagon/hexagon.py 
b/python/tvm/contrib/hexagon/hexagon.py
index 1e4d85d..9790746 100644
--- a/python/tvm/contrib/hexagon/hexagon.py
+++ b/python/tvm/contrib/hexagon/hexagon.py
@@ -268,6 +268,7 @@ def ir_lower_vtcm_pass():
 
 def create_aot_shared(so_name: Union[str, pathlib.Path], files, hexagon_arch: 
str, options=None):
     """Export Hexagon AOT module."""
+    options = options or []
     if not os.access(str(HEXAGON_CLANG_PLUS), os.X_OK):
         raise Exception(
             'The Clang++ "' + str(HEXAGON_CLANG_PLUS) + '" does not exist or 
is not executable.'
@@ -286,6 +287,7 @@ def create_aot_shared(so_name: Union[str, pathlib.Path], 
files, hexagon_arch: st
     tvm_dir = pathlib.Path(os.path.dirname(os.path.realpath(__file__))) / ".." 
/ ".." / ".." / ".."
     compute_arch = f"compute{hexagon_arch}"
     compile_options = [
+        f"-O3",
         f"-I{tvm_dir / 'include'}",
         f"-I{tvm_dir / '3rdparty' / 'dlpack' / 'include'}",
         f"-I{tvm_dir / '3rdparty' / 'dmlc-core' / 'include'}",
@@ -302,4 +304,4 @@ def create_aot_shared(so_name: Union[str, pathlib.Path], 
files, hexagon_arch: st
     cross_compile = cc.cross_compiler(compile_func=hexagon_clang_plus())
     cross_compile.output_format = "o"
     c_files = [str(file) for file in files]
-    cross_compile(str(so_name), c_files, options=compile_options)
+    cross_compile(str(so_name), c_files, options=compile_options + options)
diff --git a/tests/python/contrib/test_hexagon/conftest.py 
b/tests/python/contrib/test_hexagon/conftest.py
index 5c67763..2f2c570 100644
--- a/tests/python/contrib/test_hexagon/conftest.py
+++ b/tests/python/contrib/test_hexagon/conftest.py
@@ -78,3 +78,18 @@ def tvm_tracker_port() -> int:
 @tvm.testing.fixture
 def adb_server_socket() -> str:
     return os.getenv(ADB_SERVER_SOCKET, default="tcp:5037")
+
+
+# If the execution aborts while an RPC server is running, the python
+# code that is supposed to shut it dowm will never execute. This will
+# keep pytest from terminating (indefinitely), so add a cleanup
+# fixture to terminate any still-running servers.
[email protected](scope="session", autouse=True)
+def terminate_rpc_servers():
+    # Since this is a fixture that runs regardless of whether the
+    # execution happens on simulator or on target, make sure the
+    # yield happens every time.
+    serial = os.environ.get(ANDROID_SERIAL_NUMBER)
+    yield []
+    if serial == "simulator":
+        os.system("ps ax | grep tvm_rpc_x86 | awk '{print $1}' | xargs kill")
diff --git a/tests/python/contrib/test_hexagon/test_launcher.py 
b/tests/python/contrib/test_hexagon/test_launcher.py
index b7277ce..e9ddc50 100644
--- a/tests/python/contrib/test_hexagon/test_launcher.py
+++ b/tests/python/contrib/test_hexagon/test_launcher.py
@@ -15,6 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import os
 import pathlib
 import sys
 import pytest
@@ -33,6 +34,12 @@ from .conftest import requires_hexagon_toolchain
 
 RPC_SERVER_PORT = 7070
 
+# NOTE on server ports:
+# These tests use different port numbers for the RPC server (7070 + ...).
+# The reason is that an RPC session cannot be gracefully closed without
+# triggering TIME_WAIT state on the server socket. This prevents another
+# server to bind to the same port until the wait time elapses.
+
 
 @requires_hexagon_toolchain
 def test_add(android_serial_number, tvm_tracker_host, tvm_tracker_port, 
adb_server_socket):
@@ -58,7 +65,7 @@ def test_add(android_serial_number, tvm_tracker_host, 
tvm_tracker_port, adb_serv
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 0,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -73,9 +80,9 @@ def test_add(android_serial_number, tvm_tracker_host, 
tvm_tracker_port, adb_serv
         assert (B_data.numpy() == np.array([4])).all()
         C_data = tvm.nd.array(np.array([0, 0], dtype=dtype), 
device=sess.device)
         assert (C_data.numpy() == np.array([0, 0])).all()
-
         mod["add"](A_data, B_data, C_data)
         assert (C_data.numpy() == np.array([6, 7])).all()
+
     launcher.stop_server()
 
 
@@ -103,7 +110,7 @@ def test_add_vtcm(android_serial_number, tvm_tracker_host, 
tvm_tracker_port, adb
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 1,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -124,6 +131,7 @@ def test_add_vtcm(android_serial_number, tvm_tracker_host, 
tvm_tracker_port, adb
         mod["add"](A_data, B_data, C_data)
         result = C_data.numpy()
         assert (result == np.array([6, 7])).all()
+
     launcher.stop_server()
 
 
@@ -158,7 +166,7 @@ class TestMatMul:
         rpc_info = {
             "rpc_tracker_host": tvm_tracker_host,
             "rpc_tracker_port": tvm_tracker_port,
-            "rpc_server_port": RPC_SERVER_PORT,
+            "rpc_server_port": RPC_SERVER_PORT + 2,  # See note at the 
beginning of the file
             "adb_server_socket": adb_server_socket,
         }
         launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -236,7 +244,7 @@ def test_graph_executor(
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 3,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -248,6 +256,7 @@ def test_graph_executor(
         graph_mod.set_input(**params)
         graph_mod.run(**inputs)
         hexagon_output = graph_mod.get_output(0).numpy()
+
     launcher.stop_server()
 
     target_llvm = tvm.target.Target("llvm")
@@ -322,7 +331,7 @@ def test_graph_executor_multiple_conv2d(
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 4,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -347,6 +356,7 @@ def test_graph_executor_multiple_conv2d(
         graph_mod.set_input(**params)
         graph_mod.run(**inputs)
         hexagon_output = graph_mod.get_output(0).numpy()
+
     launcher.stop_server()
 
     target_llvm = tvm.target.Target("llvm")
@@ -365,6 +375,17 @@ def test_graph_executor_multiple_conv2d(
     tvm.testing.assert_allclose(hexagon_output, expected_output, rtol=1e-4, 
atol=1e-5)
 
 
+def _workaround_create_aot_shared():
+    # The C codegen uses TVM/RT functions directly. On Hexagon it should use
+    # functions pointers via __TVMxyz variables. This workaround makes the
+    # runtime symbols visible to the compiled shared library.
+    extra_link_flags = os.environ.get("HEXAGON_SHARED_LINK_FLAGS")
+    extra_options = str(extra_link_flags).split() if extra_link_flags else []
+    return lambda so_name, files, hexagon_arch, options: 
hexagon.create_aot_shared(
+        so_name, files, hexagon_arch, options=extra_options + options
+    )
+
+
 @requires_hexagon_toolchain
 def test_aot_executor(tvm_tracker_host, tvm_tracker_port, 
android_serial_number, adb_server_socket):
     dtype = "float32"
@@ -406,8 +427,12 @@ def test_aot_executor(tvm_tracker_host, tvm_tracker_port, 
android_serial_number,
             runtime=Runtime("cpp"),
             executor=Executor("aot", {"unpacked-api": False, "interface-api": 
"c"}),
         )
+        # Uncomment this once the workaround is not needed.
+        # lowered.export_library(
+        #     dso_binary_path, fcompile=hexagon.create_aot_shared, 
hexagon_arch="v68"
+        # )
         lowered.export_library(
-            dso_binary_path, fcompile=hexagon.create_aot_shared, 
hexagon_arch="v68"
+            dso_binary_path, fcompile=_workaround_create_aot_shared(), 
hexagon_arch="v68"
         )
 
     if not android_serial_number:
@@ -416,7 +441,7 @@ def test_aot_executor(tvm_tracker_host, tvm_tracker_port, 
android_serial_number,
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 5,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -428,6 +453,7 @@ def test_aot_executor(tvm_tracker_host, tvm_tracker_port, 
android_serial_number,
         aot_mod.set_input(**inputs)
         aot_mod.run()
         hexagon_output = aot_mod.get_output(0).numpy()
+
     launcher.stop_server()
 
     target_llvm = tvm.target.Target("llvm")
@@ -506,8 +532,12 @@ def test_aot_executor_multiple_conv2d(
             runtime=Runtime("cpp"),
             executor=Executor("aot", {"unpacked-api": False, "interface-api": 
"c"}),
         )
+        # Uncomment this once the workaround is not needed.
+        # lowered.export_library(
+        #     dso_binary_path, fcompile=hexagon.create_aot_shared, 
hexagon_arch="v68"
+        # )
         lowered.export_library(
-            dso_binary_path, fcompile=hexagon.create_aot_shared, 
hexagon_arch="v68"
+            dso_binary_path, fcompile=_workaround_create_aot_shared(), 
hexagon_arch="v68"
         )
 
     if not android_serial_number:
@@ -516,7 +546,7 @@ def test_aot_executor_multiple_conv2d(
     rpc_info = {
         "rpc_tracker_host": tvm_tracker_host,
         "rpc_tracker_port": tvm_tracker_port,
-        "rpc_server_port": RPC_SERVER_PORT,
+        "rpc_server_port": RPC_SERVER_PORT + 6,  # See note at the beginning 
of the file
         "adb_server_socket": adb_server_socket,
     }
     launcher = HexagonLauncher(serial_number=android_serial_number, 
rpc_info=rpc_info)
@@ -528,6 +558,7 @@ def test_aot_executor_multiple_conv2d(
         aot_mod.set_input(**inputs)
         aot_mod.run()
         hexagon_output = aot_mod.get_output(0).numpy()
+
     launcher.stop_server()
 
     target_llvm = tvm.target.Target("llvm")
diff --git a/tests/scripts/task_python_hexagon_simulator.sh 
b/tests/scripts/task_python_hexagon_simulator.sh
new file mode 100755
index 0000000..cddd523
--- /dev/null
+++ b/tests/scripts/task_python_hexagon_simulator.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -e
+set -u
+
+source tests/scripts/setup-pytest-env.sh
+
+make cython3
+
+export TVM_TRACKER_PORT=9190
+export TVM_TRACKER_HOST=0.0.0.0
+env PYTHONPATH=python python3 -m tvm.exec.rpc_tracker --host 
"${TVM_TRACKER_HOST}" --port "${TVM_TRACKER_PORT}" &
+TRACKER_PID=$!
+sleep 5   # Wait for tracker to bind
+
+# Temporary workaround for symbol visibility
+export HEXAGON_SHARED_LINK_FLAGS="-Lbuild/hexagon_api_output -lhexagon_rpc_sim"
+
+# HEXAGON_TOOLCHAIN is already set
+export HEXAGON_SDK_ROOT=${HEXAGON_SDK_PATH}
+export ANDROID_SERIAL_NUMBER=simulator
+run_pytest ctypes python-contrib-hexagon-simulator 
tests/python/contrib/test_hexagon/test_launcher.py
+
+kill ${TRACKER_PID}

Reply via email to