diff --git a/Jenkinsfile b/Jenkinsfile index bab7257e8f1a..15cd4927d0ba 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -45,7 +45,7 @@ // 'python3 jenkins/generate.py' // Note: This timestamp is here to ensure that updates to the Jenkinsfile are // always rebased on main before merging: -// Generated at 2022-08-12T14:39:18.041411 +// Generated at 2022-08-15T16:55:31.189354 import org.jenkinsci.plugins.pipeline.modeldefinition.Utils // NOTE: these lines are scanned by docker/dev_common.sh. Please update the regex as needed. --> @@ -67,13 +67,14 @@ ci_riscv = 'tlcpack/ci-riscv:20220810-060142-fae79bbc3' properties([ parameters([ string(name: 'ci_arm_param', defaultValue: ''), + string(name: 'ci_cortexm_param', defaultValue: ''), string(name: 'ci_cpu_param', defaultValue: ''), - string(name: 'ci_minimal_param', defaultValue: ''), string(name: 'ci_gpu_param', defaultValue: ''), string(name: 'ci_hexagon_param', defaultValue: ''), string(name: 'ci_i386_param', defaultValue: ''), string(name: 'ci_lint_param', defaultValue: ''), - string(name: 'ci_cortexm_param', defaultValue: ''), + string(name: 'ci_minimal_param', defaultValue: ''), + string(name: 'ci_riscv_param', defaultValue: ''), string(name: 'ci_wasm_param', defaultValue: ''), ]) ]) @@ -81,13 +82,14 @@ properties([ // Placeholders for newly built Docker image names (if rebuild_docker_images // is used) built_ci_arm = null; + built_ci_cortexm = null; built_ci_cpu = null; - built_ci_minimal = null; built_ci_gpu = null; built_ci_hexagon = null; built_ci_i386 = null; built_ci_lint = null; - built_ci_cortexm = null; + built_ci_minimal = null; + built_ci_riscv = null; built_ci_wasm = null; // Global variable assigned during Sanity Check that holds the sha1 which should be @@ -282,7 +284,7 @@ def prepare() { if (env.DETERMINE_DOCKER_IMAGES == 'yes') { sh( - script: "./tests/scripts/determine_docker_images.py ci_arm=${ci_arm} ci_cpu=${ci_cpu} ci_minimal=${ci_minimal} ci_gpu=${ci_gpu} ci_hexagon=${ci_hexagon} ci_i386=${ci_i386} ci_lint=${ci_lint} ci_cortexm=${ci_cortexm} ci_wasm=${ci_wasm} ", + script: "./tests/scripts/determine_docker_images.py ci_arm=${ci_arm} ci_cortexm=${ci_cortexm} ci_cpu=${ci_cpu} ci_gpu=${ci_gpu} ci_hexagon=${ci_hexagon} ci_i386=${ci_i386} ci_lint=${ci_lint} ci_minimal=${ci_minimal} ci_riscv=${ci_riscv} ci_wasm=${ci_wasm} ", label: 'Decide whether to use tlcpack or tlcpackstaging for Docker images', ) // Pull image names from the results of should_rebuild_docker.py @@ -291,16 +293,16 @@ def prepare() { label: "Find docker image name for ci_arm", returnStdout: true, ).trim() + ci_cortexm = sh( + script: "cat .docker-image-names/ci_cortexm", + label: "Find docker image name for ci_cortexm", + returnStdout: true, + ).trim() ci_cpu = sh( script: "cat .docker-image-names/ci_cpu", label: "Find docker image name for ci_cpu", returnStdout: true, ).trim() - ci_minimal = sh( - script: "cat .docker-image-names/ci_minimal", - label: "Find docker image name for ci_minimal", - returnStdout: true, - ).trim() ci_gpu = sh( script: "cat .docker-image-names/ci_gpu", label: "Find docker image name for ci_gpu", @@ -321,9 +323,14 @@ def prepare() { label: "Find docker image name for ci_lint", returnStdout: true, ).trim() - ci_cortexm = sh( - script: "cat .docker-image-names/ci_cortexm", - label: "Find docker image name for ci_cortexm", + ci_minimal = sh( + script: "cat .docker-image-names/ci_minimal", + label: "Find docker image name for ci_minimal", + returnStdout: true, + ).trim() + ci_riscv = sh( + script: "cat .docker-image-names/ci_riscv", + label: "Find docker image name for ci_riscv", returnStdout: true, ).trim() ci_wasm = sh( @@ -334,25 +341,27 @@ def prepare() { } ci_arm = params.ci_arm_param ?: ci_arm + ci_cortexm = params.ci_cortexm_param ?: ci_cortexm ci_cpu = params.ci_cpu_param ?: ci_cpu - ci_minimal = params.ci_minimal_param ?: ci_minimal ci_gpu = params.ci_gpu_param ?: ci_gpu ci_hexagon = params.ci_hexagon_param ?: ci_hexagon ci_i386 = params.ci_i386_param ?: ci_i386 ci_lint = params.ci_lint_param ?: ci_lint - ci_cortexm = params.ci_cortexm_param ?: ci_cortexm + ci_minimal = params.ci_minimal_param ?: ci_minimal + ci_riscv = params.ci_riscv_param ?: ci_riscv ci_wasm = params.ci_wasm_param ?: ci_wasm sh (script: """ echo "Docker images being used in this build:" echo " ci_arm = ${ci_arm}" + echo " ci_cortexm = ${ci_cortexm}" echo " ci_cpu = ${ci_cpu}" - echo " ci_minimal = ${ci_minimal}" echo " ci_gpu = ${ci_gpu}" echo " ci_hexagon = ${ci_hexagon}" echo " ci_i386 = ${ci_i386}" echo " ci_lint = ${ci_lint}" - echo " ci_cortexm = ${ci_cortexm}" + echo " ci_minimal = ${ci_minimal}" + echo " ci_riscv = ${ci_riscv}" echo " ci_wasm = ${ci_wasm}" """, label: 'Docker image names') @@ -488,25 +497,25 @@ def build_docker_images() { } } }, - 'ci_cpu': { + 'ci_cortexm': { node('CPU') { timeout(time: max_time, unit: 'MINUTES') { init_git() // We're purposefully not setting the built image here since they // are not yet being uploaded to tlcpack - // ci_cpu = build_image('ci_cpu') - built_ci_cpu = build_image('ci_cpu'); + // ci_cortexm = build_image('ci_cortexm') + built_ci_cortexm = build_image('ci_cortexm'); } } }, - 'ci_minimal': { + 'ci_cpu': { node('CPU') { timeout(time: max_time, unit: 'MINUTES') { init_git() // We're purposefully not setting the built image here since they // are not yet being uploaded to tlcpack - // ci_minimal = build_image('ci_minimal') - built_ci_minimal = build_image('ci_minimal'); + // ci_cpu = build_image('ci_cpu') + built_ci_cpu = build_image('ci_cpu'); } } }, @@ -554,14 +563,25 @@ def build_docker_images() { } } }, - 'ci_cortexm': { + 'ci_minimal': { node('CPU') { timeout(time: max_time, unit: 'MINUTES') { init_git() // We're purposefully not setting the built image here since they // are not yet being uploaded to tlcpack - // ci_cortexm = build_image('ci_cortexm') - built_ci_cortexm = build_image('ci_cortexm'); + // ci_minimal = build_image('ci_minimal') + built_ci_minimal = build_image('ci_minimal'); + } + } + }, + 'ci_riscv': { + node('CPU') { + timeout(time: max_time, unit: 'MINUTES') { + init_git() + // We're purposefully not setting the built image here since they + // are not yet being uploaded to tlcpack + // ci_riscv = build_image('ci_riscv') + built_ci_riscv = build_image('ci_riscv'); } } }, @@ -1135,6 +1155,57 @@ stage('Build') { Utils.markStageSkippedForConditional('BUILD: Hexagon') } }, + 'BUILD: RISC-V': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU-SMALL') { + ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/build-riscv") { + docker_init(ci_riscv) + init_git() + sh ( + script: "${docker_run} ${ci_riscv} ./tests/scripts/task_config_build_riscv.sh build", + label: 'Create RISC-V cmake config', + ) + make(ci_riscv, 'build', '-j2') + sh( + script: """ + set -eux + retry() { + local max_retries=\$1 + shift + local n=0 + local backoff_max=30 + until [ "\$n" -ge \$max_retries ] + do + "\$@" && break + n=\$((n+1)) + if [ "\$n" -eq \$max_retries ]; then + echo "failed to update after attempt \$n / \$max_retries, giving up" + exit 1 + fi + + WAIT=\$(python3 -c 'import random; print(random.randint(10, 30))') + echo "failed to update \$n / \$max_retries, waiting \$WAIT to try again" + sleep \$WAIT + done + } + + md5sum build/libtvm.so + retry 3 aws s3 cp --no-progress build/libtvm.so s3://${s3_prefix}/riscv/build/libtvm.so + md5sum build/libtvm_runtime.so + retry 3 aws s3 cp --no-progress build/libtvm_runtime.so s3://${s3_prefix}/riscv/build/libtvm_runtime.so + md5sum build/config.cmake + retry 3 aws s3 cp --no-progress build/config.cmake s3://${s3_prefix}/riscv/build/config.cmake + retry 3 aws s3 cp --no-progress build/microtvm_template_projects s3://${s3_prefix}/riscv/build/microtvm_template_projects --recursive + """, + label: 'Upload artifacts to S3', + ) + + } + } + } else { + Utils.markStageSkippedForConditional('BUILD: RISC-V') + } + }, ) } } @@ -4977,6 +5048,81 @@ def shard_run_test_Cortex_M_8_of_8() { } +def shard_run_test_RISC_V_1_of_1() { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU-SMALL') { + ws("workspace/exec_${env.EXECUTOR_NUMBER}/tvm/test-riscv") { + try { + docker_init(ci_riscv) + init_git() + timeout(time: max_time, unit: 'MINUTES') { + withEnv([ + 'PLATFORM=riscv', + 'TVM_NUM_SHARDS=1', + 'TVM_SHARD_INDEX=0', + "SKIP_SLOW_TESTS=${skip_slow_tests}"], { + sh( + script: """ + set -eux + retry() { + local max_retries=\$1 + shift + local n=0 + local backoff_max=30 + until [ "\$n" -ge \$max_retries ] + do + "\$@" && break + n=\$((n+1)) + if [ "\$n" -eq \$max_retries ]; then + echo "failed to update after attempt \$n / \$max_retries, giving up" + exit 1 + fi + + WAIT=\$(python3 -c 'import random; print(random.randint(10, 30))') + echo "failed to update \$n / \$max_retries, waiting \$WAIT to try again" + sleep \$WAIT + done + } + + retry 3 aws s3 cp --no-progress s3://${s3_prefix}/riscv/build/libtvm.so build/libtvm.so + md5sum build/libtvm.so + retry 3 aws s3 cp --no-progress s3://${s3_prefix}/riscv/build/libtvm_runtime.so build/libtvm_runtime.so + md5sum build/libtvm_runtime.so + retry 3 aws s3 cp --no-progress s3://${s3_prefix}/riscv/build/config.cmake build/config.cmake + md5sum build/config.cmake + retry 3 aws s3 cp --no-progress s3://${s3_prefix}/riscv/build/microtvm_template_projects build/microtvm_template_projects --recursive + """, + label: 'Download artifacts from S3', + ) + + add_microtvm_permissions() + ci_setup(ci_riscv) + cpp_unittest(ci_cortexm) + sh ( + script: "${docker_run} ${ci_riscv} ./tests/scripts/task_riscv_microtvm.sh", + label: 'Run microTVM tests', + ) + }) + } + } finally { + sh( + script: """ + set -eux + aws s3 cp --no-progress build/pytest-results s3://${s3_prefix}/pytest-results/test_RISC_V --recursive + """, + label: 'Upload JUnits to S3', + ) + + junit 'build/pytest-results/*.xml' + } + } + } + } else { + Utils.markStageSkippedForConditional('test: RISC-V 1 of 1') + } +} + + def run_unittest_minimal() { if (!skip_ci && is_docs_only_build != 1) { node('CPU-SMALL') { @@ -5200,6 +5346,9 @@ stage('Test') { 'test: Cortex-M 8 of 8': { shard_run_test_Cortex_M_8_of_8() }, + 'test: RISC-V 1 of 1': { + shard_run_test_RISC_V_1_of_1() + }, 'unittest: CPU MINIMAL': { run_unittest_minimal() }, @@ -5585,13 +5734,14 @@ def deploy() { ).trim() def tag = "${date_Ymd_HMS}-${upstream_revision.substring(0, 8)}" update_docker(built_ci_arm, "tlcpackstaging/ci_arm:${tag}") + update_docker(built_ci_cortexm, "tlcpackstaging/ci_cortexm:${tag}") update_docker(built_ci_cpu, "tlcpackstaging/ci_cpu:${tag}") - update_docker(built_ci_minimal, "tlcpackstaging/ci_minimal:${tag}") update_docker(built_ci_gpu, "tlcpackstaging/ci_gpu:${tag}") update_docker(built_ci_hexagon, "tlcpackstaging/ci_hexagon:${tag}") update_docker(built_ci_i386, "tlcpackstaging/ci_i386:${tag}") update_docker(built_ci_lint, "tlcpackstaging/ci_lint:${tag}") - update_docker(built_ci_cortexm, "tlcpackstaging/ci_cortexm:${tag}") + update_docker(built_ci_minimal, "tlcpackstaging/ci_minimal:${tag}") + update_docker(built_ci_riscv, "tlcpackstaging/ci_riscv:${tag}") update_docker(built_ci_wasm, "tlcpackstaging/ci_wasm:${tag}") } finally { sh( @@ -5633,30 +5783,30 @@ def deploy() { label: 'Tag tlcpackstaging/ci_arm image to tlcpack', ) } - if (ci_cpu.contains("tlcpackstaging")) { + if (ci_cortexm.contains("tlcpackstaging")) { // Push image to tlcpack - def tag = ci_cpu.split(":")[1] + def tag = ci_cortexm.split(":")[1] sh( script: """ set -eux - docker pull tlcpackstaging/ci_cpu:${tag} - docker tag tlcpackstaging/ci_cpu:${tag} tlcpack/ci-cpu:${tag} - docker push tlcpack/ci-cpu:${tag} + docker pull tlcpackstaging/ci_cortexm:${tag} + docker tag tlcpackstaging/ci_cortexm:${tag} tlcpack/ci-cortexm:${tag} + docker push tlcpack/ci-cortexm:${tag} """, - label: 'Tag tlcpackstaging/ci_cpu image to tlcpack', + label: 'Tag tlcpackstaging/ci_cortexm image to tlcpack', ) } - if (ci_minimal.contains("tlcpackstaging")) { + if (ci_cpu.contains("tlcpackstaging")) { // Push image to tlcpack - def tag = ci_minimal.split(":")[1] + def tag = ci_cpu.split(":")[1] sh( script: """ set -eux - docker pull tlcpackstaging/ci_minimal:${tag} - docker tag tlcpackstaging/ci_minimal:${tag} tlcpack/ci-minimal:${tag} - docker push tlcpack/ci-minimal:${tag} + docker pull tlcpackstaging/ci_cpu:${tag} + docker tag tlcpackstaging/ci_cpu:${tag} tlcpack/ci-cpu:${tag} + docker push tlcpack/ci-cpu:${tag} """, - label: 'Tag tlcpackstaging/ci_minimal image to tlcpack', + label: 'Tag tlcpackstaging/ci_cpu image to tlcpack', ) } if (ci_gpu.contains("tlcpackstaging")) { @@ -5711,17 +5861,30 @@ def deploy() { label: 'Tag tlcpackstaging/ci_lint image to tlcpack', ) } - if (ci_cortexm.contains("tlcpackstaging")) { + if (ci_minimal.contains("tlcpackstaging")) { // Push image to tlcpack - def tag = ci_cortexm.split(":")[1] + def tag = ci_minimal.split(":")[1] sh( script: """ set -eux - docker pull tlcpackstaging/ci_cortexm:${tag} - docker tag tlcpackstaging/ci_cortexm:${tag} tlcpack/ci-cortexm:${tag} - docker push tlcpack/ci-cortexm:${tag} + docker pull tlcpackstaging/ci_minimal:${tag} + docker tag tlcpackstaging/ci_minimal:${tag} tlcpack/ci-minimal:${tag} + docker push tlcpack/ci-minimal:${tag} """, - label: 'Tag tlcpackstaging/ci_cortexm image to tlcpack', + label: 'Tag tlcpackstaging/ci_minimal image to tlcpack', + ) + } + if (ci_riscv.contains("tlcpackstaging")) { + // Push image to tlcpack + def tag = ci_riscv.split(":")[1] + sh( + script: """ + set -eux + docker pull tlcpackstaging/ci_riscv:${tag} + docker tag tlcpackstaging/ci_riscv:${tag} tlcpack/ci-riscv:${tag} + docker push tlcpack/ci-riscv:${tag} + """, + label: 'Tag tlcpackstaging/ci_riscv image to tlcpack', ) } if (ci_wasm.contains("tlcpackstaging")) { diff --git a/ci/jenkins/Build.groovy.j2 b/ci/jenkins/Build.groovy.j2 index 21b8b2c65f8b..51360b7d9c54 100644 --- a/ci/jenkins/Build.groovy.j2 +++ b/ci/jenkins/Build.groovy.j2 @@ -241,6 +241,24 @@ stage('Build') { Utils.markStageSkippedForConditional('BUILD: Hexagon') } }, + 'BUILD: RISC-V': { + if (!skip_ci && is_docs_only_build != 1) { + node('CPU-SMALL') { + ws({{ m.per_exec_ws('tvm/build-riscv') }}) { + docker_init(ci_riscv) + init_git() + sh ( + script: "${docker_run} ${ci_riscv} ./tests/scripts/task_config_build_riscv.sh build", + label: 'Create RISC-V cmake config', + ) + make(ci_riscv, 'build', '-j2') + {{ m.upload_artifacts(tag='riscv', filenames=tvm_lib, folders=microtvm_template_projects) }} + } + } + } else { + Utils.markStageSkippedForConditional('BUILD: RISC-V') + } + }, ) } } diff --git a/ci/jenkins/Test.groovy.j2 b/ci/jenkins/Test.groovy.j2 index 09550a469701..9e8c9ac28b01 100644 --- a/ci/jenkins/Test.groovy.j2 +++ b/ci/jenkins/Test.groovy.j2 @@ -210,6 +210,26 @@ label: 'Run microTVM tests', ) {% endcall %} +{% call(shard_index, num_shards) m.sharded_test_step( + name="test: RISC-V", + node="CPU-SMALL", + ws="tvm/test-riscv", + platform="riscv", + docker_image="ci_riscv", + num_shards=1, + test_method_names=test_method_names, +) %} + {{ m.download_artifacts(tag='riscv', filenames=tvm_lib, folders=microtvm_template_projects) }} + add_microtvm_permissions() + ci_setup(ci_riscv) + {% if shard_index == 1%} + cpp_unittest(ci_cortexm) + {% endif %} + sh ( + script: "${docker_run} ${ci_riscv} ./tests/scripts/task_riscv_microtvm.sh", + label: 'Run microTVM tests', + ) +{% endcall %} def run_unittest_minimal() { {% call m.test_step_body( diff --git a/ci/jenkins/generate.py b/ci/jenkins/generate.py index 3d0198ba6fd9..901d413364b3 100644 --- a/ci/jenkins/generate.py +++ b/ci/jenkins/generate.py @@ -37,11 +37,11 @@ "platform": "ARM", }, { - "name": "ci_cpu", + "name": "ci_cortexm", "platform": "CPU", }, { - "name": "ci_minimal", + "name": "ci_cpu", "platform": "CPU", }, { @@ -61,7 +61,11 @@ "platform": "CPU", }, { - "name": "ci_cortexm", + "name": "ci_minimal", + "platform": "CPU", + }, + { + "name": "ci_riscv", "platform": "CPU", }, { diff --git a/tests/scripts/ci.py b/tests/scripts/ci.py index 4cc19462c907..31b7316d88d8 100755 --- a/tests/scripts/ci.py +++ b/tests/scripts/ci.py @@ -168,6 +168,7 @@ def docker(name: str, image: str, scripts: List[str], env: Dict[str, str], inter "ci_cortexm", "ci_arm", "ci_hexagon", + "ci_riscv", } if image in sccache_images and os.getenv("USE_SCCACHE", "1") == "1": @@ -673,6 +674,19 @@ def add_subparser( ), }, ), + generate_command( + name="riscv", + help="Run RISC-V build and test(s)", + options={ + "cpp": CPP_UNITTEST, + "python": ( + "run full Python tests", + [ + "./tests/scripts/task_riscv_microtvm.sh", + ], + ), + }, + ), ] diff --git a/tests/scripts/task_config_build_riscv.sh b/tests/scripts/task_config_build_riscv.sh new file mode 100755 index 000000000000..9e11e5e255e9 --- /dev/null +++ b/tests/scripts/task_config_build_riscv.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euxo pipefail + +BUILD_DIR=$1 +mkdir -p "$BUILD_DIR" +cd "$BUILD_DIR" +cp ../cmake/config.cmake . + +echo set\(USE_SORT ON\) >> config.cmake +echo set\(USE_MICRO ON\) >> config.cmake +echo set\(USE_CMSISNN ON\) >> config.cmake +echo set\(USE_UMA ON\) >> config.cmake +echo set\(USE_PROFILER ON\) >> config.cmake +echo set\(USE_LLVM llvm-config-10\) >> config.cmake +echo set\(CMAKE_CXX_FLAGS -Werror\) >> config.cmake +echo set\(HIDE_PRIVATE_SYMBOLS ON\) >> config.cmake +echo set\(USE_CCACHE OFF\) >> config.cmake +echo set\(SUMMARIZE ON\) >> config.cmake diff --git a/tests/scripts/task_riscv_microtvm.sh b/tests/scripts/task_riscv_microtvm.sh new file mode 100755 index 000000000000..c597506dfede --- /dev/null +++ b/tests/scripts/task_riscv_microtvm.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euxo pipefail + +source tests/scripts/setup-pytest-env.sh + +make cython3 + +# NOTE: this exists to ensure some tests run on RISC-V image. Without it, Jenkins reports a configuration error. +# This line can be removed when RISC-V tests are added. +run_pytest ctypes riscv-platform-minimal-test-0 tests/python/all-platform-minimal-test