diff --git a/.github/workflows/cc_bot.yml b/.github/workflows/cc_bot.yml index 873fafa82..ac0baa490 100644 --- a/.github/workflows/cc_bot.yml +++ b/.github/workflows/cc_bot.yml @@ -32,6 +32,7 @@ concurrency: jobs: cc-reviewers: + if: github.repository == 'apache/tvm' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/ping_reviewers.yml b/.github/workflows/ping_reviewers.yml index 683ffbaa9..96c20434d 100644 --- a/.github/workflows/ping_reviewers.yml +++ b/.github/workflows/ping_reviewers.yml @@ -11,6 +11,7 @@ concurrency: jobs: ping: + if: github.repository == 'apache/tvm' runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/tag_teams.yml b/.github/workflows/tag_teams.yml new file mode 100644 index 000000000..2518cf87d --- /dev/null +++ b/.github/workflows/tag_teams.yml @@ -0,0 +1,48 @@ +# 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: Teams + +on: + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target + pull_request_target: + types: [opened, reopened, edited, ready_for_review, labeled] + issues: + types: [opened, edited, reopened, labeled] + +concurrency: + group: Teams-${{ github.event.pull_request.number }}-${{ github.event.issue.number }} + cancel-in-progress: true + +jobs: + tag-teams: + if: github.repository == 'apache/tvm' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Tag people from relevant teams + env: + PR: ${{ toJson(github.event.pull_request) }} + ISSUE: ${{ toJson(github.event.issue) }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eux + python tests/scripts/github_tag_teams.py || echo failed diff --git a/.github/workflows/update_last_successful_branch.yml b/.github/workflows/update_last_successful_branch.yml index 1e8def404..fc2f2d0d4 100644 --- a/.github/workflows/update_last_successful_branch.yml +++ b/.github/workflows/update_last_successful_branch.yml @@ -32,6 +32,7 @@ concurrency: jobs: update-last-successful-branch: + if: github.repository == 'apache/tvm' runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index f87a3a9f6..9c6a7dddf 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 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5e37f09ed..0b3e60572 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -55,7 +55,8 @@ We do encourage everyone to work anything they are interested in. - [Thierry Moreau](https://github.com/tmoreau89) (PMC): @tmoreau89 - vta - [Kazutaka Morita](https://github.com/kazum): @kazum - frontends, opencl - [Trevor Morris](https://github.com/trevor-m): @trevor-m - byoc, compiler -- [Leandro Nunes](https://github.com/leandron): @leandron - tvmc +- [Leandro Nunes](https://github.com/leandron) (PMC): @leandron - tvmc +- [Lily Orth-Smith](https://github.com/electriclilies): @electriclilies - relay - [Krzysztof Parzyszek](https://github.com/kparzysz-quic): @kparzysz-quic - hexagon, llvm - [Andrew Reusch](https://github.com/areusch): (PMC) @areusch - runtime, microTVM - [Jared Roesch](https://github.com/jroesch) (PMC): @jroesch - relay @@ -64,6 +65,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 @@ -106,7 +108,7 @@ We do encourage everyone to work anything they are interested in. - [Manupa Karunaratne](https://github.com/manupa-arm): @manupa-arm - [Marisa Kirisame](https://github.com/MarisaKirisame): @MarisaKirisame - [Tristan Konolige](https://github.com/tkonolige): @tkonolige -- [Ruihang Lai](https://github.com/MasterJH5574): @MasterJH5574 +- [Ruihang Lai](https://github.com/MasterJH5574): @MasterJH5574 - [Wuwei Lin](https://github.com/vinx13): @vinx13 - [Andrew Liu](https://github.com/hypercubestart): @hypercubestart - [Henry Liu](https://github.com/optima2005): @optima2005 diff --git a/Jenkinsfile b/Jenkinsfile index 05df4dabd..0304d4e18 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -45,13 +45,14 @@ 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.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_lint = 'tlcpack/ci-lint:v0.68' +ci_gpu = 'tlcpack/ci-gpu:v0.81' +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 @@ -104,6 +105,21 @@ def init_git() { } } +def should_skip_slow_tests(pr_number) { + withCredentials([string( + credentialsId: 'tvm-bot-jenkins-reader', + variable: 'GITHUB_TOKEN', + )]) { + // Exit code of 1 means run slow tests, exit code of 0 means skip slow tests + result = sh ( + returnStatus: true, + script: "./tests/scripts/should_run_slow_tests.py --pr '${pr_number}'", + label: 'Check if CI should run slow tests', + ) + } + return result == 0 +} + def cancel_previous_build() { // cancel previous build if it is not on main. if (env.BRANCH_NAME != 'main') { @@ -131,6 +147,14 @@ def should_skip_ci(pr_number) { return git_skip_ci_code == 0 } +// skips builds from branch indexing; sourced from https://www.jvt.me/posts/2020/02/23/jenkins-multibranch-skip-branch-index/ +// execute this before anything else, including requesting any time on an agent +if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) { + print "INFO: Build skipped due to trigger being Branch Indexing" + currentBuild.result = 'ABORTED' // optional, gives a better hint to the user that it's been skipped, rather than the default which shows it's successful + return +} + cancel_previous_build() stage('Prepare') { @@ -168,6 +192,7 @@ stage('Sanity Check') { label: 'Check for docs only changes', ) skip_ci = should_skip_ci(env.CHANGE_ID) + skip_slow_tests = should_skip_slow_tests(env.CHANGE_ID) sh ( script: "${docker_run} ${ci_lint} ./tests/scripts/task_lint.sh", label: 'Run lint', @@ -177,6 +202,7 @@ stage('Sanity Check') { } } + // Run make. First try to do an incremental make from a previous workspace in hope to // accelerate the compilation. If something is wrong, clean the workspace and then // build from scratch. @@ -237,13 +263,13 @@ def python_unittest(image) { def fsim_test(image) { sh ( script: "${docker_run} ${image} ./tests/scripts/task_python_vta_fsim.sh", - label: 'Run VTA tests in FSIM ', + label: 'Run VTA tests in FSIM', ) } def cmake_build(image, path, make_flag) { sh ( - script: "${docker_run} ${image} ./tests/scripts/task_build.sh ${path} ${make_flag}", + script: "${docker_run} ${image} ./tests/scripts/task_build.py --num-executors ${CI_NUM_EXECUTORS} --sccache-bucket tvm-sccache-prod", label: 'Run cmake build', ) } @@ -256,6 +282,9 @@ def cpp_unittest(image) { } stage('Build') { + environment { + SKIP_SLOW_TESTS = "${skip_slow_tests}" + } parallel 'BUILD: GPU': { if (!skip_ci) { node('GPUBUILD') { @@ -286,7 +315,7 @@ stage('Build') { ci_setup(ci_cpu) // sh "${docker_run} ${ci_cpu} ./tests/scripts/task_golang.sh" // TODO(@jroesch): need to resolve CI issue will turn back on in follow up patch - sh (script: "${docker_run} ${ci_cpu} ./tests/scripts/task_rust.sh", label: "Rust build and test") + sh (script: "${docker_run} ${ci_cpu} ./tests/scripts/task_rust.sh", label: 'Rust build and test') } } } @@ -381,10 +410,41 @@ stage('Build') { } 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_hexagon} ./tests/scripts/task_build_hexagon_api.sh", + label: 'Build Hexagon API', + ) + sh ( + 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: Hexagon') + } } } stage('Test') { + environment { + SKIP_SLOW_TESTS = "${skip_slow_tests}" + } parallel 'unittest: GPU': { if (!skip_ci && is_docs_only_build != 1) { node('TensorCore') { @@ -442,7 +502,7 @@ stage('Test') { 'unittest: CPU': { if (!skip_ci && is_docs_only_build != 1) { node('CPU') { - ws(per_exec_ws("tvm/ut-python-cpu")) { + ws(per_exec_ws('tvm/ut-python-cpu')) { try { init_git() unpack_lib('cpu', tvm_multilib_tsim) @@ -452,7 +512,7 @@ stage('Test') { fsim_test(ci_cpu) sh ( script: "${docker_run} ${ci_cpu} ./tests/scripts/task_python_vta_tsim.sh", - label: "Run VTA tests in TSIM", + label: 'Run VTA tests in TSIM', ) } } finally { @@ -537,7 +597,7 @@ stage('Test') { Utils.markStageSkippedForConditional('topi: GPU') } }, - 'frontend: GPU': { + 'frontend: GPU 1': { if (!skip_ci && is_docs_only_build != 1) { node('GPU') { ws(per_exec_ws('tvm/frontend-python-gpu')) { @@ -547,8 +607,31 @@ stage('Test') { 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', + script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_frontend.sh 1", + label: 'Run Python frontend tests (shard 1)', + ) + } + } finally { + junit 'build/pytest-results/*.xml' + } + } + } + } else { + Utils.markStageSkippedForConditional('frontend: GPU 1') + } + }, + 'frontend: GPU 2': { + if (!skip_ci && is_docs_only_build != 1) { + node('GPU') { + ws(per_exec_ws('tvm/frontend-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_frontend.sh 2", + label: 'Run Python frontend tests (shard 2)', ) } } finally { @@ -557,7 +640,7 @@ stage('Test') { } } } else { - Utils.markStageSkippedForConditional('frontend: GPU') + Utils.markStageSkippedForConditional('frontend: GPU 2') } }, 'frontend: CPU': { diff --git a/apps/hexagon_api/CMakeLists.txt b/apps/hexagon_api/CMakeLists.txt index 557dcfb85..052fd0002 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 553665191..25d609dac 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/reference-vm/base-box-tool.py b/apps/microtvm/reference-vm/base-box-tool.py index fa649afa5..79d1d5900 100755 --- a/apps/microtvm/reference-vm/base-box-tool.py +++ b/apps/microtvm/reference-vm/base-box-tool.py @@ -97,10 +97,27 @@ def parse_virtualbox_devices(): return devices +VIRTUALBOX_USB_DEVICE_RE = ( + "USBAttachVendorId[0-9]+=0x([0-9a-z]{4})\n" + "USBAttachProductId[0-9]+=0x([0-9a-z]{4})" +) + + +def parse_virtualbox_attached_usb_devices(vm_uuid): + output = subprocess.check_output( + ["VBoxManage", "showvminfo", "--machinereadable", vm_uuid], encoding="utf-8" + ) + + r = re.compile(VIRTUALBOX_USB_DEVICE_RE) + attached_usb_devices = r.findall(output, re.MULTILINE) + + # List of couples (VendorId, ProductId) for all attached USB devices + return attached_usb_devices + + VIRTUALBOX_VID_PID_RE = re.compile(r"0x([0-9A-Fa-f]{4}).*") -def attach_virtualbox(uuid, vid_hex=None, pid_hex=None, serial=None): +def attach_virtualbox(vm_uuid, vid_hex=None, pid_hex=None, serial=None): usb_devices = parse_virtualbox_devices() for dev in usb_devices: m = VIRTUALBOX_VID_PID_RE.match(dev["VendorId"]) @@ -122,6 +139,12 @@ def attach_virtualbox(uuid, vid_hex=None, pid_hex=None, serial=None): and pid_hex == dev_pid_hex and (serial is None or serial == dev["SerialNumber"]) ): + attached_devices = parse_virtualbox_attached_usb_devices(vm_uuid) + for vid, pid in parse_virtualbox_attached_usb_devices(vm_uuid): + if vid_hex == vid and pid_hex == pid: + print(f"USB dev {vid_hex}:{pid_hex} already attached. Skipping attach.") + return + rule_args = [ "VBoxManage", "usbfilter", @@ -132,7 +155,7 @@ def attach_virtualbox(uuid, vid_hex=None, pid_hex=None, serial=None): "--name", "test device", "--target", - uuid, + vm_uuid, "--vendorid", vid_hex, "--productid", @@ -141,8 +164,7 @@ def attach_virtualbox(uuid, vid_hex=None, pid_hex=None, serial=None): if serial is not None: rule_args.extend(["--serialnumber", serial]) subprocess.check_call(rule_args) - # TODO(mehrdadh): skip usb attach if it's already attached - subprocess.check_call(["VBoxManage", "controlvm", uuid, "usbattach", dev["UUID"]]) + subprocess.check_call(["VBoxManage", "controlvm", vm_uuid, "usbattach", dev["UUID"]]) return raise Exception( diff --git a/apps/microtvm/zephyr/template_project/boards.json b/apps/microtvm/zephyr/template_project/boards.json index 543a34216..a2210c5c9 100644 --- a/apps/microtvm/zephyr/template_project/boards.json +++ b/apps/microtvm/zephyr/template_project/boards.json @@ -1,11 +1,19 @@ { + "b_u585i_iot02a": { + "board": "b_u585i_iot02a", + "model": "stm32u5xx", + "is_qemu": false, + "fpu": true, + "vid_hex": "0483", + "pid_hex": "374e" + }, "mimxrt1050_evk": { "board": "mimxrt1050_evk", "model": "imxrt10xx", "is_qemu": false, "fpu": true, - "vid_hex": "", - "pid_hex": "" + "vid_hex": "1366", + "pid_hex": "0105" }, "mps2_an521": { "board": "mps2_an521", diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index a7774899a..aaf848a7e 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 @@ -165,40 +166,47 @@ def _get_device_args(options): ) -# kwargs passed to usb.core.find to find attached boards for the openocd flash runner. -BOARD_USB_FIND_KW = { - "nucleo_l4r5zi": {"idVendor": 0x0483, "idProduct": 0x374B}, - "nucleo_f746zg": {"idVendor": 0x0483, "idProduct": 0x374B}, - "stm32f746g_disco": {"idVendor": 0x0483, "idProduct": 0x374B}, - "mimxrt1050_evk": {"idVendor": 0x1366, "idProduct": 0x0105}, -} +def generic_find_serial_port(serial_number=None): + """Find a USB serial port based on its serial number or its VID:PID. + This method finds a USB serial port device path based on the port's serial number (if given) or + based on the board's idVendor and idProduct ids. -def openocd_serial(options): - """Find the serial port to use for a board with OpenOCD flash strategy.""" - if "openocd_serial" in options: - return options["openocd_serial"] + Parameters + ---------- + serial_number : str + The serial number associated to the USB serial port which the board is attached to. This is + the same number as shown by 'lsusb -v' in the iSerial field. - import usb # pylint: disable=import-outside-toplevel + Returns + ------- + Path to the USB serial port device, for example /dev/ttyACM1. + """ + if serial_number: + regex = serial_number + else: + prop = BOARD_PROPERTIES[CMAKE_CACHE["BOARD"]] + device_id = ":".join([prop["vid_hex"], prop["pid_hex"]]) + regex = device_id - find_kw = BOARD_USB_FIND_KW[CMAKE_CACHE["BOARD"]] - boards = usb.core.find(find_all=True, **find_kw) - serials = [] - for b in boards: - serials.append(b.serial_number) + serial_ports = list(serial.tools.list_ports.grep(regex)) - if len(serials) == 0: - raise BoardAutodetectFailed(f"No attached USB devices matching: {find_kw!r}") - serials.sort() + if len(serial_ports) == 0: + raise Exception(f"No serial port found for board {prop['board']}!") - autodetected_openocd_serial = serials[0] - _LOG.debug("zephyr openocd driver: autodetected serial %s", serials[0]) + if len(serial_ports) != 1: + ports_lst = "" + for port in serial_ports: + ports_lst += f"Serial port: {port.device}, serial number: {port.serial_number}\n" - return autodetected_openocd_serial + raise Exception("Expected 1 serial port, found multiple ports:\n {ports_lst}") + + return serial_ports[0].device def _get_openocd_device_args(options): - return ["--serial", openocd_serial(options)] + serial_number = options.get("openocd_serial") + return ["--serial", generic_find_serial_port(serial_number)] def _get_nrf_device_args(options): @@ -588,6 +596,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,23 +640,30 @@ 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): - serial_number = openocd_serial(options) - ports = [p for p in serial.tools.list_ports.grep(serial_number)] - if len(ports) != 1: - raise Exception( - f"_find_openocd_serial_port: expected 1 port to match {serial_number}, " - f"found: {ports!r}" - ) - - return ports[0].device + serial_number = options.get("openocd_serial") + return generic_find_serial_port(serial_number) @classmethod def _find_jlink_serial_port(cls, options): - return cls._find_openocd_serial_port(options) + return generic_find_serial_port() + + @classmethod + def _find_stm32cubeprogrammer_serial_port(cls, options): + return generic_find_serial_port() @classmethod def _find_serial_port(cls, options): @@ -656,6 +678,9 @@ def _find_serial_port(cls, options): if flash_runner == "jlink": return cls._find_jlink_serial_port(options) + if flash_runner == "stm32cubeprogrammer": + return cls._find_stm32cubeprogrammer_serial_port(options) + raise RuntimeError(f"Don't know how to deduce serial port for flash runner {flash_runner}") def __init__(self, options): diff --git a/apps/microtvm/zephyr_cmsisnn/CMakeLists.txt b/apps/microtvm/zephyr_cmsisnn/CMakeLists.txt index 7f0db59ca..b09e1d064 100644 --- a/apps/microtvm/zephyr_cmsisnn/CMakeLists.txt +++ b/apps/microtvm/zephyr_cmsisnn/CMakeLists.txt @@ -57,11 +57,11 @@ set(CMSIS_SOURCES ${CMSIS_PATH}/CMSIS/NN/Source/ConvolutionFunctions/arm_convolve_1_x_n_s8.c ${CMSIS_PATH}/CMSIS/NN/Source/ConvolutionFunctions/arm_convolve_1x1_s8_fast.c ${CMSIS_PATH}/CMSIS/NN/Source/ConvolutionFunctions/arm_convolve_s8.c - ${CMSIS_PATH}/CMSIS/NN/Source/ConvolutionFunctions/arm_nn_mat_mult_kernel_s8_s16.c + ${CMSIS_PATH}/CMSIS/NN/Source/ConvolutionFunctions/arm_nn_mat_mult_s8.c ${CMSIS_PATH}/CMSIS/NN/Source/FullyConnectedFunctions/arm_fully_connected_s8.c - ${CMSIS_PATH}/CMSIS/NN/Source/NNSupportFunctions/arm_nn_mat_mult_nt_t_s8.c + ${CMSIS_PATH}/CMSIS/NN/Source/NNSupportFunctions/arm_nn_mat_mul_core_4x_s8.c ${CMSIS_PATH}/CMSIS/NN/Source/NNSupportFunctions/arm_nn_vec_mat_mult_t_s8.c - ${CMSIS_PATH}/CMSIS/NN/Source/NNSupportFunctions/arm_q7_to_q15_with_offset.c + ${CMSIS_PATH}/CMSIS/NN/Source/NNSupportFunctions/arm_nn_mat_mul_core_1x_s8.c ) add_custom_command( diff --git a/apps/microtvm/zephyr_cmsisnn/prj.conf b/apps/microtvm/zephyr_cmsisnn/prj.conf index 59ca3154a..2bb203571 100644 --- a/apps/microtvm/zephyr_cmsisnn/prj.conf +++ b/apps/microtvm/zephyr_cmsisnn/prj.conf @@ -18,5 +18,5 @@ # newlib needed for math.h CONFIG_NEWLIB_LIBC=y -# emulate finite stack size -CONFIG_MAIN_STACK_SIZE=256 +# Enables architecture extensions +CONFIG_FPU=y diff --git a/apps/microtvm/zephyr_cmsisnn/src/main.c b/apps/microtvm/zephyr_cmsisnn/src/main.c index 274bd63d3..466c25e71 100644 --- a/apps/microtvm/zephyr_cmsisnn/src/main.c +++ b/apps/microtvm/zephyr_cmsisnn/src/main.c @@ -34,7 +34,8 @@ extern float output_storage[12]; extern const size_t output_len; -static uint8_t g_crt_workspace[TVMGEN_DEFAULT_WORKSPACE_SIZE + 512]; +static uint8_t __attribute__((aligned(TVM_RUNTIME_ALLOC_ALIGNMENT_BYTES))) +g_crt_workspace[TVMGEN_DEFAULT_WORKSPACE_SIZE]; tvm_workspace_t app_workspace; void TVMLogf(const char* msg, ...) { diff --git a/cmake/modules/Hexagon.cmake b/cmake/modules/Hexagon.cmake index d1e62358a..a8844a22e 100644 --- a/cmake/modules/Hexagon.cmake +++ b/cmake/modules/Hexagon.cmake @@ -78,10 +78,13 @@ endif() # # 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). +# 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) @@ -116,6 +119,15 @@ function(add_android_paths) link_directories(${HEXAGON_REMOTE_ROOT}) endfunction() +function(add_hexagon_wrapper_paths) + if(NOT DEFINED HEXAGON_TOOLCHAIN) + message(FATAL_ERROR "This function must be called after find_hexagon_toolchain") + endif() + include_directories(SYSTEM + "${HEXAGON_TOOLCHAIN}/include/iss" + ) + link_directories("${HEXAGON_TOOLCHAIN}/lib/iss") +endfunction() # Common sources for TVM runtime with Hexagon support file_glob_append(RUNTIME_HEXAGON_COMMON_SRCS @@ -148,12 +160,11 @@ if(USE_HEXAGON_DEVICE) 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" ) - include_directories(SYSTEM "${HEXAGON_TOOLCHAIN}/include/iss") - link_directories("${HEXAGON_TOOLCHAIN}/lib/iss") list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper") ExternalProject_Add(sim_dev @@ -245,6 +256,23 @@ if(USE_HEXAGON_RPC) target_include_directories(hexagon_rpc_skel SYSTEM PRIVATE "${TVMRT_SOURCE_DIR}/hexagon/rpc" ) + # 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 + ) + + 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() # USE_HEXAGON_RPC diff --git a/cmake/modules/contrib/EthosN.cmake b/cmake/modules/contrib/EthosN.cmake index 244f461b2..dbf554918 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 3b01374e1..07eaf5dde 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/dev_common.sh b/docker/dev_common.sh index 11ba34eb0..a4fc59556 100644 --- a/docker/dev_common.sh +++ b/docker/dev_common.sh @@ -45,7 +45,7 @@ function filter_jenkinsfile() { function lookup_image_spec() { img_line=$(cat "${GIT_TOPLEVEL}/Jenkinsfile" | filter_jenkinsfile | grep -E "^${1} = ") if [ -n "${img_line}" ]; then - img_spec=$(echo "${img_line}" | sed -E "s/${1} = \"([^\"]*)\"/\1/") + img_spec=$(echo "${img_line}" | sed -E "s/${1} = '([^\"]*)'/\1/") has_similar_docker_image=1 docker inspect "${1}" &>/dev/null || has_similar_docker_image=0 if [ ${has_similar_docker_image} -ne 0 ]; then diff --git a/docker/install/ubuntu1804_install_python.sh b/docker/install/ubuntu1804_install_python.sh index 4676ffb8b..94d316199 100755 --- a/docker/install/ubuntu1804_install_python.sh +++ b/docker/install/ubuntu1804_install_python.sh @@ -40,7 +40,7 @@ update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1 # $ 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 +pip==19.3.1 --hash=sha256:6917c65fc3769ecdc61405d3dfd97afdedd75808d200b2838d7d961cebc0c2c7 +setuptools==58.4.0 --hash=sha256:e8b1d3127a0441fb99a130bcc3c2bf256c2d3ead3aba8fd400e5cbbaf788e036 EOF pip3 install -r base-requirements.txt diff --git a/docker/install/ubuntu_install_boost.sh b/docker/install/ubuntu_install_boost.sh index 7af9bf46f..e226bbc5d 100644 --- a/docker/install/ubuntu_install_boost.sh +++ b/docker/install/ubuntu_install_boost.sh @@ -24,8 +24,8 @@ cleanup() { trap cleanup 0 -curl -O https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.gz -BOOST_HASH=cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e +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 diff --git a/docs/contribute/document.rst b/docs/contribute/document.rst index 8658c0fea..ffd63490d 100644 --- a/docs/contribute/document.rst +++ b/docs/contribute/document.rst @@ -233,3 +233,21 @@ Please use sphinx's ``:ref:`` markup to refer to another location in the same do ---------- You can use :ref:`document-my-section-tag` to refer to My Section. + +Documents with Images / Figures +------------------------------- +reStructuredText's `figure `_ +and `image `_ +elements allow a document to include an image URL. + +Image files created for TVM documentation should reside in the ``_ +repository, while the `.rst` files *using* those images should reside in the main TVM repostitory +(``_). + +This will require two Github Pull Requests, one for the image files and another for the `.rst` files. +Discussion between the contributor and reviewers may be necessary to coordinate the review process. + +*IMPORTANT NOTE:* When using two Pull Requests as described above, please merge the +Pull Request in ``_ *before* merging +the Pull Request in ``_. +This helps ensure that all URL links in TVM's online documentation are valid. diff --git a/docs/reference/api/python/contrib.rst b/docs/reference/api/python/contrib.rst index 52d3faff0..26b5abb97 100644 --- a/docs/reference/api/python/contrib.rst +++ b/docs/reference/api/python/contrib.rst @@ -97,10 +97,12 @@ tvm.contrib.relay_viz ~~~~~~~~~~~~~~~~~~~~~ .. automodule:: tvm.contrib.relay_viz :members: -.. automodule:: tvm.contrib.relay_viz.interface +.. automodule:: tvm.contrib.relay_viz.dot :members: .. automodule:: tvm.contrib.relay_viz.terminal :members: +.. automodule:: tvm.contrib.relay_viz.interface + :members: 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 index f61fc41f4..10e6dab12 100644 --- a/gallery/how_to/work_with_relay/using_relay_viz.py +++ b/gallery/how_to/work_with_relay/using_relay_viz.py @@ -32,6 +32,8 @@ 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. + +For more details, please refer to :py:mod:`tvm.contrib.relay_viz`. """ from typing import ( Dict, diff --git a/include/tvm/ir/function.h b/include/tvm/ir/function.h index 72dc8a5c9..1493544e7 100644 --- a/include/tvm/ir/function.h +++ b/include/tvm/ir/function.h @@ -190,16 +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"; - } // namespace attr } // namespace tvm #endif // TVM_IR_FUNCTION_H_ diff --git a/include/tvm/ir/module.h b/include/tvm/ir/module.h index d308db87a..e2b47ef32 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 cb556fc13..d8f6632a6 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/meta_schedule/builder.h b/include/tvm/meta_schedule/builder.h index d7b23dd79..2b8094591 100644 --- a/include/tvm/meta_schedule/builder.h +++ b/include/tvm/meta_schedule/builder.h @@ -32,7 +32,7 @@ class BuilderInputNode : public runtime::Object { IRModule mod; /*! \brief The target to be built for. */ Target target; - /*! \brief The optional parameters used for build */ + /*! \brief Parameters for Relay build module. */ Optional> params; void VisitAttrs(tvm::AttrVisitor* v) { @@ -55,7 +55,7 @@ class BuilderInput : public runtime::ObjectRef { * \brief Constructor of BuilderInput. * \param mod The IRModule to be built. * \param target The target to be built for. - * \param params The optional parameters used for build + * \param params Parameters for Relay build module. */ TVM_DLL explicit BuilderInput(IRModule mod, Target target, Optional> params = NullOpt); diff --git a/include/tvm/meta_schedule/runner.h b/include/tvm/meta_schedule/runner.h index b154195f4..61023c8e2 100644 --- a/include/tvm/meta_schedule/runner.h +++ b/include/tvm/meta_schedule/runner.h @@ -125,12 +125,18 @@ class RunnerFutureNode : public runtime::Object { * \brief Check whether the runner has finished. * \return A boolean indicating whether the runner has finished. */ - bool Done() const { return f_done(); } + bool Done() const { + ICHECK(f_done != nullptr) << "PyRunnerFuture's Done method not implemented!"; + return f_done(); + } /*! * \brief Fetch the runner's output if it is ready. * \return The runner's output. */ - RunnerResult Result() const { return f_result(); } + RunnerResult Result() const { + ICHECK(f_result != nullptr) << "PyRunnerFuture's Result method not implemented!"; + return f_result(); + } static constexpr const char* _type_key = "meta_schedule.RunnerFuture"; TVM_DECLARE_FINAL_OBJECT_INFO(RunnerFutureNode, runtime::Object); diff --git a/include/tvm/meta_schedule/space_generator.h b/include/tvm/meta_schedule/space_generator.h index 3611870c7..bad9ae0f6 100644 --- a/include/tvm/meta_schedule/space_generator.h +++ b/include/tvm/meta_schedule/space_generator.h @@ -114,7 +114,7 @@ class PySpaceGeneratorNode : public SpaceGeneratorNode { void InitializeWithTuneContext(const TuneContext& context) final { ICHECK(f_initialize_with_tune_context != nullptr) - << "PySpaceGenerator's InitializeWithTuneContext !"; + << "PySpaceGenerator's InitializeWithTuneContext method not implemented!"; f_initialize_with_tune_context(context); } diff --git a/include/tvm/meta_schedule/tune_context.h b/include/tvm/meta_schedule/tune_context.h index 428a2e80f..7a7599b0a 100644 --- a/include/tvm/meta_schedule/tune_context.h +++ b/include/tvm/meta_schedule/tune_context.h @@ -82,6 +82,8 @@ class TuneContextNode : public runtime::Object { v->Visit("rand_state", &rand_state); v->Visit("num_threads", &num_threads); v->Visit("is_stopped", &is_stopped); + v->Visit("builder_results", &builder_results); + v->Visit("runner_futures", &runner_futures); v->Visit("measure_candidates", &measure_candidates); } diff --git a/include/tvm/node/structural_hash.h b/include/tvm/node/structural_hash.h index 887a012cf..a30a2c59d 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/executor.h b/include/tvm/relay/executor.h index 6d1bd2de7..858ba5cfe 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 fab579d0e..d8f575dfd 100644 --- a/include/tvm/relay/expr_functor.h +++ b/include/tvm/relay/expr_functor.h @@ -232,6 +232,8 @@ class ExprMutator : public ::tvm::relay::ExprFunctor { */ class MixedModeVisitor : public ::tvm::relay::ExprVisitor { public: + using ::tvm::relay::ExprFunctor::VisitExpr_; + /*! \brief The constructor of MixedModeVisitor * \param visit_limit The number of times to allow visitation to a node. Usually 1, ocassionally * higher (i.e., 2 for dead code elimiation), limited to 10 as a sanity check. @@ -277,6 +279,8 @@ class MixedModeVisitor : public ::tvm::relay::ExprVisitor { */ class MixedModeMutator : public ::tvm::relay::ExprMutator { public: + using ::tvm::relay::ExprFunctor::VisitExpr_; + MixedModeMutator(bool pre = false) : pre_{pre} {}; Expr VisitExpr(const Expr& expr) final; diff --git a/include/tvm/relay/interpreter.h b/include/tvm/relay/interpreter.h index eed6d0ffc..f71107258 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 c4cabf5a5..10e124bc3 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 4bbc2df0a..ea3a5dba6 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/shape_tuple.h b/include/tvm/runtime/container/shape_tuple.h index 774077fc3..3a6f1843d 100644 --- a/include/tvm/runtime/container/shape_tuple.h +++ b/include/tvm/runtime/container/shape_tuple.h @@ -133,8 +133,8 @@ class ShapeTuple : public ObjectRef { * \return the i-th element. */ index_type operator[](size_t idx) const { - ICHECK(0 <= idx && idx < this->size()) - << "IndexError: indexing " << idx << " on an array of size " << this->size(); + ICHECK(idx < this->size()) << "IndexError: indexing " << idx << " on an array of size " + << this->size(); return this->data()[idx]; } diff --git a/include/tvm/runtime/data_type.h b/include/tvm/runtime/data_type.h index 3b7675473..e0c3106e1 100644 --- a/include/tvm/runtime/data_type.h +++ b/include/tvm/runtime/data_type.h @@ -57,7 +57,7 @@ class DataType { kCustomBegin = 129 }; /*! \brief default constructor */ - DataType() {} + DataType() { data_ = DataType::Void(); } /*! * \brief Constructor * \param dtype The DLDataType diff --git a/include/tvm/runtime/metadata.h b/include/tvm/runtime/metadata.h new file mode 100644 index 000000000..cd65f6fb7 --- /dev/null +++ b/include/tvm/runtime/metadata.h @@ -0,0 +1,169 @@ +/* + * 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 main 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"; + 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"; + 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 000000000..96743199f --- /dev/null +++ b/include/tvm/runtime/metadata_base.h @@ -0,0 +1,198 @@ +/* + * 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: + 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 MetadataTypeIndex : 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, MetadataTypeIndex type_index, const char* struct_name) + : array(::std::move(array)), type_index{type_index}, struct_name{struct_name} {} + + Array array; + MetadataTypeIndex type_index; + const char* struct_name; + 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, MetadataTypeIndex type_index, 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 7b5326a44..a93f1c66c 100644 --- a/include/tvm/runtime/module.h +++ b/include/tvm/runtime/module.h @@ -217,6 +217,8 @@ TVM_DLL bool RuntimeEnabled(const std::string& target); /*! \brief namespace for constant symbols */ namespace symbol { +/*! \brief A PackedFunc that retrieves exported metadata. */ +constexpr const char* tvm_get_c_metadata = "get_c_metadata"; /*! \brief Global variable to store module context. */ constexpr const char* tvm_module_ctx = "__tvm_module_ctx"; /*! \brief Global variable to store device module blob */ @@ -235,8 +237,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 a3bb56904..326f9661d 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