You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by ar...@apache.org on 2022/08/15 21:01:43 UTC

[tvm] branch add-riscv-image updated (dc3820f5d4 -> b54be4cc7d)

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

areusch pushed a change to branch add-riscv-image
in repository https://gitbox.apache.org/repos/asf/tvm.git


    omit dc3820f5d4 Add RISC-V build/test pipeline to Jenkins.
     new b54be4cc7d Add RISC-V build/test pipeline to Jenkins.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (dc3820f5d4)
            \
             N -- N -- N   refs/heads/add-riscv-image (b54be4cc7d)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Jenkinsfile                | 9 +++++----
 ci/jenkins/Build.groovy.j2 | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)


[tvm] 01/01: Add RISC-V build/test pipeline to Jenkins.

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

areusch pushed a commit to branch add-riscv-image
in repository https://gitbox.apache.org/repos/asf/tvm.git

commit b54be4cc7d2a6d11b8e18a85b4a62db65f55174e
Author: Andrew Reusch <ar...@gmail.com>
AuthorDate: Mon Aug 15 10:13:09 2022 -0700

    Add RISC-V build/test pipeline to Jenkins.
---
 Jenkinsfile                              | 256 +++++++++++++++++++++++++------
 ci/jenkins/Build.groovy.j2               |  18 +++
 ci/jenkins/Test.groovy.j2                |  17 ++
 ci/jenkins/generate.py                   |  10 +-
 tests/scripts/task_config_build_riscv.sh |  35 +++++
 tests/scripts/task_riscv_microtvm.sh     |  25 +++
 6 files changed, 311 insertions(+), 50 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index bab7257e8f..0d4bd48f42 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-15T14:01:29.759271
 
 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}/cortexm/build/libtvm.so
+              md5sum build/libtvm_runtime.so
+              retry 3 aws s3 cp --no-progress build/libtvm_runtime.so s3://${s3_prefix}/cortexm/build/libtvm_runtime.so
+              md5sum build/config.cmake
+              retry 3 aws s3 cp --no-progress build/config.cmake s3://${s3_prefix}/cortexm/build/config.cmake
+              retry 3 aws s3 cp --no-progress build/microtvm_template_projects s3://${s3_prefix}/cortexm/build/microtvm_template_projects --recursive
+            """,
+            label: 'Upload artifacts to S3',
+          )
+
+        }
+      }
+     } else {
+      Utils.markStageSkippedForConditional('BUILD: RISC-V')
+    }
+  },
   )
 }
 }
@@ -4977,6 +5048,80 @@ 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)
+              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 +5345,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 +5733,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 +5782,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 +5860,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 21b8b2c65f..675f976f13 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='cortexm', 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 09550a4697..9e59942599 100644
--- a/ci/jenkins/Test.groovy.j2
+++ b/ci/jenkins/Test.groovy.j2
@@ -210,6 +210,23 @@
     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)
+  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 3d0198ba6f..901d413364 100644
--- a/ci/jenkins/generate.py
+++ b/ci/jenkins/generate.py
@@ -37,11 +37,11 @@ data = {
             "platform": "ARM",
         },
         {
-            "name": "ci_cpu",
+            "name": "ci_cortexm",
             "platform": "CPU",
         },
         {
-            "name": "ci_minimal",
+            "name": "ci_cpu",
             "platform": "CPU",
         },
         {
@@ -61,7 +61,11 @@ data = {
             "platform": "CPU",
         },
         {
-            "name": "ci_cortexm",
+            "name": "ci_minimal",
+            "platform": "CPU",
+        },
+        {
+            "name": "ci_riscv",
             "platform": "CPU",
         },
         {
diff --git a/tests/scripts/task_config_build_riscv.sh b/tests/scripts/task_config_build_riscv.sh
new file mode 100755
index 0000000000..9e11e5e255
--- /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 0000000000..1b55ac1c51
--- /dev/null
+++ b/tests/scripts/task_riscv_microtvm.sh
@@ -0,0 +1,25 @@
+#!/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: no tests are added here for now.