Архитектура RISC-V корнями уходит к началу 1980-х годов, группа под руководством Дэвида Паттерсона в стенах университета Беркли разработала архитектуры RISC-I и RISC-II. Долгое время архитектуре приходилось существовать в тени лицензируемых ARM и MIPS ядер. Архитектура RISC-V появилась в 2010 году, и поддерживается Linux Foundation. Отметка в 10 миллиардов произведенных ядер была преодолена за 12 лет.
Сейчас RISC-V может сыграть большую роль в становлении российской микроэлектроники. Компании CloudBEAR и Syntacore работают над процессорами собственной микроархитектуры, совместимыми с системой команд RISC-V. Архитектура RISC-V позволяет нашим разработчикам создавать энергоэффективные процессоры сравнимого с мировым уровня и сохранять программную совместимость со всеми программами, созданными для экосистемы RISC-V во всем мире. Большая часть RISC-V устройств на сегодняшний день требуют кросс-компиляции кода, чем мы сегодня и займемся.
Исследуемое RISC-V устройство
Нашим подопытным является плата MangoPi MQ PRO D1, выполненная в нестандартном розовом цвете.
Характеристики у данной платы следующие:
SoC - Allwinner D1 C906 RISC-V частотой 1 ГГц с 2D ускорителем
1 Гб DDR3L ОЗУ (есть версия платы с 512 Мб)
Разъем для карты MicroSD под систему
Mini HDMI порт
24-контактный разъем для камеры
RTL8723DS модуль Wi-Fi 2,4 ГГц 802.11b/g/n + Bluetooth 4.2 и гнездо для антенны
2 USB type C порта под питание и подключение периферии
40-pins GPIO гребенка, идентичная оной на Raspberry Pi
Данная плата стоит чуть больше 2000 рублей на Aliexpress, что делает ее идеальным кандидатом на знакомство с архитектурой RISC-V.
Установка операционной системы на Mango Pi.
Для работы миникомпьютера нужна специализированная сборка операционной системы. Мы возьмем образ системы Armbian 22.08.0-trunk Jammy c ядром Linux 5.19.0-rc1-d1 с официального сайта mangopi: ссылка. Установка системы делается также, как и на любой Raspberry или его клоне - образ разворачивается на MicroSD карточку, например с помощью Raspberry Pi Imager. Дальше просто вставляем флешку в разъем и подаем питание на плату. Плата начнет загружаться и при подключении mini HDMI к монитору, вы будете видеть логи загрузки.
При первом запуске система предложит установить пароль root-пользователя, а также имя и пароль обычного пользователя. Для подключения WiFi и настройки SSH можно воспользоваться встроенной утилитой armbian-config. В данной утилите с псевдографикой в меню Network можно удобно подключиться к домашней WiFi-сети и включить удаленный доступ по SSH.
С помощью команды ifconfig узнаем ip-адрес нашей MangoPi, чтобы в дальнейшем работать дистанционно.
Установка кросс-компилятора
Сама по себе плата не очень производительная, ведь у нее всего одно процессорное ядро, поэтому для экспериментов наше ПО мы будем собирать с помощью кросс-компилятора на основной машине, и затем запускать на MangoPi.
Для экспериментов подойдет любая актуальная версия Ubuntu, мы воспользуемся версией 23.04. Для сборки программы под RISC-V архитектуру на x86 машине понадобится собрать и установить кросс-компилятор.
Установим зависимости:
sudo apt-get install git cmake autoconf automake autotools-dev curl \
libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo \
gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build
При установке на Ubuntu 20.04 была небольшая ошибка с установкой пакета libglib2.0-dev
, она решилась указанием версии пакета libglib2.0
sudo apt-get install libglib2.0-dev libglib2.0-0=2.64.6-1~ubuntu20.04.3
Скачиваем исходный код кросс-компилятора:
git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
Создадим директорию под собираемый компилятор:
sudo mkdir -m 777 -p /opt/riscv/bin
И добавим наш будущий компилятор в переменную PATH:
export PATH="/opt/riscv/bin:$PATH"
Можно приступать к сборке компилятора. Стоит указать параметр -j с числом физических ядер вашего процессора, чтобы при компиляции использовались все ядра.
./configure --prefix=/opt/riscv
make linux -j$(nproc)
Сборка кросс-компилятора - дело небыстрое, поэтому запасаемся терпением и кофе, и идем полчаса прогуляться. Возвращаясь с прогулки, видим, что наш компьютер перестал шуметь и переходим к сборке тестовой программы.
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
Соберем его с помощью нашего кросс-компилятора:
riscv64-unknown-linux-gnu-gcc hello.c -o hello
Чтобы проверить, что мы действительно собрали приложение для архитектуры RISC-V, можно воспользоваться командами readelf или file:
Утилита readelf
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-readelf -h hello
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 848 (bytes into file)
Flags: 0x5, RVC, double-float ABI
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 12
Section header string table index: 11
Утилита file
$ file hello
hello: ELF 64-bit LSB relocatable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), not stripped
Для удобства переноса файлов с основной машины на MangoPi можно подключиться по SFTP, тогда файловое пространство MangoPi будет доступной папкой в файловом менеджере, что облегчит копирование.
Перекинув собранный бинарный файл на MangoPi, программа запустится. Теперь можно переходить к более полезной задаче - кросс-компиляции библиотеки OpenCV под RISC-V.
Кросс-компиляция библиотеки OpenCV для RISC-V
Чтобы узнать возможности платы, давайте соберем под нее OpenCV. Поскольку наша одноядерная плата хорошо вписывается в задачу edge computing - получения изображения с веб-камеры, некоторой обработки и передачи информации, извлеченной из изображений, в хранилище.
Качаем исходный код OpenCV:
git clone https://github.com/opencv/opencv.git
cd opencv
Создаем папку для билда:
mkdir build_mangopi && cd build_mangopi
Собираем OpenCV, гулять уже не идем, потому что OpenCV собирается значительно быстрее.
cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/riscv64-gcc.toolchain.cmake -DCMAKE_C_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -DCMAKE_CXX_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-g++ -DBUILD_SHARED_LIBS=OFF ../
make -j$(nproc)
В OpenCV собираются несколько тестовых приложений. Перекидываем их на MangoPi и запускаем приложения из папки build_mangopi/bin, собранные с OpenCV. Перенесем файлы из папки build_mangopi/bin на плату и запустим бенчмаркинг модуля core:
build_mangopi/bin/opencv_perf_core
Пришло время кросс-компиляцией собрать собственное приложение, использующее OpenCV. Протестируем скорость работы фильтра Гаусса с большим ядром, повторив запуск фильтра 10 раз. Создадим следующие cpp и cmake файлы.
gaussian.cpp
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat img(2560, 2027, CV_32FC3, Scalar::all(0));
RNG rng;
rng.fill(img, RNG::UNIFORM, 0, 255);
Mat dst;
TickMeter tick;
for (size_t i = 0; i < 10; ++i)
{
tick.start();
GaussianBlur(img, dst, Size(19, 19), 0.84089642);
tick.stop();
cout << i << " | " << tick.getAvgTimeMilli() << " ms" << endl;
}
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project( TestGaussian )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( TestGaussian gaussian.cpp )
target_link_libraries( TestGaussian ${OpenCV_LIBS} )
Команды для кросс-компиляции нашего приложения с использованием функций OpenCV собранным нами компилятором:
cmake -DCMAKE_TOOLCHAIN_FILE=~/opencv/platforms/linux/riscv64-gcc.toolchain.cmake \
-DCMAKE_C_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-g++ \
-DOpenCV_DIR=~/opencv/build_mangopi -DCMAKE_EXE_LINKER_FLAGS="-latomic" ../
make -j$(nproc)
После того, как у вас собрался файл TestGaussian, перенесите его на MangoPi, и запустите. На моем устройстве программа выдала следующие результаты работы. Интересно что разброс времени работы от запуска к запуску одного и того же фильтра достигает 5%.
./TestGaussian
0 | 15376.1 ms
1 | 14943.1 ms
2 | 14808.8 ms
3 | 14721.3 ms
4 | 14672.3 ms
5 | 14652.8 ms
6 | 14625.9 ms
7 | 14616.6 ms
8 | 14601.1 ms
9 | 14599.2 ms
Поздравляем! У вас получилось собрать RISC-V кросс-компилятор, библиотеку OpenCV и собственное приложение с её использованием. В следующих статьях мы попробуем углубиться в оптимизацию и ускорение вычислений под RISC-V, чтобы улучшить данный результат.
Большая благодарность инженерам компании YADRO Владимиру Дуднику, Максиму Шабунину за помощь в подготовке данной статьи.
Комментарии (10)
c0mmandor
09.06.2023 09:20+1Интересно было бы посмотреть есть ли разница в производительности между ядром Xuantie C906 (на котором mangopi-mq-pro плата сделана) и SiFive U74 ядром (на котором VisionFive2 плата делана). Оба поддерживают RVV 0.7.1, при этом C906 имеет задокументированное ограничение, попытка использовать 64-х разрядные элементы в векторном регистре приводит к исключению (ну т.е. не полностью реализовано RISCV RVV). Как с этим в U74? Может есть еще какие то микроархитектурные отличия? То в VisionFive2 процессор двухядерный понятно.
FenixFly Автор
09.06.2023 09:20Да, мы столкнулись с тем, что в MangoPi для использования RVV надо шаманить, постараемся побороть. Сравнить производительность разными бенчмарками было бы конечно супер, может у вас есть подходящие бенчмарки на примете? Сейчас же можно посмотреть некоторые результаты сравнения с VisionFive v1 в этом препринте: https://www.researchgate.net/publication/370814919_Case_Study_for_Running_Memory-Bound_Kernels_on_RISC-V_CPUs
c0mmandor
09.06.2023 09:20спасибо, интересные данные. когда и если доберусь до VisionFive2 или LicheePi-4a очень хочу посмотреть перф и возможности. Если кто уже смотрел и имеет что сказать пож-та не держите в себе.
lenz1986
09.06.2023 09:20+1А не будет статей как запустить свой линукс? НЕ армбиан который везде и всюду уже, а просто ядро.
Mox
Не совсем понятно как быть если собираемая библиотека требует другие библиотеки. Может нужен способ как-то подмонтировать файловую систему целевого RISC-V чтобы оттуда исходники брать? А еще лучше чтобы вендор давал какие-нибудь apt репозитории с уже собранными вещами.
FenixFly Автор
Можно по sftp получить доступ к ФС RISC-V с основной машины (в статье про это немного есть, но тут пожалуй стоит расширить часть по компиляции разного ПО, сделаем в следующих статьях). Репозиторий APT под RISC-V у Mango Pi есть, но пока очень ограниченный.
Chaa
Пакетный менеджер позволяет устанавливать пакеты для другой архитектуры. Использую для сборки версии Aarch64 на обычной x86_64. Для RiscV видимо тоже можно.
Краткое руководство: https://askubuntu.com/questions/430705/
FenixFly Автор
Спасибо! Очень полезно будет тоже разобраться в этом.
Johan_Palych
Если интересует:
https://wiki.debian.org/RISC-V
Pre-built toolchains
$ sudo dpkg --add-architecture riscv64
$ sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu
Run qemu-system-riscv64 with OpenSBI, U-Boot and the disk image
armbian for riscv64 devices such as LicheePi 4A, MangoPi MQ Pro
https://github.com/chainsx/armbian-riscv-build
И готовые образы
https://github.com/chainsx/armbian-riscv-build/releases
FenixFly Автор
Спасибо, замечательные ссылки!