Skip to main content

RISC-V Workflows on GitHub Actions (QEMU)

June 28, 2025technicalGitHubAbout 2 min

RISC-V Workflows on GitHub Actions (QEMU)

GitHub Actions provides various continuous integration environments for projects hosted on GitHub, including three operating systems (Linux, macOS, and Windows) and two architectures (AMD64 and ARM64). These environments are sufficient for most projects, but RISC-V developers may find it challenging to run RISC-V workflows on GitHub Actions. Commercial companies can use self-hosted runners (refer to Supporting runners on 64bit RISC-Vopen in new window) or service providers (RISC-V Runnersopen in new window and Cloud-Vopen in new window), but for individual developers, this represents a significant expense.

The Savior: QEMU

An obvious solution is to use QEMU to emulate RISC-V on GitHub Actions and run workflows within the virtual machine. Configuring and launching QEMU isn't straightforward, but uraimo/run-on-arch-actionopen in new window can help handle the tedious QEMU operations.

Let's take the GoATopen in new window project as an example to create a RISC-V workflow. The GoATopen in new window project compiles C code into Go assembly, supporting AMD64, ARM64, and RISC-V architectures. Below is the RISC-V test workflow:

name: test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  riscv:
    name: ubuntu-24.04-riscv
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: uraimo/run-on-arch-action@v3
        with:
          arch: riscv64
          distro: ubuntu24.04
          githubToken: ${{ github.token }}
          dockerRunArgs: |
            --volume "${PWD}:/opt/goat"
          install: |
            apt-get update
            apt-get install -y clang golang
          run: |
            cd /opt/goat
            go run . tests/src/universal.c -o tests -march=rv64imafd
            go test -v ./tests

After checking out, uraimo/run-on-arch-actionopen in new window is used. Here’s an explanation of each parameter:

  • arch: The architecture, set to riscv64.
  • distro: The Linux distribution used, here Ubuntu 24.04.
  • githubToken: Used to save workflow caches.
  • dockerRunArgs: Maps the current directory into the virtual machine.
  • install: Installs dependencies, with the resulting image saved in the cache for future use.
  • run: The corresponding test commands.

The Cost of Emulation

Emulating RISC-V on AMD64 comes at a cost. For complex logic or computationally intensive tests, QEMU struggles to keep up. Below is a comparison of execution times for some unit tests from the Gorse recommender systemopen in new window on AMD64 versus QEMU-emulated RISC-V:

TestAMD64RISC-V (QEMU)
common/ann.TestMNIST22.58s562.50s
common/ann.TestMovieLens25.96s91.42s
common/nn.TestNeuralNetwork1.22s12.10s
common/nn.TestIris8.98s139.29s
model/cf.TestBPR_MovieLens23.328s247.33s
model/cf.TestCCD_MovieLens8.73s102.63s
TestFactorizationMachines_Classification_Frappe29.13s176.41s

The tests listed are computationally intensive, and the execution times on QEMU-emulated RISC-V show a significant gap compared to AMD64. Running unit tests on QEMU is no longer practical.

Conclusion

This article explains how to run RISC-V workflows on GitHub Actions. Using uraimo/run-on-arch-actionopen in new window makes it easy to run workflows in a QEMU-emulated RISC-V environment. Although the performance of QEMU-emulated RISC-V falls short of real hardware, it is sufficient for most testing purposes. For individual developers, using QEMU to emulate RISC-V is an economical choice.