diff --git a/.github/ISSUE_TEMPLATE/flaky-test.md b/.github/ISSUE_TEMPLATE/flaky-test.md new file mode 100644 index 000000000000..1d61bbb632a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/flaky-test.md @@ -0,0 +1,18 @@ +--- +name: "\U00002744 Flaky Test" +about: Report a flaky test, make sure to include links to CI runs, a sample failure log, and the name of the test(s) +title: "[Flaky Test] " +labels: "test: flaky" +--- + +Thanks for participating in the TVM community! We use https://discuss.tvm.ai for any general usage questions and discussions. The issue tracker is used for actionable items such as feature proposals discussion, roadmaps, and bug tracking. You are always welcomed to post on the forum first :smile_cat: + +These tests were found to be flaky (intermittently failing on `main` or failed in a PR with unrelated changes). As per [the docs](https://github.com/apache/tvm/blob/main/docs/contribute/ci.rst#handling-flaky-failures, these failures will be disabled in a PR that references this issue until the test owners can fix the source of the flakiness. + +### Test(s) + +- `tests/python/some_file.py::the_test_name` + +### Jenkins Links + +- Please provide link(s) to failed CI runs. If runs are for a PR, explain why your PR did not break the test (e.g. did not touch that part of the codebase) diff --git a/.github/workflows/update_last_successful_branch.yml b/.github/workflows/update_last_successful_branch.yml new file mode 100644 index 000000000000..1e8def4040ae --- /dev/null +++ b/.github/workflows/update_last_successful_branch.yml @@ -0,0 +1,43 @@ +# 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. + +# GH actions. +# We use it to cover windows and mac builds +# Jenkins is still the primary CI + +name: Update last-successful branch + +on: + schedule: + - cron: "0/15 * * * *" + workflow_dispatch: + +concurrency: + group: update-last-successful-branch + cancel-in-progress: true + +jobs: + update-last-successful-branch: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Update last-successful branch + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eux + python tests/scripts/update_branch.py || echo step failed diff --git a/.gitignore b/.gitignore index b5ff0f77581b..4e2c9824d307 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,8 @@ DerivedData/ *.class jvm/*/target/ jvm/*/*/target/ +jvm/native/*/generated +jvm/native/src/main/native/org_apache_tvm_native_c_api.h *.worksheet *.idea *.iml diff --git a/CMakeLists.txt b/CMakeLists.txt index f8d0ab95b80a..9c6a7dddfdf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ tvm_option(USE_LLVM "Build with LLVM, can be set to specific llvm-config path" O tvm_option(USE_STACKVM_RUNTIME "Include stackvm into the runtime" OFF) tvm_option(USE_GRAPH_EXECUTOR "Build with tiny graph executor" ON) tvm_option(USE_GRAPH_EXECUTOR_CUDA_GRAPH "Build with tiny graph executor with CUDA Graph for GPUs" OFF) +tvm_option(USE_AOT_EXECUTOR "Build with AOT executor" ON) tvm_option(USE_PROFILER "Build profiler for the VM and graph executor" ON) tvm_option(USE_OPENMP "Build with OpenMP thread pool implementation" OFF) tvm_option(USE_RELAY_DEBUG "Building Relay in debug mode..." OFF) @@ -395,6 +396,13 @@ if(USE_PROFILER) list(APPEND RUNTIME_SRCS ${RUNTIME_VM_PROFILER_SRCS}) endif(USE_PROFILER) +if(USE_AOT_EXECUTOR) + message(STATUS "Build with AOT Executor support...") + file(GLOB RUNTIME_AOT_EXECUTOR_SRCS src/runtime/aot_executor/*.cc) + list(APPEND RUNTIME_SRCS ${RUNTIME_AOT_EXECUTOR_SRCS}) + +endif(USE_AOT_EXECUTOR) + # Enable ctest if gtest is available if(USE_GTEST) # Check env var for backward compatibility. A better way to specify package @@ -482,6 +490,7 @@ add_library(tvm_runtime_objs OBJECT ${RUNTIME_SRCS}) add_library(tvm_libinfo_objs OBJECT ${LIBINFO_FILE}) add_library(tvm SHARED $ $ $) +target_include_directories(tvm PUBLIC "$") set_property(TARGET tvm APPEND PROPERTY LINK_OPTIONS "${TVM_NO_UNDEFINED_SYMBOLS}") set_property(TARGET tvm APPEND PROPERTY LINK_OPTIONS "${TVM_VISIBILITY_FLAG}") if(BUILD_STATIC_RUNTIME) @@ -496,6 +505,7 @@ else() add_library(tvm_runtime SHARED $ $) set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS "${TVM_NO_UNDEFINED_SYMBOLS}") endif() +target_include_directories(tvm_runtime PUBLIC "$") set_property(TARGET tvm_runtime APPEND PROPERTY LINK_OPTIONS "${TVM_VISIBILITY_FLAG}") target_compile_definitions(tvm_objs PUBLIC DMLC_USE_LOGGING_LIBRARY=) @@ -566,17 +576,6 @@ target_link_libraries(tvm_runtime PRIVATE ${TVM_RUNTIME_LINKER_LIBS}) # Set flags for clang include(cmake/modules/ClangFlags.cmake) - -# Related headers -target_include_directories( - tvm - PUBLIC "topi/include") -target_include_directories( - tvm_objs - PUBLIC "topi/include") -target_include_directories( - tvm_libinfo_objs - PUBLIC "topi/include") set(CRC16_INCLUDE_PATH "3rdparty/libcrc/include") target_include_directorieS( tvm_objs @@ -621,33 +620,56 @@ endif() add_custom_target(runtime DEPENDS tvm_runtime) # Installation rules -install(TARGETS tvm DESTINATION lib${LIB_SUFFIX}) -install(TARGETS tvm_runtime DESTINATION lib${LIB_SUFFIX}) +install(TARGETS tvm EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX}) +install(TARGETS tvm_runtime EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX}) if (INSTALL_DEV) install( - DIRECTORY "include/." DESTINATION "include" + DIRECTORY "include/" DESTINATION "include" FILES_MATCHING PATTERN "*.h" ) install( - DIRECTORY "3rdparty/dlpack/include/." DESTINATION "include" + DIRECTORY "3rdparty/dlpack/include/" DESTINATION "include" FILES_MATCHING PATTERN "*.h" ) install( - DIRECTORY "3rdparty/dmlc-core/include/." DESTINATION "include" + DIRECTORY "3rdparty/dmlc-core/include/" DESTINATION "include" FILES_MATCHING PATTERN "*.h" ) else(INSTALL_DEV) install( - DIRECTORY "include/tvm/runtime/." DESTINATION "include/tvm/runtime" + DIRECTORY "include/tvm/runtime/" DESTINATION "include/tvm/runtime" FILES_MATCHING PATTERN "*.h" ) endif(INSTALL_DEV) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +set(PROJECT_CONFIG_CONTENT "@PACKAGE_INIT@\n") +string(APPEND PROJECT_CONFIG_CONTENT "include(CMakeFindDependencyMacro)\n") +string(APPEND PROJECT_CONFIG_CONTENT "find_dependency(Threads REQUIRED)\n") +string(APPEND PROJECT_CONFIG_CONTENT + "include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake\")") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/temp_config_file.cmake" ${PROJECT_CONFIG_CONTENT}) + +install(EXPORT ${PROJECT_NAME}Targets + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + +# Create config for find_package() +configure_package_config_file( + "${CMAKE_CURRENT_BINARY_DIR}/temp_config_file.cmake" ${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + +install( + FILES + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + # More target definitions if(MSVC) target_compile_definitions(tvm_objs PRIVATE -DTVM_EXPORTS) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5e37f09edcf2..03fd4abbb826 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -64,6 +64,7 @@ We do encourage everyone to work anything they are interested in. - [Christopher Sidebottom](https://github.com/Mousius): @Mousius - arm, ethos-u, relay - [Junru Shao](https://github.com/junrushao1994) (PMC): @junrushao1994 - relay, compiler - [Haichen Shen](https://github.com/icemelon) (PMC): @icemelon - relay, topi +- [Chris Sullivan](https://github.com/csullivan): @csullivan - amd backend - [Siva Rama Krishna Reddy](https://github.com/srkreddy1238): @srkreddy1238 - frontends, golang - [Zhixun Tan](https://github.com/phisiart): @phisiart - opengl, web - [Andrew Tulloch](https://github.com/ajtulloch): @ajtulloch - topi, compiler, runtime diff --git a/Jenkinsfile b/Jenkinsfile index b0e5f77612f5..840f72640900 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -47,11 +47,12 @@ import org.jenkinsci.plugins.pipeline.modeldefinition.Utils // NOTE: these lines are scanned by docker/dev_common.sh. Please update the regex as needed. --> ci_lint = "tlcpack/ci-lint:v0.68" ci_gpu = "tlcpack/ci-gpu:v0.81" -ci_cpu = "tlcpack/ci-cpu:v0.80" +ci_cpu = "tlcpack/ci-cpu:v0.81" ci_wasm = "tlcpack/ci-wasm:v0.71" ci_i386 = "tlcpack/ci-i386:v0.74" ci_qemu = "tlcpack/ci-qemu:v0.10" ci_arm = "tlcpack/ci-arm:v0.07" +ci_hexagon = "tlcpack/ci-hexagon:v0.01" // <--- End of regex-scanned config. // Parameters to allow overriding (in Jenkins UI), the images @@ -256,20 +257,20 @@ def cpp_unittest(image) { } stage('Build') { - parallel 'BUILD: GPU': { - if (!skip_ci) { - node('GPUBUILD') { - ws(per_exec_ws('tvm/build-gpu')) { - init_git() - sh "${docker_run} ${ci_gpu} ./tests/scripts/task_config_build_gpu.sh" - make(ci_gpu, 'build', '-j2') - pack_lib('gpu', tvm_multilib) - // compiler test - sh "${docker_run} ${ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh" - make(ci_gpu, 'build2', '-j2') - } + parallel 'BUILD: GPU': { + if (!skip_ci) { + node('GPUBUILD') { + ws(per_exec_ws('tvm/build-gpu')) { + init_git() + sh "${docker_run} ${ci_gpu} ./tests/scripts/task_config_build_gpu.sh" + make(ci_gpu, 'build', '-j2') + pack_lib('gpu', tvm_multilib) + // compiler test + sh "${docker_run} ${ci_gpu} ./tests/scripts/task_config_build_gpu_other.sh" + make(ci_gpu, 'build2', '-j2') } } + } }, 'BUILD: CPU': { if (!skip_ci && is_docs_only_build != 1) { @@ -360,32 +361,64 @@ stage('Build') { script: "${docker_run} ${ci_qemu} ./tests/scripts/task_config_build_qemu.sh", label: 'Create QEMU cmake config', ) - make(ci_qemu, 'build', '-j2') - timeout(time: max_time, unit: 'MINUTES') { - ci_setup(ci_qemu) + try { + make(ci_qemu, 'build', '-j2') + timeout(time: max_time, unit: 'MINUTES') { + ci_setup(ci_qemu) + sh ( + script: "${docker_run} ${ci_qemu} ./tests/scripts/task_python_microtvm.sh", + label: 'Run microTVM tests', + ) + sh ( + script: "${docker_run} ${ci_qemu} ./tests/scripts/task_demo_microtvm.sh", + label: 'Run microTVM demos', + ) + } + } finally { + junit 'build/pytest-results/*.xml' + } + } + } + } else { + Utils.markStageSkippedForConditional('BUILD: QEMU') + } + }, + 'BUILD: Hexagon': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU') { + ws(per_exec_ws('tvm/build-hexagon')) { + init_git() + sh ( + script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_config_build_hexagon.sh", + label: 'Create Hexagon cmake config', + ) + try { + make(ci_hexagon, 'build', '-j2') sh ( - script: "${docker_run} ${ci_qemu} ./tests/scripts/task_python_microtvm.sh", - label: 'Run microTVM tests', + script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_build_hexagon_api.sh", + label: 'Build Hexagon API', ) sh ( - script: "${docker_run} ${ci_qemu} ./tests/scripts/task_demo_microtvm.sh", - label: 'Run microTVM demos', + script: "${docker_run} ${ci_hexagon} ./tests/scripts/task_python_hexagon.sh", + label: 'Run Hexagon tests', ) + } finally { junit 'build/pytest-results/*.xml' } } } } else { - Utils.markStageSkippedForConditional('BUILD: QEMU') + Utils.markStageSkippedForConditional('BUILD: Hexagon') } } } stage('Test') { - parallel 'unittest: GPU': { - if (!skip_ci && is_docs_only_build != 1) { - node('TensorCore') { - ws(per_exec_ws('tvm/ut-python-gpu')) { + parallel 'unittest: GPU': { + if (!skip_ci && is_docs_only_build != 1) { + node('TensorCore') { + ws(per_exec_ws('tvm/ut-python-gpu')) { + try { init_git() unpack_lib('gpu', tvm_multilib) timeout(time: max_time, unit: 'MINUTES') { @@ -402,18 +435,21 @@ stage('Test') { script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_integration_gpuonly.sh", label: 'Run Python GPU integration tests', ) - junit 'build/pytest-results/*.xml' } + } finally { + junit 'build/pytest-results/*.xml' } } - } else { - Utils.markStageSkippedForConditional('unittest: GPU') } - }, - 'integration: CPU': { - if (!skip_ci && is_docs_only_build != 1) { - node('CPU') { - ws(per_exec_ws('tvm/ut-python-cpu')) { + } else { + Utils.markStageSkippedForConditional('unittest: GPU') + } + }, + 'integration: CPU': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU') { + ws(per_exec_ws('tvm/ut-python-cpu')) { + try { init_git() unpack_lib('cpu', tvm_multilib_tsim) timeout(time: max_time, unit: 'MINUTES') { @@ -422,18 +458,21 @@ stage('Test') { script: "${docker_run} ${ci_cpu} ./tests/scripts/task_python_integration.sh", label: 'Run CPU integration tests', ) - junit 'build/pytest-results/*.xml' } + } finally { + junit 'build/pytest-results/*.xml' } } - } else { - Utils.markStageSkippedForConditional('integration: CPU') } - }, - 'unittest: CPU': { - if (!skip_ci && is_docs_only_build != 1) { - node('CPU') { - ws(per_exec_ws("tvm/ut-python-cpu")) { + } else { + Utils.markStageSkippedForConditional('integration: CPU') + } + }, + 'unittest: CPU': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU') { + ws(per_exec_ws("tvm/ut-python-cpu")) { + try { init_git() unpack_lib('cpu', tvm_multilib_tsim) timeout(time: max_time, unit: 'MINUTES') { @@ -444,18 +483,21 @@ stage('Test') { script: "${docker_run} ${ci_cpu} ./tests/scripts/task_python_vta_tsim.sh", label: "Run VTA tests in TSIM", ) - junit "build/pytest-results/*.xml" } + } finally { + junit 'build/pytest-results/*.xml' } } - } else { - Utils.markStageSkippedForConditional('unittest: CPU') } - }, - 'python3: i386': { - if (!skip_ci && is_docs_only_build != 1) { - node('CPU') { - ws(per_exec_ws('tvm/ut-python-i386')) { + } else { + Utils.markStageSkippedForConditional('unittest: CPU') + } + }, + 'python3: i386': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU') { + ws(per_exec_ws('tvm/ut-python-i386')) { + try { init_git() unpack_lib('i386', tvm_multilib) timeout(time: max_time, unit: 'MINUTES') { @@ -466,18 +508,21 @@ stage('Test') { label: 'Run i386 integration tests', ) fsim_test(ci_i386) - junit 'build/pytest-results/*.xml' } + } finally { + junit 'build/pytest-results/*.xml' } } - } else { - Utils.markStageSkippedForConditional('python3: i386') } - }, - 'python3: arm': { - if (!skip_ci && is_docs_only_build != 1) { - node('ARM') { - ws(per_exec_ws('tvm/ut-python-arm')) { + } else { + Utils.markStageSkippedForConditional('python3: i386') + } + }, + 'python3: arm': { + if (!skip_ci && is_docs_only_build != 1) { + node('ARM') { + ws(per_exec_ws('tvm/ut-python-arm')) { + try { init_git() unpack_lib('arm', tvm_multilib) timeout(time: max_time, unit: 'MINUTES') { @@ -487,47 +532,55 @@ stage('Test') { script: "${docker_run} ${ci_arm} ./tests/scripts/task_python_arm_compute_library.sh", label: 'Run test_arm_compute_lib test', ) - junit 'build/pytest-results/*.xml' // sh "${docker_run} ${ci_arm} ./tests/scripts/task_python_integration.sh" } + } finally { + junit 'build/pytest-results/*.xml' } } - } else { - Utils.markStageSkippedForConditional('python3: arm') } - }, + } else { + Utils.markStageSkippedForConditional('python3: arm') + } + }, 'topi: GPU': { - if (!skip_ci && is_docs_only_build != 1) { - node('GPU') { - ws(per_exec_ws('tvm/topi-python-gpu')) { - init_git() - unpack_lib('gpu', tvm_multilib) - timeout(time: max_time, unit: 'MINUTES') { - ci_setup(ci_gpu) - sh ( - script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_topi.sh", - label: 'Run TOPI tests', - ) - junit 'build/pytest-results/*.xml' + if (!skip_ci && is_docs_only_build != 1) { + node('GPU') { + ws(per_exec_ws('tvm/topi-python-gpu')) { + try { + init_git() + unpack_lib('gpu', tvm_multilib) + timeout(time: max_time, unit: 'MINUTES') { + ci_setup(ci_gpu) + sh ( + script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_topi.sh", + label: 'Run TOPI tests', + ) + } + } finally { + junit 'build/pytest-results/*.xml' + } } } - } } else { Utils.markStageSkippedForConditional('topi: GPU') - } + } }, 'frontend: GPU': { if (!skip_ci && is_docs_only_build != 1) { node('GPU') { ws(per_exec_ws('tvm/frontend-python-gpu')) { - init_git() - unpack_lib('gpu', tvm_multilib) - timeout(time: max_time, unit: 'MINUTES') { - ci_setup(ci_gpu) - sh ( - script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_frontend.sh", - label: 'Run Python frontend tests', - ) + try { + init_git() + unpack_lib('gpu', tvm_multilib) + timeout(time: max_time, unit: 'MINUTES') { + ci_setup(ci_gpu) + sh ( + script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_frontend.sh", + label: 'Run Python frontend tests', + ) + } + } finally { junit 'build/pytest-results/*.xml' } } @@ -540,14 +593,17 @@ stage('Test') { if (!skip_ci && is_docs_only_build != 1) { node('CPU') { ws(per_exec_ws('tvm/frontend-python-cpu')) { - init_git() - unpack_lib('cpu', tvm_multilib) - timeout(time: max_time, unit: 'MINUTES') { - ci_setup(ci_cpu) - sh ( - script: "${docker_run} ${ci_cpu} ./tests/scripts/task_python_frontend_cpu.sh", - label: 'Run Python frontend tests', - ) + try { + init_git() + unpack_lib('cpu', tvm_multilib) + timeout(time: max_time, unit: 'MINUTES') { + ci_setup(ci_cpu) + sh ( + script: "${docker_run} ${ci_cpu} ./tests/scripts/task_python_frontend_cpu.sh", + label: 'Run Python frontend tests', + ) + } + } finally { junit 'build/pytest-results/*.xml' } } @@ -595,13 +651,13 @@ stage('Build packages') { */ stage('Deploy') { - node('doc') { - ws(per_exec_ws('tvm/deploy-docs')) { - if (env.BRANCH_NAME == 'main') { + node('doc') { + ws(per_exec_ws('tvm/deploy-docs')) { + if (env.BRANCH_NAME == 'main') { unpack_lib('docs', 'docs.tgz') sh 'cp docs.tgz /var/docs/docs.tgz' sh 'tar xf docs.tgz -C /var/docs' - } } } + } } diff --git a/apps/android_rpc/.gitignore b/apps/android_rpc/.gitignore index 39fb081a42a8..1f8bc3b3e5e6 100644 --- a/apps/android_rpc/.gitignore +++ b/apps/android_rpc/.gitignore @@ -7,3 +7,9 @@ /build /captures .externalNativeBuild + +/app/src/main/jni/jni_helper_func.h +/app/src/main/jni/org_apache_tvm_native_c_api.cc +/app/src/main/jni/org_apache_tvm_native_c_api.h +/app/src/main/obj/ +dev_tools/tvmrpc.keystore diff --git a/apps/cpp_rpc/CMakeLists.txt b/apps/cpp_rpc/CMakeLists.txt index 966448929a0a..657d486500a9 100644 --- a/apps/cpp_rpc/CMakeLists.txt +++ b/apps/cpp_rpc/CMakeLists.txt @@ -51,6 +51,10 @@ if (BUILD_FOR_ANDROID AND USE_HEXAGON_SDK) list(APPEND TVM_RPC_LINKER_LIBS cdsprpc log) endif() -list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime) +if(BUILD_STATIC_RUNTIME) + list(APPEND TVM_RPC_LINKER_LIBS -Wl,--whole-archive tvm_runtime -Wl,--no-whole-archive) +else() + list(APPEND TVM_RPC_LINKER_LIBS tvm_runtime) +endif() target_link_libraries(tvm_rpc ${TVM_RPC_LINKER_LIBS}) diff --git a/apps/hexagon_api/CMakeLists.txt b/apps/hexagon_api/CMakeLists.txt index 557dcfb85045..052fd00020cb 100644 --- a/apps/hexagon_api/CMakeLists.txt +++ b/apps/hexagon_api/CMakeLists.txt @@ -23,6 +23,31 @@ else() endif() file(MAKE_DIRECTORY ${HEXAGON_API_BINARY_DIR}) +# Build X86 binaries: +# - tvm_rpc_x86 + +ExternalProject_Add(x86_tvm_runtime_rpc + SOURCE_DIR "${TVM_SOURCE_DIR}" + BUILD_COMMAND $(MAKE) runtime tvm_rpc + CMAKE_ARGS + "-DUSE_HEXAGON_TOOLCHAIN=${USE_HEXAGON_TOOLCHAIN}" + "-DCMAKE_CXX_STANDARD=14" + "-DUSE_LIBBACKTRACE=OFF" + "-DUSE_RPC=ON" + "-DUSE_CPP_RPC=ON" + "-DUSE_HEXAGON_RPC=ON" + "-DBUILD_STATIC_RUNTIME=ON" + INSTALL_COMMAND "" + BUILD_ALWAYS ON +) +ExternalProject_Get_Property(x86_tvm_runtime_rpc BINARY_DIR) +ExternalProject_Add_Step(x86_tvm_runtime_rpc copy_rpc_server + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${BINARY_DIR}/tvm_rpc + ${HEXAGON_API_BINARY_DIR}/tvm_rpc_x86 + DEPENDEES install +) + # Build Android binaries: # - libtvm_runtime.so # - tvm_rpc_android @@ -38,7 +63,6 @@ ExternalProject_Add(android_tvm_runtime_rpc "-DUSE_HEXAGON_ARCH=${USE_HEXAGON_ARCH}" "-DCMAKE_CXX_STANDARD=14" "-DUSE_LIBBACKTRACE=OFF" - "-DUSE_LLVM=OFF" "-DUSE_RPC=ON" "-DUSE_CPP_RPC=ON" "-DUSE_HEXAGON_RPC=ON" @@ -66,7 +90,7 @@ ExternalProject_Add_Step(android_tvm_runtime_rpc copy_rpc_server ExternalProject_Add(hexagon_tvm_runtime_rpc SOURCE_DIR "${TVM_SOURCE_DIR}" - BUILD_COMMAND $(MAKE) runtime + BUILD_COMMAND $(MAKE) runtime hexagon_rpc_sim CMAKE_ARGS "-DCMAKE_C_COMPILER=${USE_HEXAGON_TOOLCHAIN}/bin/hexagon-clang" "-DCMAKE_CXX_COMPILER=${USE_HEXAGON_TOOLCHAIN}/bin/hexagon-clang++" @@ -84,6 +108,7 @@ ExternalProject_Add_Step(hexagon_tvm_runtime_rpc copy_binaries COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BINARY_DIR}/libtvm_runtime.a ${BINARY_DIR}/libhexagon_rpc_skel.so + ${BINARY_DIR}/libhexagon_rpc_sim.so ${HEXAGON_API_BINARY_DIR} DEPENDEES install ) diff --git a/apps/microtvm/arduino/template_project/src/example_project/model.c b/apps/microtvm/arduino/template_project/src/example_project/model.c index 553665191b14..25d609dacce1 100644 --- a/apps/microtvm/arduino/template_project/src/example_project/model.c +++ b/apps/microtvm/arduino/template_project/src/example_project/model.c @@ -86,7 +86,7 @@ tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) { void TVMInitialize() { StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE); } void TVMExecute(void* input_data, void* output_data) { - int ret_val = tvmgen_default_run_model(input_data, output_data); + int ret_val = tvmgen_default___tvm_main__(input_data, output_data); if (ret_val != 0) { TVMPlatformAbort(kTvmErrorPlatformCheckFailure); } diff --git a/apps/microtvm/ethosu/src/demo_bare_metal.c b/apps/microtvm/ethosu/src/demo_bare_metal.c index 753dd0712852..78d79dc23e4d 100644 --- a/apps/microtvm/ethosu/src/demo_bare_metal.c +++ b/apps/microtvm/ethosu/src/demo_bare_metal.c @@ -40,7 +40,7 @@ int main(int argc, char** argv) { printf("Running inference\n"); struct tvmgen_default_outputs outputs = { - .output = output, + .MobilenetV2_Predictions_Reshape_11 = output, }; struct tvmgen_default_inputs inputs = { .tfl_quantize = input, diff --git a/apps/microtvm/ethosu/src/demo_freertos.c b/apps/microtvm/ethosu/src/demo_freertos.c index cd5b76b15f49..2be8f1148e28 100644 --- a/apps/microtvm/ethosu/src/demo_freertos.c +++ b/apps/microtvm/ethosu/src/demo_freertos.c @@ -106,7 +106,7 @@ static void prvInferenceTask(void* pvParameters) { .tfl_quantize = pucReceivedData, }; struct tvmgen_default_outputs xOutputs = { - .output = output, + .MobilenetV2_Predictions_Reshape_11 = output, }; struct ethosu_driver* xDriver = ethosu_reserve_driver(); struct tvmgen_default_devices xDevices = { diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index a7774899acb8..de95be949ad9 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -20,6 +20,7 @@ import collections.abc import enum import fcntl +import json import logging import os import os.path @@ -35,7 +36,7 @@ import tempfile import threading import time -import json +import usb import serial import serial.tools.list_ports @@ -179,8 +180,6 @@ def openocd_serial(options): if "openocd_serial" in options: return options["openocd_serial"] - import usb # pylint: disable=import-outside-toplevel - find_kw = BOARD_USB_FIND_KW[CMAKE_CACHE["BOARD"]] boards = usb.core.find(find_all=True, **find_kw) serials = [] @@ -588,6 +587,13 @@ def _set_nonblock(fd): class ZephyrSerialTransport: + + NRF5340_VENDOR_ID = 0x1366 + + # NRF5340_DK v1.0.0 uses VCOM2 + # NRF5340_DK v2.0.0 uses VCOM1 + NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID = {0x1055: "VCOM2", 0x1051: "VCOM1"} + @classmethod def _lookup_baud_rate(cls, options): # TODO(mehrdadh): remove this hack once dtlib.py is a standalone project @@ -625,7 +631,17 @@ def _find_nrf_serial_port(cls, options): parts = line.split() ports_by_vcom[parts[2]] = parts[1] - return ports_by_vcom["VCOM2"] + nrf_board = usb.core.find(idVendor=cls.NRF5340_VENDOR_ID) + + if nrf_board == None: + raise Exception("_find_nrf_serial_port: unable to find NRF5340DK") + + if nrf_board.idProduct in cls.NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID: + vcom_port = cls.NRF5340_DK_BOARD_VCOM_BY_PRODUCT_ID[nrf_board.idProduct] + else: + raise Exception("_find_nrf_serial_port: unable to find known NRF5340DK product ID") + + return ports_by_vcom[vcom_port] @classmethod def _find_openocd_serial_port(cls, options): diff --git a/apps/microtvm/zephyr/template_project/src/aot_demo/main.c b/apps/microtvm/zephyr/template_project/src/aot_demo/main.c index 3946727b26a8..27d74d7ba76b 100644 --- a/apps/microtvm/zephyr/template_project/src/aot_demo/main.c +++ b/apps/microtvm/zephyr/template_project/src/aot_demo/main.c @@ -178,7 +178,7 @@ void TVMInfer() { .input_1 = input_data, }; struct tvmgen_default_outputs outputs = { - .output = output_data, + .Identity = output_data, }; StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE); diff --git a/apps/microtvm/zephyr_cmsisnn/src/main.c b/apps/microtvm/zephyr_cmsisnn/src/main.c index 7696915f7aa2..31f6cd0cc1d0 100644 --- a/apps/microtvm/zephyr_cmsisnn/src/main.c +++ b/apps/microtvm/zephyr_cmsisnn/src/main.c @@ -34,7 +34,7 @@ extern float output_storage[12]; extern const size_t output_len; -static uint8_t g_crt_workspace[TVMGEN_DEFAULT_WORKSPACE_SIZE + 256]; +static uint8_t g_crt_workspace[TVMGEN_DEFAULT_WORKSPACE_SIZE]; tvm_workspace_t app_workspace; void TVMLogf(const char* msg, ...) { @@ -62,7 +62,7 @@ void main(void) { StackMemoryManager_Init(&app_workspace, g_crt_workspace, TVMGEN_DEFAULT_WORKSPACE_SIZE); struct tvmgen_default_inputs inputs = {.input = input_storage}; - struct tvmgen_default_outputs outputs = {.output = output_storage}; + struct tvmgen_default_outputs outputs = {.Identity = output_storage}; if (tvmgen_default_run(&inputs, &outputs) != 0) { printk("Model run failed\n"); diff --git a/cmake/modules/Arduino.cmake b/cmake/modules/Arduino.cmake index 54c144081efa..f603e5d5df2b 100644 --- a/cmake/modules/Arduino.cmake +++ b/cmake/modules/Arduino.cmake @@ -43,7 +43,7 @@ if(USE_MICRO) math(EXPR job_spec_stop "${job_spec_length} - 3") list(GET job_spec 0 job_src_base) - set(job_src_base "${CMAKE_SOURCE_DIR}/${job_src_base}") + set(job_src_base "${CMAKE_CURRENT_SOURCE_DIR}/${job_src_base}") foreach(copy_pattern_index RANGE 1 "${job_spec_stop}" 3) list(GET job_spec ${copy_pattern_index} copy_pattern) math(EXPR copy_dest_index "${copy_pattern_index} + 2") diff --git a/cmake/modules/Hexagon.cmake b/cmake/modules/Hexagon.cmake index b90528d0767d..a8844a22e164 100644 --- a/cmake/modules/Hexagon.cmake +++ b/cmake/modules/Hexagon.cmake @@ -47,92 +47,200 @@ function(find_hexagon_toolchain) endif() endfunction() -if(BUILD_FOR_HEXAGON) - find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") - # Add SDK and QuRT includes when building for Hexagon. - include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_QURT_INCLUDES}) +macro(file_glob_append _output_list) + tvm_file_glob(GLOB _tmp0 ${ARGN}) + set(_tmp1 ${${_output_list}}) + list(APPEND _tmp1 ${_tmp0}) + set(${_output_list} ${_tmp1}) +endmacro() + +set(TVMRT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime") + +# First, verify that USE_HEXAGON_DEVICE has a valid value. +if(DEFINED USE_HEXAGON_DEVICE) + if(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND + NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}" AND + NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_NONE}") + message(SEND_ERROR "USE_HEXAGON_DEVICE must be one of " + "[${PICK_NONE}|${PICK_SIM}|${PICK_HW}]") + set(USE_HEXAGON_DEVICE OFF) + endif() endif() -if (NOT USE_HEXAGON_SDK STREQUAL "" AND - NOT USE_HEXAGON_SDK STREQUAL "/path/to/sdk") - set(HEXAGON_SDK_PATH_DEFINED ${USE_HEXAGON_SDK}) +# This .cmake file is included when building any part of TVM for any +# architecture. It shouldn't require any Hexagon-specific parameters +# (like the path to the SDK), unless it's needed. +# +# Aside from building the code for Hexagon, two flags can enable some +# Hexagon-related functionality: +# - USE_HEXAGON_DEVICE +# - USE_HEXAGON_RPC +# +# USE_HEXAGON_RPC: +# - When building for Hexagon, this will build the Hexagon endpoint of the +# RPC server: the FastRPC skel library (with TVM runtime built into it), +# and the standalone RPC server for simulator. +# - When building for Android, this will build the (intermediary) RPC server, +# including the "stub" code for the FastRPC implementation of the RPC +# channel. +# - When building for x86, this will build the host-side code that instan- +# tiates the simulator. + +if(NOT BUILD_FOR_HEXAGON AND NOT BUILD_FOR_ANDROID) + set(BUILD_FOR_HOST TRUE) endif() -if (BUILD_FOR_ANDROID AND HEXAGON_SDK_PATH_DEFINED) - find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") + +if(NOT USE_HEXAGON_DEVICE AND NOT USE_HEXAGON_RPC AND NOT BUILD_FOR_HEXAGON) + # If nothing related to Hexagon is enabled, add phony Hexagon codegen, + # and some stuff needed by cpptests (this part is a temporary workaround + # until e2e support for Hexagon is enabled). + if(BUILD_FOR_HOST) + list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc) + endif() + list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_buffer.cc) + list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_common.cc) + list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_user_dma.cc) + return() +endif() + + +function(add_android_paths) + if(NOT DEFINED HEXAGON_SDK_INCLUDES OR + NOT DEFINED HEXAGON_RPCMEM_ROOT OR + NOT DEFINED HEXAGON_REMOTE_ROOT) + message(FATAL_ERROR "This function must be called after find_hexagon_sdk_root") + endif() include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_RPCMEM_ROOT}/inc - ${HEXAGON_REMOTE_ROOT}) + ${HEXAGON_REMOTE_ROOT} + ) link_directories(${HEXAGON_REMOTE_ROOT}) - list(APPEND TVM_RUNTIME_LINKER_LIBS cdsprpc) -endif() +endfunction() -# Don't run these checks when compiling Hexagon device code, -# e.g. when compiling the TVM runtime for Hexagon. -if (NOT BUILD_FOR_HEXAGON AND NOT BUILD_FOR_ANDROID) - if(USE_HEXAGON_DEVICE STREQUAL "OFF") - list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc) - # append select runtime sources for unit testing - list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_buffer.cc) - list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_common.cc) - list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon/hexagon_user_dma.cc) - return() - elseif(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND - NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}") - message(SEND_ERROR "USE_HEXAGON_DEVICE must be one of " - "[${PICK_NONE}|${PICK_SIM}|${PICK_HW}]") - return() +function(add_hexagon_wrapper_paths) + if(NOT DEFINED HEXAGON_TOOLCHAIN) + message(FATAL_ERROR "This function must be called after find_hexagon_toolchain") endif() -endif() + include_directories(SYSTEM + "${HEXAGON_TOOLCHAIN}/include/iss" + ) + link_directories("${HEXAGON_TOOLCHAIN}/lib/iss") +endfunction() -# If no Hexagon support is enabled (other than some stub code), cmake -# execution should stop before reaching this point. +# Common sources for TVM runtime with Hexagon support +file_glob_append(RUNTIME_HEXAGON_COMMON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/hexagon_module.cc" + "${TVMRT_SOURCE_DIR}/hexagon/hexagon/*.cc" +) -if(NOT USE_HEXAGON_SDK OR NOT USE_HEXAGON_ARCH) - message(SEND_ERROR "Please set USE_HEXAGON_SDK to the Hexagon SDK root, " - "and USE_HEXAGON_ARCH to the Hexagon architecture version") - return() -endif() -if(USE_HEXAGON_LAUNCHER STREQUAL "ON") - message(SEND_ERROR "USE_HEXAGON_LAUNCHER is deprecated, please build apps separately") +if(BUILD_FOR_HEXAGON) + find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") + # Add SDK and QuRT includes when building for Hexagon. + include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_QURT_INCLUDES}) + + list(APPEND RUNTIME_HEXAGON_SRCS ${RUNTIME_HEXAGON_COMMON_SRCS}) endif() -# find_hexagon_sdk_root has been called at this point. + +if(USE_HEXAGON_DEVICE) + function(invalid_device_value_for BUILD_TARGET) + message(SEND_ERROR + "USE_HEXAGON_DEVICE=${USE_HEXAGON_DEVICE} is not supported when " + "building for ${BUILD_TARGET}" + ) + endfunction() + + list(APPEND RUNTIME_HEXAGON_SRCS ${RUNTIME_HEXAGON_COMMON_SRCS}) + + if(BUILD_FOR_HOST) + if(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}") + invalid_device_value_for("host") + endif() + find_hexagon_toolchain() + add_hexagon_wrapper_paths() + file_glob_append(RUNTIME_HEXAGON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/android/*.cc" + "${TVMRT_SOURCE_DIR}/hexagon/android/sim/*.cc" + ) + list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper") + + ExternalProject_Add(sim_dev + SOURCE_DIR "${TVMRT_SOURCE_DIR}/hexagon/android/sim/driver" + CMAKE_ARGS + "-DCMAKE_C_COMPILER=${HEXAGON_TOOLCHAIN}/bin/hexagon-clang" + "-DCMAKE_CXX_COMPILER=${HEXAGON_TOOLCHAIN}/bin/hexagon-clang++" + "-DHEXAGON_ARCH=${USE_HEXAGON_ARCH}" + INSTALL_COMMAND "true" + ) + + elseif(BUILD_FOR_ANDROID) + if(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}") + invalid_device_value_for("Android") + endif() + find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") + find_hexagon_toolchain() + add_android_paths() + file_glob_append(RUNTIME_HEXAGON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/android/*.cc" + "${TVMRT_SOURCE_DIR}/hexagon/android/target/*.cc" + ) + # Hexagon runtime uses __android_log_print, which is in liblog. + list(APPEND TVM_RUNTIME_LINKER_LIBS dl log cdsprpc) + + elseif(BUILD_FOR_HEXAGON) + invalid_device_value_for("Hexagon") + endif() +endif() # USE_HEXAGON_DEVICE + if(USE_HEXAGON_RPC) - set(TVMRT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src/runtime") - set(QAIC_EXE "${HEXAGON_QAIC_EXE}") - foreach(INCDIR IN LISTS HEXAGON_SDK_INCLUDES HEXAGON_REMOTE_ROOT) - list(APPEND QAIC_FLAGS "-I${INCDIR}") - endforeach() - - add_custom_command( - OUTPUT - "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.h" - "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_skel.c" - "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_stub.c" - COMMAND - ${QAIC_EXE} ${QAIC_FLAGS} "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.idl" - -o "${TVMRT_SOURCE_DIR}/hexagon/rpc" - MAIN_DEPENDENCY "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.idl" - ) + function(build_rpc_idl) + set(QAIC_EXE "${HEXAGON_QAIC_EXE}") + foreach(INCDIR IN LISTS HEXAGON_SDK_INCLUDES HEXAGON_REMOTE_ROOT) + list(APPEND QAIC_FLAGS "-I${INCDIR}") + endforeach() + + add_custom_command( + OUTPUT + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.h" + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_skel.c" + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_stub.c" + COMMAND + ${QAIC_EXE} ${QAIC_FLAGS} "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.idl" + -o "${TVMRT_SOURCE_DIR}/hexagon/rpc" + MAIN_DEPENDENCY "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc.idl" + ) + endfunction() + + list(APPEND RUNTIME_HEXAGON_SRCS ${RUNTIME_HEXAGON_COMMON_SRCS}) if(BUILD_FOR_ANDROID) # Android part - tvm_file_glob(GLOB RUNTIME_HEXAGON_SRCS src/runtime/hexagon/host/*.cc) - tvm_file_glob(GLOB RUNTIME_HEXAGON_SRCS "${TVMRT_SOURCE_DIR}/hexagon/rpc/android/*.cc") - list(APPEND RUNTIME_HEXAGON_SRCS "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_stub.c") + find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") + add_android_paths() + build_rpc_idl() + file_glob_append(RUNTIME_HEXAGON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/host/*.cc" + "${TVMRT_SOURCE_DIR}/hexagon/rpc/android/*.cc" + ) + # Add this file separately, because it's auto-generated, and glob won't + # find it during cmake-time. + list(APPEND RUNTIME_HEXAGON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_stub.c" + ) + list(APPEND TVM_RUNTIME_LINKER_LIBS cdsprpc) elseif(BUILD_FOR_HEXAGON) # Hexagon part + find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") find_hexagon_toolchain() - message(STATUS "HEXAGON_TOOLCHAIN: ${HEXAGON_TOOLCHAIN}") + build_rpc_idl() - add_library(hexagon_rpc_skel SHARED - "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_skel.c" - "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon/rpc_server.cc" + # Include the generic RPC code into the TVM runtime. + list(APPEND RUNTIME_HEXAGON_SRCS "${TVMRT_SOURCE_DIR}/minrpc/minrpc_server.h" "${TVMRT_SOURCE_DIR}/minrpc/rpc_reference.h" "${TVMRT_SOURCE_DIR}/rpc/rpc_module.cc" @@ -140,60 +248,33 @@ if(USE_HEXAGON_RPC) "${TVMRT_SOURCE_DIR}/rpc/rpc_session.cc" "${TVMRT_SOURCE_DIR}/rpc/rpc_local_session.cc" ) + # Add the hardware-specific RPC code into the skel library. + add_library(hexagon_rpc_skel SHARED + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon/rpc_server.cc" + "${TVMRT_SOURCE_DIR}/hexagon/rpc/hexagon_rpc_skel.c" + ) target_include_directories(hexagon_rpc_skel SYSTEM PRIVATE "${TVMRT_SOURCE_DIR}/hexagon/rpc" ) - endif() -endif() - -if(USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}") - find_hexagon_toolchain() - message(STATUS "Hexagon toolchain: ${HEXAGON_TOOLCHAIN}") - tvm_file_glob(GLOB RUNTIME_HEXAGON_SIM_SRCS src/runtime/hexagon/android/sim/*.cc) - include_directories(SYSTEM "${HEXAGON_TOOLCHAIN}/include/iss") - link_directories("${HEXAGON_TOOLCHAIN}/lib/iss") - list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper") - ExternalProject_Add(sim_dev - SOURCE_DIR "${CMAKE_SOURCE_DIR}/src/runtime/hexagon/android/sim/driver" - CMAKE_ARGS - "-DCMAKE_C_COMPILER=${HEXAGON_TOOLCHAIN}/bin/hexagon-clang" - "-DCMAKE_CXX_COMPILER=${HEXAGON_TOOLCHAIN}/bin/hexagon-clang++" - "-DHEXAGON_ARCH=${USE_HEXAGON_ARCH}" - INSTALL_COMMAND "true" - ) -elseif(USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}") - find_hexagon_sdk_root("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}") - find_hexagon_toolchain() - tvm_file_glob(GLOB RUNTIME_HEXAGON_DEVICE_SRCS src/runtime/hexagon/android/target/*.cc) - - include_directories(SYSTEM - ${HEXAGON_SDK_INCLUDES} - ${HEXAGON_RPCMEM_ROOT}/inc - ${HEXAGON_REMOTE_ROOT} - ) + # Add the simulator-specific RPC code into a shared library to be + # executed via run_main_on_sim. + add_library(hexagon_rpc_sim SHARED + "${TVMRT_SOURCE_DIR}/hexagon/rpc/simulator/rpc_server.cc" + ) + target_link_libraries(hexagon_rpc_sim + -Wl,--whole-archive tvm_runtime -Wl,--no-whole-archive + ) - list(APPEND TVM_RUNTIME_LINKER_LIBS "dl") - if(BUILD_FOR_ANDROID) - # Hexagon runtime uses __android_log_print, which is in liblog. - list(APPEND TVM_RUNTIME_LINKER_LIBS "log") + elseif(BUILD_FOR_HOST) + find_hexagon_toolchain() + add_hexagon_wrapper_paths() + file_glob_append(RUNTIME_HEXAGON_SRCS + "${TVMRT_SOURCE_DIR}/hexagon/host/*.cc" + "${TVMRT_SOURCE_DIR}/hexagon/rpc/simulator/session.cc" + ) + list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper") endif() -endif() +endif() # USE_HEXAGON_RPC -set(RUNTIME_HEXAGON_COMMON_SRCS src/runtime/hexagon/hexagon_module.cc) -if (USE_HEXAGON_DEVICE STREQUAL "${PICK_NONE}") - if(BUILD_FOR_HEXAGON) - tvm_file_glob(GLOB RUNTIME_HEXAGON_SRCS src/runtime/hexagon/hexagon/*.cc) - elseif(BUILD_FOR_ANDROID AND HEXAGON_SDK_PATH_DEFINED) - else() - tvm_file_glob(GLOB RUNTIME_HEXAGON_SRCS src/runtime/hexagon/host/*.cc) - endif() -else() - tvm_file_glob(GLOB RUNTIME_HEXAGON_SRCS src/runtime/hexagon/android/*.cc) -endif() -list(APPEND RUNTIME_SRCS - ${RUNTIME_HEXAGON_SRCS} - ${RUNTIME_HEXAGON_SIM_SRCS} - ${RUNTIME_HEXAGON_DEVICE_SRCS} - ${RUNTIME_HEXAGON_COMMON_SRCS} -) +list(APPEND RUNTIME_SRCS ${RUNTIME_HEXAGON_SRCS}) diff --git a/cmake/modules/RustExt.cmake b/cmake/modules/RustExt.cmake index 2922bc48dee2..e30caf0a0b04 100644 --- a/cmake/modules/RustExt.cmake +++ b/cmake/modules/RustExt.cmake @@ -16,8 +16,8 @@ # under the License. if(USE_RUST_EXT) - set(RUST_SRC_DIR "${CMAKE_SOURCE_DIR}/rust") - set(CARGO_OUT_DIR "${CMAKE_SOURCE_DIR}/rust/target") + set(RUST_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust") + set(CARGO_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rust/target") if(USE_RUST_EXT STREQUAL "STATIC") set(COMPILER_EXT_PATH "${CARGO_OUT_DIR}/release/libcompiler_ext.a") diff --git a/cmake/modules/StandaloneCrt.cmake b/cmake/modules/StandaloneCrt.cmake index e63521e26dbf..c6e6dc77b442 100644 --- a/cmake/modules/StandaloneCrt.cmake +++ b/cmake/modules/StandaloneCrt.cmake @@ -57,7 +57,7 @@ if(USE_MICRO) math(EXPR job_spec_stop "${job_spec_length} - 3") list(GET job_spec 0 job_src_base) - set(job_src_base "${CMAKE_SOURCE_DIR}/${job_src_base}") + set(job_src_base "${CMAKE_CURRENT_SOURCE_DIR}/${job_src_base}") foreach(copy_pattern_index RANGE 1 "${job_spec_stop}" 3) list(GET job_spec ${copy_pattern_index} copy_pattern) math(EXPR copy_dest_index "${copy_pattern_index} + 2") @@ -93,7 +93,7 @@ if(USE_MICRO) endforeach() set(make_common_args - "CRT_CONFIG=${CMAKE_SOURCE_DIR}/src/runtime/micro/crt_config.h" + "CRT_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/micro/crt_config.h" "BUILD_DIR=${host_build_dir_abspath}" "EXTRA_CFLAGS=-fPIC" "EXTRA_CXXFLAGS=-fPIC" @@ -124,9 +124,9 @@ if(USE_MICRO) # Create the `crttest` target if we can find GTest. If not, we create dummy # targets that give the user an informative error message. if(GTEST_FOUND) - tvm_file_glob(GLOB TEST_SRCS ${CMAKE_SOURCE_DIR}/tests/crt/*.cc) + tvm_file_glob(GLOB TEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/tests/crt/*.cc) add_executable(crttest ${TEST_SRCS}) - target_include_directories(crttest SYSTEM PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/standalone_crt/include ${CMAKE_SOURCE_DIR}/src/runtime/micro) + target_include_directories(crttest SYSTEM PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/standalone_crt/include ${CMAKE_CURRENT_SOURCE_DIR}/src/runtime/micro) target_link_libraries(crttest PRIVATE ${cmake_crt_libraries} GTest::GTest GTest::Main pthread dl) set_target_properties(crttest PROPERTIES EXCLUDE_FROM_ALL 1) set_target_properties(crttest PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1) diff --git a/cmake/modules/Zephyr.cmake b/cmake/modules/Zephyr.cmake index 048240375cd6..a1cafce29d6e 100644 --- a/cmake/modules/Zephyr.cmake +++ b/cmake/modules/Zephyr.cmake @@ -43,7 +43,7 @@ if(USE_MICRO) math(EXPR job_spec_stop "${job_spec_length} - 3") list(GET job_spec 0 job_src_base) - set(job_src_base "${CMAKE_SOURCE_DIR}/${job_src_base}") + set(job_src_base "${CMAKE_CURRENT_SOURCE_DIR}/${job_src_base}") foreach(copy_pattern_index RANGE 1 "${job_spec_stop}" 3) list(GET job_spec ${copy_pattern_index} copy_pattern) math(EXPR copy_dest_index "${copy_pattern_index} + 2") diff --git a/cmake/modules/contrib/EthosN.cmake b/cmake/modules/contrib/EthosN.cmake index 244f461b251d..dbf5549180aa 100644 --- a/cmake/modules/contrib/EthosN.cmake +++ b/cmake/modules/contrib/EthosN.cmake @@ -40,8 +40,7 @@ if(NOT USE_ETHOSN STREQUAL "OFF") list(APPEND TVM_LINKER_LIBS ${ETHOSN_COMPILER_LIBRARY} ${ETHOSN_RUNTIME_LIBRARY}) - list(APPEND TVM_RUNTIME_LINKER_LIBS ${ETHOSN_COMPILER_LIBRARY} - ${ETHOSN_RUNTIME_LIBRARY}) + list(APPEND TVM_RUNTIME_LINKER_LIBS ${ETHOSN_RUNTIME_LIBRARY}) if(NOT MSVC) set_source_files_properties(${COMPILER_ETHOSN_SRCS} diff --git a/cmake/utils/FindEthosN.cmake b/cmake/utils/FindEthosN.cmake index 3b01374e1959..07eaf5ddeee1 100644 --- a/cmake/utils/FindEthosN.cmake +++ b/cmake/utils/FindEthosN.cmake @@ -58,7 +58,16 @@ macro(find_ethosn use_ethosn) PATHS ${__ethosn_stack}/lib) find_library(ETHOSN_COMPILER_LIBRARY NAMES EthosNSupport) - set(ETHOSN_PACKAGE_VERSION "0.1.1") + list(GET ETHOSN_INCLUDE_DIRS 0 filename) + set(filename "${filename}/ethosn_support_library/Support.hpp") + file(READ ${filename} ETHOSN_SUPPORT_H) + string(REGEX MATCH "VERSION_MAJOR ([0-9]*)" _ ${ETHOSN_SUPPORT_H}) + set(ver_major ${CMAKE_MATCH_1}) + string(REGEX MATCH "VERSION_MINOR ([0-9]*)" _ ${ETHOSN_SUPPORT_H}) + set(ver_minor ${CMAKE_MATCH_1}) + string(REGEX MATCH "VERSION_PATCH ([0-9]*)" _ ${ETHOSN_SUPPORT_H}) + set(ver_patch ${CMAKE_MATCH_1}) + set(ETHOSN_PACKAGE_VERSION "${ver_major}.${ver_minor}.${ver_patch}") set(ETHOSN_DEFINITIONS -DETHOSN_API_VERSION=${USE_ETHOSN_API_VERSION}) # Runtime hardware support. Driver library also needed for diff --git a/docker/Dockerfile.ci_cpu b/docker/Dockerfile.ci_cpu index 962d738a9fc2..9f9f9a0b07c1 100644 --- a/docker/Dockerfile.ci_cpu +++ b/docker/Dockerfile.ci_cpu @@ -16,7 +16,6 @@ # under the License. # CI docker CPU env -# tag: v0.62 FROM ubuntu:18.04 RUN apt-get update --fix-missing @@ -33,8 +32,8 @@ RUN pip config set global.no-cache-dir false COPY install/ubuntu_install_python_package.sh /install/ubuntu_install_python_package.sh RUN bash /install/ubuntu_install_python_package.sh -COPY install/ubuntu1804_install_llvm.sh /install/ubuntu1804_install_llvm.sh -RUN bash /install/ubuntu1804_install_llvm.sh +COPY install/ubuntu_install_llvm_source.sh /install/ubuntu1804_install_llvm_source.sh +RUN bash /install/ubuntu1804_install_llvm_source.sh COPY install/ubuntu_install_dnnl.sh /install/ubuntu_install_dnnl.sh RUN bash /install/ubuntu_install_dnnl.sh @@ -99,6 +98,10 @@ COPY install/ubuntu_download_arm_compute_lib_binaries.sh /install/ubuntu_downloa RUN bash /install/ubuntu_download_arm_compute_lib_binaries.sh # Caffe deps +COPY install/ubuntu_install_boost.sh /install/ubuntu_install_boost.sh +RUN bash /install/ubuntu_install_boost.sh + +# Caffe COPY install/ubuntu_install_caffe.sh /install/ubuntu_install_caffe.sh RUN bash /install/ubuntu_install_caffe.sh diff --git a/docker/Dockerfile.ci_hexagon b/docker/Dockerfile.ci_hexagon new file mode 100644 index 000000000000..f1293019bbba --- /dev/null +++ b/docker/Dockerfile.ci_hexagon @@ -0,0 +1,54 @@ +# 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. + +# CI docker Hexagon env +# tag: v0.01 +FROM tvmcihexagon/ci-hexagon-base:v0.01_SDK4.2.0.2 + +RUN apt-get update --fix-missing +RUN apt-get install -y ca-certificates gnupg2 libxml2-dev + +COPY install/ubuntu_install_core.sh /install/ubuntu_install_core.sh +RUN bash /install/ubuntu_install_core.sh + +COPY install/ubuntu1804_install_python.sh /install/ubuntu1804_install_python.sh +RUN bash /install/ubuntu1804_install_python.sh + +# Globally disable pip cache +RUN pip config set global.cache-dir false + +COPY install/ubuntu_install_python_package.sh /install/ubuntu_install_python_package.sh +RUN bash /install/ubuntu_install_python_package.sh + +# ANTLR deps +COPY install/ubuntu_install_java.sh /install/ubuntu_install_java.sh +RUN bash /install/ubuntu_install_java.sh + +# Android SDK +COPY install/ubuntu_install_androidsdk.sh /install/ubuntu_install_androidsdk.sh +RUN bash /install/ubuntu_install_androidsdk.sh +ENV ANDROID_HOME=/opt/android-sdk-linux +ENV ANDROID_NDK_HOME=/opt/android-sdk-linux/ndk/21.3.6528147 +ENV PATH /opt/android-sdk-linux/platform-tools:$PATH + +# Hexagon +# HEXAGON_SDK_PATH is and env variable in tvmcihexagon/ci-hexagon-base +COPY install/ubuntu_install_hexagon.sh /install/ubuntu_install_hexagon.sh +RUN bash /install/ubuntu_install_hexagon.sh +ENV CLANG_LLVM_HOME /opt/clang-llvm +ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/opt/clang-llvm/lib +ENV HEXAGON_TOOLCHAIN "${HEXAGON_SDK_PATH}/tools/HEXAGON_Tools/8.4.09/Tools" diff --git a/docker/Dockerfile.ci_i386 b/docker/Dockerfile.ci_i386 index d4ce370c4205..e5e02b9755e4 100644 --- a/docker/Dockerfile.ci_i386 +++ b/docker/Dockerfile.ci_i386 @@ -18,7 +18,7 @@ # CI docker i386 env # tag: v0.53 -FROM ioft/i386-ubuntu:16.04 +FROM i386/ubuntu:18.04 RUN apt-get update --fix-missing && apt-get install -y ca-certificates @@ -28,8 +28,8 @@ RUN bash /install/ubuntu_install_core.sh COPY install/ubuntu_install_llvm.sh /install/ubuntu_install_llvm.sh RUN bash /install/ubuntu_install_llvm.sh -COPY install/ubuntu_install_python.sh /install/ubuntu_install_python.sh -RUN bash /install/ubuntu_install_python.sh +COPY install/ubuntu1804_install_python.sh /install/ubuntu1804_install_python.sh +RUN bash /install/ubuntu1804_install_python.sh # Globally disable pip cache RUN pip config set global.no-cache-dir false diff --git a/docker/bash.sh b/docker/bash.sh index 6f31aa7a5180..4a695c96f0ce 100755 --- a/docker/bash.sh +++ b/docker/bash.sh @@ -314,7 +314,7 @@ fi # PID namespace (--pid=host). The process inside does not have pid 1 # and SIGKILL is propagated to the process inside, allowing jenkins to # kill it if needed. -DOCKER_FLAGS+=( --rm --pid=host) +DOCKER_FLAGS+=( --pid=host) # Expose services running in container to the host. if $USE_NET_HOST; then diff --git a/docker/build.sh b/docker/build.sh index 39fe7a024246..de320115e2cd 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -79,7 +79,7 @@ if [[ "$1" == "--net=host" ]]; then shift 1 fi -DOCKER_NO_CACHE_ARG=--no-cache +#DOCKER_NO_CACHE_ARG=--no-cache if [[ "$1" == "--cache-from" ]]; then shift 1 diff --git a/docker/dev_common.sh b/docker/dev_common.sh index 6823f754ae16..11ba34eb06e2 100644 --- a/docker/dev_common.sh +++ b/docker/dev_common.sh @@ -56,6 +56,11 @@ function lookup_image_spec() { } function run_docker() { + docker_bash_args=( ) + while [ "x${1:0:1}" == "x-" ]; do + docker_bash_args=( "${docker_bash_args[@]}" "$1" ) + shift + done image_name="$1" # Name of the Jenkinsfile var to find shift @@ -65,5 +70,6 @@ function run_docker() { exit 2 fi - "${GIT_TOPLEVEL}/docker/bash.sh" "${image_spec}" "$@" + docker_bash_args=( "${docker_bash_args[@]}" "${image_spec}" "$@" ) + "${GIT_TOPLEVEL}/docker/bash.sh" "${docker_bash_args[@]}" } diff --git a/docker/install/ubuntu1804_install_python.sh b/docker/install/ubuntu1804_install_python.sh index 5d39918f918c..4676ffb8b20d 100755 --- a/docker/install/ubuntu1804_install_python.sh +++ b/docker/install/ubuntu1804_install_python.sh @@ -20,13 +20,27 @@ set -e set -u set -o pipefail -# install python and pip, don't modify this, modify install_python_package.sh + +cleanup() { + rm -rf base-requirements.txt +} + +trap cleanup 0 + + +# Install python and pip. Don't modify this to add Python package dependencies, +# instead modify install_python_package.sh apt-get update apt-get install -y software-properties-common -apt-get install -y python3-dev python3-setuptools - -# Install pip -cd /tmp && wget -q https://bootstrap.pypa.io/pip/3.6/get-pip.py && python3 get-pip.py +apt-get install -y python3.7 python3.7-dev python3-pip +update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1 # Pin pip and setuptools versions -pip3 install pip==19.3.1 setuptools==58.4.0 +# Hashes generated via: +# $ pip download == +# $ pip hash --algorithm sha512 .whl +cat < base-requirements.txt +pip==22.0.3 --hash=sha512:12ca75130a1ce9807060a66dd2341afc7c7e663357ca4b937868dbc733634e11bae49ffff96acb0f5f3fb16cb14f680b9b6d185155a711c6098eda5cfbf2f8f5 +setuptools==60.9.1 --hash=sha512:24c21006f0650209e6a934a5366614e32a98fbdf11bc0e941419731aa3c8cb6d217e486608b4834b8f89c14dc36b3bafa30e795c87b58705be2b156f78acc3c5 +EOF +pip3 install -r base-requirements.txt diff --git a/docker/install/ubuntu_install_boost.sh b/docker/install/ubuntu_install_boost.sh new file mode 100644 index 000000000000..e226bbc5d96e --- /dev/null +++ b/docker/install/ubuntu_install_boost.sh @@ -0,0 +1,38 @@ +#!/bin/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 -euxo pipefail + +cleanup() { + rm -rf /boost_1_67_0 /boost_1_67_0.tar.gz +} + +trap cleanup 0 + +curl -LO https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.gz +BOOST_HASH=8c247e040303a97895cee9c9407ef205e2c3ab09f0b8320997835ad6221dff23a87231629498ccfd0acca473f74e9ec27b8bd774707b062228df1e5f72d44c92 +echo "$BOOST_HASH" boost_1_67_0.tar.gz | sha512sum -c +tar -xf boost_1_67_0.tar.gz + +pushd boost_1_67_0 +./bootstrap.sh --with-python="$(which python3.7)" +./b2 install --with-python --with-system --with-filesystem --with-thread --with-regex +popd + +ln -s /usr/local/lib/libboost_python37.so.1.67.0 /usr/local/lib/libboost_python.so +ln -s /usr/local/lib/libboost_python37.a /usr/local/lib/libboost_python.a diff --git a/docker/install/ubuntu_install_caffe.sh b/docker/install/ubuntu_install_caffe.sh index b26f339c3fa1..ab71eab54a2d 100644 --- a/docker/install/ubuntu_install_caffe.sh +++ b/docker/install/ubuntu_install_caffe.sh @@ -16,17 +16,15 @@ # specific language governing permissions and limitations # under the License. -set -e -set -u -set -o pipefail +set -euxo pipefail apt-get update --fix-missing -# Install dependencies -apt-get install -y --no-install-recommends libboost-filesystem-dev libboost-python-dev \ - libboost-system-dev libboost-thread-dev libboost-regex-dev protobuf-compiler \ +# # Install dependencies +apt-get install -y --no-install-recommends protobuf-compiler \ libprotobuf-dev libhdf5-serial-dev libopenblas-dev libgflags-dev libgoogle-glog-dev + # install python packages pip install "numpy" "protobuf" "scikit-image" "six" @@ -36,15 +34,23 @@ CAFFE_HOME="/opt/caffe" git clone --branch=ssd --depth 1 https://github.com/weiliu89/caffe /caffe_src cd /caffe_src + echo "Building Caffe" mkdir /caffe_src/build && cd /caffe_src/build -cmake .. -DCMAKE_INSTALL_PREFIX=${CAFFE_HOME} -DCMAKE_BUILD_TYPE=Release -DCPU_ONLY=1 \ - -Dpython_version=3 -DUSE_OPENCV=OFF -DUSE_LEVELDB=OFF -DUSE_LMDB=OFF -DBUILD_docs=OFF -DBLAS=open +cmake -DCMAKE_INSTALL_PREFIX=${CAFFE_HOME}\ + -DCMAKE_BUILD_TYPE=Release \ + -DCPU_ONLY=1 \ + -Dpython_version=3 \ + -DUSE_OPENCV=OFF \ + -DUSE_LEVELDB=OFF \ + -DUSE_LMDB=OFF \ + -DBUILD_docs=OFF \ + -DBLAS=open \ + .. + make all -j$(expr $(nproc) - 1) make pycaffe -j$(expr $(nproc) - 1) make test -j$(expr $(nproc) - 1) -make runtest -j$(expr $(nproc) - 1) -make pytest -j$(expr $(nproc) - 1) echo "Installing Caffe to /opt/caffe" make install @@ -54,4 +60,4 @@ cd / && rm -rf /caffe_src PYCAFFE_ROOT=${CAFFE_HOME}/python echo "${CAFFE_HOME}/lib" >> /etc/ld.so.conf.d/caffe.conf && ldconfig -ln -s ${PYCAFFE_ROOT}/caffe /usr/local/lib/python3.6/dist-packages/caffe +ln -s ${PYCAFFE_ROOT}/caffe /usr/local/lib/python3.7/dist-packages/caffe diff --git a/docker/install/ubuntu_install_dnnl.sh b/docker/install/ubuntu_install_dnnl.sh index fb0efd52a2c1..34f917ce6606 100755 --- a/docker/install/ubuntu_install_dnnl.sh +++ b/docker/install/ubuntu_install_dnnl.sh @@ -21,9 +21,9 @@ set -u set -o pipefail cd /usr/local/ -wget -q https://github.com/oneapi-src/oneDNN/releases/download/v1.5/dnnl_lnx_1.5.0_cpu_gomp.tgz -tar -xzf dnnl_lnx_1.5.0_cpu_gomp.tgz -mv dnnl_lnx_1.5.0_cpu_gomp/include/* /usr/local/include/ -mv dnnl_lnx_1.5.0_cpu_gomp/lib/libdnnl* /usr/local/lib/ -rm -rf dnnl_lnx_1.5.0_cpu_gomp.tgz dnnl_lnx_1.5.0_cpu_gomp +wget -q https://github.com/oneapi-src/oneDNN/releases/download/v2.2/dnnl_lnx_2.2.0_cpu_gomp.tgz +tar -xzf dnnl_lnx_2.2.0_cpu_gomp.tgz +mv dnnl_lnx_2.2.0_cpu_gomp/include/* /usr/local/include/ +mv dnnl_lnx_2.2.0_cpu_gomp/lib/libdnnl* /usr/local/lib/ +rm -rf dnnl_lnx_2.2.0_cpu_gomp.tgz dnnl_lnx_2.2.0_cpu_gomp cd - diff --git a/docker/install/ubuntu_install_hexagon.sh b/docker/install/ubuntu_install_hexagon.sh new file mode 100644 index 000000000000..46d2a44cfaa5 --- /dev/null +++ b/docker/install/ubuntu_install_hexagon.sh @@ -0,0 +1,29 @@ +#!/bin/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 -o errexit -o nounset +set -o pipefail + +# Install LLVM/clang +CLANG_LLVM_HOME=/opt/clang-llvm +CLANG_LLVM_VERSION=13.0.0 +CLANG_LLVM_FILENAME=clang_llvm.tar.xz +wget -q https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_LLVM_VERSION}/clang+llvm-${CLANG_LLVM_VERSION}-x86_64-linux-gnu-ubuntu-16.04.tar.xz -O ${CLANG_LLVM_FILENAME} +mkdir ${CLANG_LLVM_HOME} +tar -xvf ${CLANG_LLVM_FILENAME} -C ${CLANG_LLVM_HOME} --strip-components=1 +rm ${CLANG_LLVM_FILENAME} diff --git a/docker/install/ubuntu_install_llvm.sh b/docker/install/ubuntu_install_llvm.sh index 1f4eec6ee6ef..6616bfc5eb2b 100755 --- a/docker/install/ubuntu_install_llvm.sh +++ b/docker/install/ubuntu_install_llvm.sh @@ -16,9 +16,10 @@ # specific language governing permissions and limitations # under the License. -set -e -set -u -set -o pipefail +set -euxo pipefail + +apt-get update +apt-get install -y gnupg echo deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main\ >> /etc/apt/sources.list.d/llvm.list @@ -46,4 +47,4 @@ echo deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main\ >> /etc/apt/sources.list.d/llvm.list wget -q -O - http://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - -apt-get update && apt-get install -y llvm-4.0 llvm-9 llvm-8 llvm-7 clang-9 libclang-9-dev clang-8 libclang-8-dev clang-7 libclang-7-dev +apt-get install -y llvm-4.0 llvm-9 llvm-8 llvm-7 clang-9 libclang-9-dev clang-8 libclang-8-dev clang-7 libclang-7-dev diff --git a/docker/lint.sh b/docker/lint.sh index 4bad5ea3b923..a968bc1e6421 100755 --- a/docker/lint.sh +++ b/docker/lint.sh @@ -37,6 +37,9 @@ function run_lint_step() { ;; asf) cmd=( tests/lint/check_asf_header.sh --local ) + if [ $inplace_fix -eq 1 ]; then + cmd=( "${cmd[@]}" --fix ) + fi ;; clang_format) if [ $inplace_fix -eq 0 ]; then @@ -77,6 +80,9 @@ function run_lint_step() { echo "error: don't know how to run lint step: $1" >&2 echo "usage: ${SCRIPT_NAME} [-i] " >&2 echo >&2 + echo "options:" >&2 + echo " -i Fix lint errors in-place where possible (modifies non-compliant files)" >&2 + echo >&2 echo "available lint_step: ${DEFAULT_STEPS[@]}" >&2 exit 2 ;; @@ -84,7 +90,7 @@ function run_lint_step() { shift if [ $validate_only -eq 0 ]; then - run_docker "ci_lint" "${cmd[@]}" + run_docker -it "ci_lint" "${cmd[@]}" fi } diff --git a/docker/with_the_same_user b/docker/with_the_same_user index 89ae8f5044da..f8ebc1482d1e 100644 --- a/docker/with_the_same_user +++ b/docker/with_the_same_user @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -x # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file diff --git a/docs/reference/api/python/contrib.rst b/docs/reference/api/python/contrib.rst index 0eb3024c2d08..52d3faff0fc4 100644 --- a/docs/reference/api/python/contrib.rst +++ b/docs/reference/api/python/contrib.rst @@ -93,6 +93,16 @@ tvm.contrib.random :members: +tvm.contrib.relay_viz +~~~~~~~~~~~~~~~~~~~~~ +.. automodule:: tvm.contrib.relay_viz + :members: +.. automodule:: tvm.contrib.relay_viz.interface + :members: +.. automodule:: tvm.contrib.relay_viz.terminal + :members: + + tvm.contrib.rocblas ~~~~~~~~~~~~~~~~~~~ .. automodule:: tvm.contrib.rocblas diff --git a/gallery/how_to/work_with_relay/using_relay_viz.py b/gallery/how_to/work_with_relay/using_relay_viz.py new file mode 100644 index 000000000000..f61fc41f4f14 --- /dev/null +++ b/gallery/how_to/work_with_relay/using_relay_viz.py @@ -0,0 +1,159 @@ +# 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. +# pylint: disable=line-too-long +""" +Use Relay Visualizer to Visualize Relay +============================================================ +**Author**: `Chi-Wei Wang `_ + +Relay IR module can contain lots of operations. Although an individual +operation is usually easy to understand, putting them together can cause +a complicated, hard-to-read graph. Things can get even worse with optimiztion-passes +coming into play. + +This utility visualizes an IR module as nodes and edges. It defines a set of interfaces including +parser, plotter(renderer), graph, node, and edges. +A default parser is provided. Users can implement their own renderers to render the graph. + +Here we use a renderer rendering graph in the text-form. +It is a lightweight, AST-like visualizer, inspired by `clang ast-dump `_. +We will introduce how to implement customized parsers and renderers through interface classes. +""" +from typing import ( + Dict, + Union, + Tuple, + List, +) +import tvm +from tvm import relay +from tvm.contrib import relay_viz +from tvm.contrib.relay_viz.interface import ( + VizEdge, + VizNode, + VizParser, +) +from tvm.contrib.relay_viz.terminal import ( + TermGraph, + TermPlotter, + TermVizParser, +) + +###################################################################### +# Define a Relay IR Module with multiple GlobalVar +# ------------------------------------------------ +# Let's build an example Relay IR Module containing multiple ``GlobalVar``. +# We define an ``add`` function and call it in the main function. +data = relay.var("data") +bias = relay.var("bias") +add_op = relay.add(data, bias) +add_func = relay.Function([data, bias], add_op) +add_gvar = relay.GlobalVar("AddFunc") + +input0 = relay.var("input0") +input1 = relay.var("input1") +input2 = relay.var("input2") +add_01 = relay.Call(add_gvar, [input0, input1]) +add_012 = relay.Call(add_gvar, [input2, add_01]) +main_func = relay.Function([input0, input1, input2], add_012) +main_gvar = relay.GlobalVar("main") + +mod = tvm.IRModule({main_gvar: main_func, add_gvar: add_func}) + +###################################################################### +# Render the graph with Relay Visualizer on the terminal +# ------------------------------------------------------ +# The terminal can show a Relay IR module in text similar to clang AST-dump. +# We should see ``main`` and ``AddFunc`` function. ``AddFunc`` is called twice in the ``main`` function. +viz = relay_viz.RelayVisualizer(mod) +viz.render() + +###################################################################### +# Customize Parser for Interested Relay Types +# ------------------------------------------- +# Sometimes we want to emphasize interested information, or parse things differently for a specific usage. +# It is possible to provide customized parsers as long as it obeys the interface. +# Here demostrate how to customize parsers for ``relay.var``. +# We need to implement abstract interface :py:class:`tvm.contrib.relay_viz.interface.VizParser`. +class YourAwesomeParser(VizParser): + def __init__(self): + self._delegate = TermVizParser() + + def get_node_edges( + self, + node: relay.Expr, + relay_param: Dict[str, tvm.runtime.NDArray], + node_to_id: Dict[relay.Expr, str], + ) -> Tuple[Union[VizNode, None], List[VizEdge]]: + + if isinstance(node, relay.Var): + node = VizNode(node_to_id[node], "AwesomeVar", f"name_hint {node.name_hint}") + # no edge is introduced. So return an empty list. + return node, [] + + # delegate other types to the other parser. + return self._delegate.get_node_edges(node, relay_param, node_to_id) + + +###################################################################### +# Pass the parser and an interested renderer to visualizer. +# Here we just the terminal renderer. +viz = relay_viz.RelayVisualizer(mod, {}, TermPlotter(), YourAwesomeParser()) +viz.render() + +###################################################################### +# Customization around Graph and Plotter +# ------------------------------------------- +# Besides parsers, we can also customize graph and renderers by implementing +# abstract class :py:class:`tvm.contrib.relay_viz.interface.VizGraph` and +# :py:class:`tvm.contrib.relay_viz.interface.Plotter`. +# Here we override the ``TermGraph`` defined in ``terminal.py`` for easier demo. +# We add a hook duplicating above ``AwesomeVar``, and make ``TermPlotter`` use the new class. +class AwesomeGraph(TermGraph): + def node(self, viz_node): + # add the node first + super().node(viz_node) + # if it's AwesomeVar, duplicate it. + if viz_node.type_name == "AwesomeVar": + duplicated_id = f"duplciated_{viz_node.identity}" + duplicated_type = "double AwesomeVar" + super().node(VizNode(duplicated_id, duplicated_type, "")) + # connect the duplicated var to the original one + super().edge(VizEdge(duplicated_id, viz_node.identity)) + + +# override TermPlotter to use `AwesomeGraph` instead +class AwesomePlotter(TermPlotter): + def create_graph(self, name): + self._name_to_graph[name] = AwesomeGraph(name) + return self._name_to_graph[name] + + +viz = relay_viz.RelayVisualizer(mod, {}, AwesomePlotter(), YourAwesomeParser()) +viz.render() + +###################################################################### +# Summary +# ------- +# This tutorial demonstrates the usage of Relay Visualizer and customization. +# The class :py:class:`tvm.contrib.relay_viz.RelayVisualizer` is composed of interfaces +# defined in ``interface.py``. +# +# It is aimed for quick look-then-fix iterations. +# The constructor arguments are intended to be simple, while the customization is still +# possible through a set of interface classes. +# diff --git a/include/tvm/ir/expr.h b/include/tvm/ir/expr.h index 0e43abb54b93..4a00de802c61 100644 --- a/include/tvm/ir/expr.h +++ b/include/tvm/ir/expr.h @@ -178,6 +178,11 @@ class RelayExprNode : public BaseExprNode { * * For expressions that have the function type, the virtual device describes where the result of * the call to the function or closure is stored (instead of where the function itself is stored). + * For example, the virtual device of f = fn(x) { body } is the virtual device of f(y), not where + * the function itself is stored. Note that f(y)'s virtual device will be the same as the virtual + * device of body. For more details, see the documentation in + * src/relay/transforms/device_planner.cc. + * * The VirtualDevice's Target field describes how the body of the function should be compiled. * * Set to VirtualDevice::FullyUnconstrained by default. @@ -190,6 +195,13 @@ class RelayExprNode : public BaseExprNode { /*! * \return The virtual device (VirtualDevice). * If the virtual device is not defined, returns VirtualDevice::FullyUnconstrained(). + * Note that for function types, the virtual device is the device where the result of a + * call to the function is stored, not where the function itself lives. + * For example, the virtual device of f = fn(x) { body } is the virtual device of f(y), not where + * the function itself is stored. Note that f(y)'s virtual device will be the same as the virtual + * device of body. + * + * See the documentation of the virtual_device_ field (above) for more details. */ VirtualDevice virtual_device() const; diff --git a/include/tvm/ir/function.h b/include/tvm/ir/function.h index 051c05dd3d01..1493544e7324 100644 --- a/include/tvm/ir/function.h +++ b/include/tvm/ir/function.h @@ -190,26 +190,6 @@ constexpr const char* kTarget = "target"; */ constexpr const char* kGlobalSymbol = "global_symbol"; -/*! - * \brief The \p VirtualDevice which will hold each of the functions parameters. - * - * Only supported on Relay \p Functions. Generally added by the \p PlanDevices pass, but - * may be included as an annotation on user programs. - * - * Type: Array - */ -constexpr const char* kParamVirtualDevice = "param_virtual_devices"; - -/*! - * \brief The \p VirtualDevice which will hold the function result. - * - * Only supported on Relay \p Functions. Generally added by the \p PlanDevices pass, but - * may be included as an annotation on user programs. - * - * Type: VirtualDevice - */ -constexpr const char* kResultVirtualDevice = "result_virtual_device"; - } // namespace attr } // namespace tvm #endif // TVM_IR_FUNCTION_H_ diff --git a/include/tvm/ir/memory_pools.h b/include/tvm/ir/memory_pools.h index c6e52648ebd4..d4eefdc910b0 100644 --- a/include/tvm/ir/memory_pools.h +++ b/include/tvm/ir/memory_pools.h @@ -103,29 +103,34 @@ struct PoolInfoNode : public Object { TVM_DECLARE_FINAL_OBJECT_INFO(PoolInfoNode, Object); }; +/*! + * \brief The string parameter to indicate read and write access to a pool + * This needs to be kept in sync with PoolInfo.READ_WRITE_ACCESS in + * python/tvm/ir/memory_pools.py + */ +static constexpr const char* kTargetPoolReadWriteAccess = "rw"; + +/*! + * \brief The string parameter to indicate read only access to a pool + * This needs to be kept in sync with PoolInfo.READ_ONLY_ACCESS in + * python/tvm/ir/memory_pools.py + */ +static constexpr const char* kTargetPoolReadOnlyAccess = "ro"; + +/*! \brief The PoolSize is unrestricted for the memory planner */ +static const int kUnrestrictedPoolSizeHint = -1; + +/*! \brief The clock frequency is not known */ +static const int kUnknownClockFrequency = -1; + +/*! \brief The read bandwidth is not known */ +static const int kUnknownReadBandwidth = -1; + +/*! \brief The write bandwidth is not known */ +static const int kUnknownWriteBandwidth = -1; + class PoolInfo : public ObjectRef { public: - /*! - * \brief The string parameter to indicate read and write access to a pool - * This needs to be kept in sync with PoolInfo.READ_WRITE_ACCESS in - * python/tvm/ir/memory_pools.py - */ - static constexpr const char* kTargetPoolReadWriteAccess = "rw"; - /*! - * \brief The string parameter to indicate read only access to a pool - * This needs to be kept in sync with PoolInfo.READ_ONLY_ACCESS in - * python/tvm/ir/memory_pools.py - */ - static constexpr const char* kTargetPoolReadOnlyAccess = "ro"; - /*! \brief The PoolSize is unrestricted for the memory planner */ - static const int kUnrestrictedPoolSizeHint = -1; - /*! \brief The clock frequency is not known */ - static const int kUnknownClockFrequency = -1; - /*! \brief The read bandwidth is not known */ - static const int kUnknownReadBandwidth = -1; - /*! \brief The write bandwidth is not known */ - static const int kUnknownWriteBandwidth = -1; - TVM_DLL PoolInfo(String pool_name, Map target_access, Integer size_hint_bytes = kUnrestrictedPoolSizeHint, Integer clock_frequency_hz = kUnknownClockFrequency, diff --git a/include/tvm/ir/module.h b/include/tvm/ir/module.h index d308db87af8b..e2b47ef324df 100644 --- a/include/tvm/ir/module.h +++ b/include/tvm/ir/module.h @@ -40,7 +40,44 @@ #include namespace tvm { +/*! + * \brief Describes one parameter that should be linked into the generated module. + * + * When parameters are to be linked in with generated code (i.e. on target_host-compatible + * backends), Relay attaches instances of this object to a global TIR function. Code-generators + * use the information contained in this node to include the parameter data in the generated + * module. + */ +class LinkedParamNode : public Object { + public: + /*! \brief Unique numeric identifier used by runtimes to lookup this parameter. */ + int64_t id; + + /*! \brief Parameter data which should get linked into the final module. */ + ::tvm::runtime::NDArray param; + + void VisitAttrs(tvm::AttrVisitor* v) { + v->Visit("id", &id); + v->Visit("param", ¶m); + } + + static constexpr const char* _type_key = "tir.LinkedParam"; + TVM_DECLARE_FINAL_OBJECT_INFO(LinkedParamNode, Object); +}; + +/*! + * \brief Managed reference to LinkedParamNode. + */ +class LinkedParam : public ObjectRef { + public: + TVM_DLL LinkedParam(int64_t id, tvm::runtime::NDArray param); + + TVM_DEFINE_OBJECT_REF_METHODS(LinkedParam, ObjectRef, LinkedParamNode); + TVM_DEFINE_OBJECT_REF_COW_METHOD(LinkedParamNode); +}; + class IRModule; + /*! * \brief IRModule that holds functions and type definitions. * @@ -504,6 +541,11 @@ constexpr const char* kRuntime = "runtime"; */ constexpr const char* kWorkspaceMemoryPools = "workspace_memory_pools"; +/* + * \brief Module attribute for tir constants + */ +constexpr const char* kConstantsArray = "Constants"; + } // namespace attr } // namespace tvm #endif // TVM_IR_MODULE_H_ diff --git a/include/tvm/ir/transform.h b/include/tvm/ir/transform.h index cb556fc13de7..d8f6632a66ca 100644 --- a/include/tvm/ir/transform.h +++ b/include/tvm/ir/transform.h @@ -392,7 +392,62 @@ class Pass : public ObjectRef { TVM_DEFINE_OBJECT_REF_METHODS(Pass, ObjectRef, PassNode); }; -class SequentialNode; +/*! + * \brief The SequentialNode contains a set of passes that transform Relay + * programs from one AST to another semantically equivalent one. + * + * One example of this level of pass is that the pass manager needs to correctly + * perform a host of optimizations with a given optimization level and disabled + * passes. + */ +class SequentialNode : public PassNode { + public: + /* \brief The pass meta data.*/ + PassInfo pass_info; + + /*! \brief A list of passes that used to compose a sequential pass. */ + tvm::Array passes; + + void VisitAttrs(tvm::AttrVisitor* v) { + v->Visit("pass_info", &pass_info); + v->Visit("passes", &passes); + } + + /*! + * \brief Get the pass information/meta data. + */ + PassInfo Info() const override { return pass_info; } + + /*! + * \brief Resolve the pass dependency. It globs all required passes by + * a given pass and executes them. + * + * \param mod The module that an optimization pass runs on. + * + * \return The updated module after resolving pass dependencies. + * + * TODO(zhiics) Build a dependency graph among the passes using provided + * metadata, i.e. required_passes. Likely, we can have a data structure, i.e. + * PassInfo, to store the relevant information including the parent passes. + */ + void ResolveDependency(const IRModule& mod); + + /*! + * \brief Perform optimizations on a series of passes. The aforementioned + * typical pass manager jobs could be done by it. This function could + * be overloaded to focus on different metrics, i.e. performance, + * memory footprint, etc. + * + * \param mod The module that these passes are applied on. + * \param pass_ctx The context that these passes execute on. + * + * \return Return the updated module. + */ + IRModule operator()(IRModule mod, const PassContext& pass_ctx) const final; + + static constexpr const char* _type_key = "transform.Sequential"; + TVM_DECLARE_FINAL_OBJECT_INFO(SequentialNode, PassNode); +}; class Sequential : public Pass { public: @@ -418,7 +473,7 @@ class Sequential : public Pass { explicit Sequential(ObjectPtr n) : Pass(n) {} const SequentialNode* operator->() const; - using ContainerType = Sequential; + using ContainerType = SequentialNode; }; /* diff --git a/include/tvm/node/structural_hash.h b/include/tvm/node/structural_hash.h index 887a012cfc93..a30a2c59d0d1 100644 --- a/include/tvm/node/structural_hash.h +++ b/include/tvm/node/structural_hash.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -199,5 +200,13 @@ class SHashReducer { bool map_free_vars_; }; +class SEqualReducer; +struct NDArrayContainerTrait { + static constexpr const std::nullptr_t VisitAttrs = nullptr; + static void SHashReduce(const runtime::NDArray::Container* key, SHashReducer hash_reduce); + static bool SEqualReduce(const runtime::NDArray::Container* lhs, + const runtime::NDArray::Container* rhs, SEqualReducer equal); +}; + } // namespace tvm #endif // TVM_NODE_STRUCTURAL_HASH_H_ diff --git a/include/tvm/relay/dataflow_matcher.h b/include/tvm/relay/dataflow_matcher.h index 10e461645c8b..8dd5fbdd5eac 100644 --- a/include/tvm/relay/dataflow_matcher.h +++ b/include/tvm/relay/dataflow_matcher.h @@ -106,6 +106,17 @@ Expr RewritePatterns(Array callbacks, Expr expr, IRModule mod */ Expr PartitionPattern(DFPattern pattern, Expr expr, Map attrs, PackedFunc check); +/*! + * \brief Infer the type of an expression. + * + * \param expr The expression to rewrite + * + * \return Return An Expr with unambiguous type information filled in, as well as it's + * checked type field populated with the result type. + * + */ +Expr InferType(const Expr& expr); + } // namespace relay } // namespace tvm diff --git a/include/tvm/relay/executor.h b/include/tvm/relay/executor.h index 6d1bd2de7f57..858ba5cfe198 100644 --- a/include/tvm/relay/executor.h +++ b/include/tvm/relay/executor.h @@ -113,6 +113,8 @@ class ExecutorNode : public Object { } static constexpr const char* _type_key = "Executor"; + static constexpr const bool _type_has_method_sequal_reduce = true; + static constexpr const bool _type_has_method_shash_reduce = true; TVM_DECLARE_FINAL_OBJECT_INFO(ExecutorNode, Object); }; @@ -122,8 +124,6 @@ class ExecutorNode : public Object { */ class Executor : public ObjectRef { public: - Executor() = default; - /*! * \brief Create a new Executor object using the registry * \throws Error if name is not registered @@ -147,7 +147,8 @@ class Executor : public ObjectRef { TVM_DLL static Map ListExecutorOptions(const String& name); /*! \brief specify container node */ - TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(Executor, ObjectRef, ExecutorNode); + TVM_DEFINE_OBJECT_REF_METHODS(Executor, ObjectRef, ExecutorNode); + TVM_DEFINE_OBJECT_REF_COW_METHOD(ExecutorNode) private: /*! diff --git a/include/tvm/relay/expr_functor.h b/include/tvm/relay/expr_functor.h index f96faffb24f4..fab579d0edd9 100644 --- a/include/tvm/relay/expr_functor.h +++ b/include/tvm/relay/expr_functor.h @@ -476,8 +476,19 @@ void ExpandDataflow(Expr expr, FCheckVisited fcheck_visited, FVisitLeaf fvisit_l auto fexpand_expr = [](const Expr& expr) { std::vector result; if (const CallNode* op = expr.as()) { - for (auto it = op->args.rbegin(); it != op->args.rend(); ++it) { - result.push_back(*it); + if (op->op == Op::Get("call_lowered")) { + // Ignore the intermediate tuple since this is purely a calling-convention detail + const auto* tuple_args = op->args[1].as(); + ICHECK(tuple_args) + << "Expected second arg to call_lowered to be a Tuple of input arguments."; + for (auto it = tuple_args->fields.rbegin(); it != tuple_args->fields.rend(); ++it) { + result.push_back(*it); + } + result.push_back(op->args[0]); + } else { + for (auto it = op->args.rbegin(); it != op->args.rend(); ++it) { + result.push_back(*it); + } } result.push_back(op->op); } else if (const TupleNode* op = expr.as()) { diff --git a/include/tvm/relay/interpreter.h b/include/tvm/relay/interpreter.h index eed6d0ffc1e4..f71107258d9a 100644 --- a/include/tvm/relay/interpreter.h +++ b/include/tvm/relay/interpreter.h @@ -184,10 +184,12 @@ TypedPackedFunc)> EvalFunction(IRModule mod, Expr expr, De * \param import_set Already imported external modules. * \param device The device on which all primitives will be executed. * \param target The compiler target flag for compiling primitives. + * \param attrs Attributes for the expression to be evaluated with * @return The object representing the result. */ ObjectRef Eval(Expr expr, Map type_definitions, - std::unordered_set import_set, Device device, Target target); + std::unordered_set import_set, Device device, Target target, + Map attrs = {}); } // namespace relay } // namespace tvm diff --git a/include/tvm/relay/runtime.h b/include/tvm/relay/runtime.h index c4cabf5a5548..10e124bc339b 100644 --- a/include/tvm/relay/runtime.h +++ b/include/tvm/relay/runtime.h @@ -44,6 +44,12 @@ class AttrRegistry; namespace relay { +/*! \brief Value used with Runtime::name to indicate the C++ runtime. */ +static constexpr const char* kTvmRuntimeCpp = "cpp"; + +/*! \brief Value used with Runtime::name to indicate the C runtime. */ +static constexpr const char* kTvmRuntimeCrt = "crt"; + /*! * \brief Runtime information. * @@ -105,6 +111,8 @@ class RuntimeNode : public Object { } static constexpr const char* _type_key = "Runtime"; + static constexpr const bool _type_has_method_sequal_reduce = true; + static constexpr const bool _type_has_method_shash_reduce = true; TVM_DECLARE_FINAL_OBJECT_INFO(RuntimeNode, Object); }; diff --git a/include/tvm/relay/transform.h b/include/tvm/relay/transform.h index 4bbc2df0ae48..ea3a5dba6bf7 100644 --- a/include/tvm/relay/transform.h +++ b/include/tvm/relay/transform.h @@ -499,6 +499,10 @@ TVM_DLL Pass PlanDevices(CompilationConfig config); /*! * \brief Bind the free variables to a Relay expression. This is a helper * function usually called by other pass functions to help optimizations. + * If any free variables are introduced into a function, those are added + * to the functoin parameters. + * Additionally this may change the order of parameters if you map a variable + * to a variable. * * \param expr The input expression. * \param binds The variable to expression map that will be used to help the @@ -508,6 +512,19 @@ TVM_DLL Pass PlanDevices(CompilationConfig config); */ TVM_DLL Expr Bind(const Expr& expr, const tvm::Map& binds); +/*! + * \brief Substitute variables with new variables (including function parameters) in a function. + * This is a helper function usually called by other pass functions to help optimizations. + * Expects all values in the bind map to be Vars. + * + * \param func The input function. + * \param binds The variable to expression map that will be used to help the + * binding. + * + * \return The updated expression. + */ +TVM_DLL Function SubstituteBoundVars(const Function& func, const tvm::Map& binds); + /*! * \brief Apply rewrite rules to rewrite the expr in post DFS order. This * function is used as a helper function to rewrtie an expression in a pass. diff --git a/include/tvm/runtime/container/optional.h b/include/tvm/runtime/container/optional.h index bea4228c48b8..9961d5eeba0b 100644 --- a/include/tvm/runtime/container/optional.h +++ b/include/tvm/runtime/container/optional.h @@ -93,6 +93,11 @@ class Optional : public ObjectRef { ICHECK(data_ != nullptr); return T(data_); } + /*! + * \return The internal object pointer with container type of T. + * \note This function do not perform not-null checking. + */ + const ContainerType* get() const { return static_cast(data_.get()); } /*! * \return The contained value if the Optional is not null * otherwise return the default_value. diff --git a/include/tvm/runtime/metadata.h b/include/tvm/runtime/metadata.h new file mode 100644 index 000000000000..4f02efb8cee4 --- /dev/null +++ b/include/tvm/runtime/metadata.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +/*! + * \file tvm/runtime/metadata.h + * \brief Defines types which can be used in Metadata. + */ +#ifndef TVM_RUNTIME_METADATA_H_ +#define TVM_RUNTIME_METADATA_H_ + +#include +#ifdef __cplusplus +#include +#include +#include +#endif +#include +#ifdef __cplusplus +#include +#include +#endif + +// Version number recorded in emitted artifacts for runtime checking. +#define TVM_METADATA_VERSION 1 + +#ifdef __cplusplus +namespace tvm { +namespace runtime { +namespace metadata { +/*! + * \brief Version of metadata emitted and understood by this compiler/runtime. + * Should be populated into the `version` field of all TVMMetadata. + */ +static const constexpr int64_t kMetadataVersion = TVM_METADATA_VERSION; +} // namespace metadata +} // namespace runtime +} // namespace tvm + +extern "C" { +#endif + +/*! + * \brief Top-level metadata structure. Holds all other metadata types. + */ +struct TVMMetadata { + /*! \brief Version identifier for this metadata. */ + int64_t version; + /*! \brief Inputs to the AOT run_model function. + * The order of the elements is the same as in the arguments to run_model. That is to say, + * this array specifies the first `num_inputs` arguments to run_model. + */ + const struct TVMTensorInfo* inputs; + /*! \brief Number of elements in `inputs` array. */ + int64_t num_inputs; + /*! \brief Outputs of the AOT run_model function. + * The order of the elements is the same as in the arguments to run_model. That is to say, + * this array specifies the last `num_outputs` arguments to run_model. + */ + const struct TVMTensorInfo* outputs; + /*! \brief Number of elements in `outputs` array. */ + int64_t num_outputs; + /*! \brief Memory Pools needed by the AOT run_model function. + * The order of the elements is the same as in the arguments to run_model. That is to say, + * this array specifies the last `num_pools` arguments to run_model. + */ + const struct TVMTensorInfo* pools; + /*! \brief Number of elements in `pools` array. */ + int64_t num_pools; + /*! \brief Name of the model, as passed to tvm.relay.build. */ + const char* mod_name; +}; + +/*! + * \brief Describes one tensor argument to `run_model`. + * NOTE: while TIR allows for other types of arguments, such as scalars, the AOT run_model + * function does not currently accept these. Therefore it's not possible to express those + * in this metadata. A future patch may modify this. + */ +struct TVMTensorInfo { + /*! \brief Name of the tensor, as specified in the Relay program. */ + const char* name; + /*! \brief Shape of the tensor. */ + const int64_t* shape; + /*! \brief Rank of this tensor. */ + int64_t num_shape; + /*! \brief Data type of one element of this tensor. */ + DLDataType dtype; +}; +#ifdef __cplusplus +} // extern "C" +#include +namespace tvm { +namespace runtime { +namespace metadata { + +class Metadata; +class TensorInfo; + +class MetadataNode : public MetadataBaseNode { + public: + explicit MetadataNode(const struct ::TVMMetadata* data) : data_{data} {} + static constexpr const char* _type_key = "metadata.MetadataNode"; + const char* get_c_struct_name() const override; + inline int64_t version() const { return int64_t(data_->version); } + inline int64_t num_inputs() const { return data_->num_inputs; } + ArrayAccessor inputs(); + inline int64_t num_outputs() const { return data_->num_outputs; } + ArrayAccessor outputs(); + inline int64_t num_pools() const { return data_->num_pools; } + ArrayAccessor pools(); + inline ::tvm::runtime::String mod_name() const { return ::tvm::runtime::String(data_->mod_name); } + const struct ::TVMMetadata* data() const { return data_; } + TVM_DECLARE_FINAL_OBJECT_INFO(MetadataNode, MetadataBaseNode); + + private: + const struct ::TVMMetadata* data_; +}; + +class Metadata : public MetadataBase { + public: + explicit Metadata(const struct ::TVMMetadata* data); + TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(Metadata, MetadataBase, MetadataNode); +}; + +class TensorInfoNode : public MetadataBaseNode { + public: + explicit TensorInfoNode(const struct ::TVMTensorInfo* data) : data_{data} {} + static constexpr const char* _type_key = "metadata.TensorInfoNode"; + const char* get_c_struct_name() const override; + inline ::tvm::runtime::String name() const { return ::tvm::runtime::String(data_->name); } + inline int64_t num_shape() const { return data_->num_shape; } + inline ::tvm::support::Span shape() const { + return ::tvm::support::Span(data_->shape, + data_->shape + data_->num_shape); + } + inline ::tvm::runtime::DataType dtype() const { return ::tvm::runtime::DataType(data_->dtype); } + const struct ::TVMTensorInfo* data() const { return data_; } + TVM_DECLARE_FINAL_OBJECT_INFO(TensorInfoNode, MetadataBaseNode); + + private: + const struct ::TVMTensorInfo* data_; +}; + +class TensorInfo : public MetadataBase { + public: + explicit TensorInfo(const struct ::TVMTensorInfo* data); + TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(TensorInfo, MetadataBase, TensorInfoNode); +}; + +} // namespace metadata +} // namespace runtime +} // namespace tvm +#endif // defined(__cplusplus) + +#endif // TVM_RUNTIME_METADATA_H_ diff --git a/include/tvm/runtime/metadata_base.h b/include/tvm/runtime/metadata_base.h new file mode 100644 index 000000000000..442c42c303b1 --- /dev/null +++ b/include/tvm/runtime/metadata_base.h @@ -0,0 +1,216 @@ +/* + * 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. + */ + +/*! + * \file tvm/runtime/metadata_base.h + * \brief Defines types which can be used in Metadata. + */ +#ifndef TVM_RUNTIME_METADATA_BASE_H_ +#define TVM_RUNTIME_METADATA_BASE_H_ + +#include +#include + +#include +#include +#include +#include + +namespace tvm { +namespace runtime { +namespace metadata { + +/*! + * \brief Common base class for all Metadata. + * + * This class is used in the visitor classes as a internal check to ensure that verify that all + * parts of the Metadata struct used in codegen are Metadata objects. + */ +class MetadataBaseNode : public ::tvm::runtime::Object { + public: + virtual const char* get_c_struct_name() const = 0; + + static constexpr const char* _type_key = "metadata.MetadataBaseNode"; + TVM_DECLARE_BASE_OBJECT_INFO(MetadataBaseNode, ::tvm::runtime::Object); +}; + +/*! \brief Reference class for the common MetadataBaseNode class. */ +class MetadataBase : public ::tvm::runtime::ObjectRef { + public: + TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(MetadataBase, ::tvm::runtime::ObjectRef, MetadataBaseNode); +}; + +template +class ArrayAccessor; + +/*! \brief An iterator implementation that lazily instantiates the C++ wrapping Metadata class. */ +template +class ArrayIterator { + public: + ArrayIterator(size_t index, const ArrayAccessor* parent) + : index_{index}, parent_{parent} {} + + inline Ref operator*() { return (*parent_)[index_]; } + + inline ArrayIterator& operator++() { + if (index_ < parent_->size()) { + index_++; + } + + return *this; + } + + inline bool operator==(const ArrayIterator& other) const { + return parent_ == other.parent_ && index_ == other.index_; + } + + inline bool operator!=(const ArrayIterator& other) const { return !operator==(other); } + + private: + size_t index_; + const ArrayAccessor* parent_; +}; + +/*! \brief A span-like class which permits access to Array fields with complex elements. + * These array fields should be accessed from C++ using the Metadata wrapper classes. This class + * lazily instantiates those wrappers as they are accessed. + */ +template +class ArrayAccessor { + public: + using value_type = Ref; + using iterator = ArrayIterator; + using const_iterator = iterator; + + template ::value>::type> + ArrayAccessor(const C* data, size_t num_data) : data_{data}, num_data_{num_data} {} + + inline size_t size() const { return num_data_; } + + inline Ref operator[](size_t index) const { + if (index >= num_data_) { + throw std::runtime_error("Index out of range"); + } + + return Ref(&data_[index]); + } + + inline ArrayIterator begin() const { return ArrayIterator{0, this}; } + + inline ArrayIterator end() const { return ArrayIterator{num_data_, this}; } + + private: + const C* data_; + size_t num_data_; +}; + +/*! \brief A specialization of ArrayAccessor for String. + * This class is needed because the String constructor signature is different from the typical + * Metadata subclass. + */ +template <> +class ArrayAccessor { + public: + using value_type = ::tvm::runtime::String; + using iterator = ArrayIterator; + using const_iterator = iterator; + + ArrayAccessor(const char** data, size_t num_data) : data_{data}, num_data_{num_data} {} + + inline size_t size() const { return num_data_; } + + inline ::tvm::runtime::String operator[](size_t index) const { + if (index >= num_data_) { + throw std::runtime_error("Index out of range"); + } + return ::tvm::runtime::String(data_[index]); + } + + inline ArrayIterator begin() const { + return ArrayIterator{0, this}; + } + + inline ArrayIterator end() const { + return ArrayIterator{num_data_, this}; + } + + private: + const char** data_; + size_t num_data_; +}; + +/*! \brief Enumerates the primitive types which can be part of a Metadata instance. + * + * These are separate from TIR DataType because TIR does not model structs. + */ +enum MetadataKind : uint8_t { + kUint64 = 0, + kInt64 = 1, + kBool = 2, + kString = 3, + kHandle = 4, + kMetadata = 5, +}; + +/*! \brief Container for arrays in the metadata. + * + * Type information is needed when emitting arrays. This container augments the data field with + * the necessary typing information. + */ +class MetadataArrayNode : public MetadataBaseNode { + public: + MetadataArrayNode(Array array, MetadataKind kind, const char* type_key) + : array(::std::move(array)), kind{kind}, type_key{type_key} {} + + const char* get_c_struct_name() const final; + + std::string get_element_c_struct_name() const { + CHECK(kind == MetadataKind::kMetadata) + << "cannot get struct name for MetadataArray with kind=" << kind; + constexpr int prefix_size = sizeof("metadata.") - 1; + constexpr int suffix_size = sizeof("Node") - 1; + std::string type_key_str(type_key); + return std::string{"TVM"} + type_key_str.substr(prefix_size, type_key_str.size() - prefix_size - suffix_size); + } + + Array array; + + /*! \brief Describes the storage class of the emitted struct member. */ + MetadataKind kind; + + /*! \brief When `kind` is Metadata, type_key of the MetadataBaseNode used with this array. */ + const char* type_key; + + static constexpr const char* _type_key = "metadata.MetadataArrayNode"; + TVM_DECLARE_BASE_OBJECT_INFO(MetadataArrayNode, MetadataBaseNode); +}; + +/*! \brief Reference class for MetadataArray. */ +class MetadataArray : public MetadataBase { + public: + MetadataArray(Array array, MetadataKind kind, const char* struct_name); + + TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(MetadataArray, MetadataBase, MetadataArrayNode); +}; + +} // namespace metadata +} // namespace runtime +} // namespace tvm + +#endif // TVM_RUNTIME_METADATA_BASE_H_ diff --git a/include/tvm/runtime/module.h b/include/tvm/runtime/module.h index 7b5326a44921..2e2a79b1ca53 100644 --- a/include/tvm/runtime/module.h +++ b/include/tvm/runtime/module.h @@ -235,8 +235,6 @@ constexpr const char* tvm_module_main = "__tvm_main__"; constexpr const char* tvm_param_prefix = "__tvm_param__"; /*! \brief A PackedFunc that looks up linked parameters by storage_id. */ constexpr const char* tvm_lookup_linked_param = "_lookup_linked_param"; -/*! \brief The main AOT executor function generated from TIR */ -constexpr const char* tvm_run_func_suffix = "run_model"; /*! \brief Model entrypoint generated as an interface to the AOT function outside of TIR */ constexpr const char* tvm_entrypoint_suffix = "run"; } // namespace symbol diff --git a/include/tvm/runtime/packed_func.h b/include/tvm/runtime/packed_func.h index a3bb569045eb..232ccd11f3c3 100644 --- a/include/tvm/runtime/packed_func.h +++ b/include/tvm/runtime/packed_func.h @@ -56,6 +56,10 @@ class TVMArgValue; class TVMMovableArgValueWithContext_; class TVMRetValue; class TVMArgsSetter; +template +class TypedPackedFunc; +template +struct SignaturePrinter; /*! * \brief Object container class that backs PackedFunc. @@ -178,6 +182,9 @@ class PackedFunc : public ObjectRef { TVM_DEFINE_OBJECT_REF_METHODS(PackedFunc, ObjectRef, PackedFuncObj); }; +/*! \brief Using static function to output TypedPackedFunc signature */ +using FSig = std::string(); + /*! * \brief Please refer to \ref TypedPackedFuncAnchor "TypedPackedFunc" */ @@ -751,12 +758,16 @@ class TVMMovableArgValueWithContext_ { * \param value The other return value. * \param type_code The code associated with the type of the value. * \param arg_index In a function call, this argument is at index arg_index (0-indexed). - * \param optional_name Name of the function being called. Can be nullptr if the function is not + * \param optional_name Name of the function being called. Can be nullptr if the function is not. + * \param f_sig Pointer to static function outputting signature of the function being called. * named. */ TVMMovableArgValueWithContext_(TVMValue value, int type_code, int arg_index, - const std::string* optional_name) - : value_(value, type_code), arg_index_(arg_index), optional_name_(optional_name) {} + const std::string* optional_name, FSig* f_sig) + : value_(value, type_code), + arg_index_(arg_index), + optional_name_(optional_name), + f_sig_(f_sig) {} template operator T() const { @@ -764,7 +775,8 @@ class TVMMovableArgValueWithContext_ { return value_; // implicit conversion happens here } catch (dmlc::Error& e) { LOG(FATAL) << "In function " << (optional_name_ == nullptr ? "" : *optional_name_) - << ": error while converting argument " << arg_index_ << ": " << e.what(); + << (f_sig_ == nullptr ? "" : (*f_sig_)()) << ": error while converting argument " + << arg_index_ << ": " << e.what(); throw; // never reached, LOG(FATAL) throws, but this silences a warning. } } @@ -773,6 +785,7 @@ class TVMMovableArgValueWithContext_ { TVMMovableArgValue_ value_; int arg_index_; const std::string* optional_name_; + FSig* f_sig_; }; /*! @@ -1268,6 +1281,61 @@ inline void for_each(const F& f, Args&&... args) { // NOLINT(*) for_each_dispatcher::run(f, std::forward(args)...); } +namespace parameter_pack { + +template +struct EnumeratedParamPack { + struct Invoke { + template