В ходе недавних исследований мы выполнили комплексное тестирование производительности математической библиотеки OpenBLAS на платформе RISC-V и выявили существенную разницу в скорости выполнения ключевой операции матричного умножения cblas_sgemm по сравнению с архитектурой x86 — производительность оказалась значительно ниже. cblas_sgemm - функция для умножения матриц, состоящих из 32-разрядных вещественных чисел. Хотелось бы обратить внимание на то, что функция матричного умножения gemm, соответствующая стандартам BLAS, используется во многих библиотеках и алгоритмах. А OpenBLAS — одна из самых популярных реализаций стандарта BLAS с оптимизацией под различные платформы.
Так на x86_64 OpenBlas получает производительность примерно 80-90 % от теоретического максимума процессора. А на Risc-v примерно 20-25%. Также была рассмотрена самостоятельно реализованная функция перемножения матриц mini-gemm по алгоритму описанному в статье. При этом наша реализация получает производительность 30-35% от максимума. Из чего встает два вопроса: почему на RISC-V не получили 80%, как на x86_64 и как так вышло, что наша реализация обогнала OpenBLAS.
Как проводили тестирование
Тестирование проводилось на двух платах: плата LicheePi 4A и плата Banana Pi BPI-F3. Сборка делалась через кросс-компиляцию. Для LicheePi 4A использовался XuanTie toolchain версии 2.8.1, ссылка для скачивания: Xuantie-900-gcc-linux-5.10.4-glibc-i386-V2.8.1-20240115.tar.gz. Для Banana Pi BPI-F3 использовался SpacemiT toolchain версии 1.0.5, ссылка для скачивания: spacemit-toolchain-linux-glibc-x86_64-v1.0.5.tar.xz.
Оптимизированная под плату Lichee Pi функция mini_gemm была разработана Евгением Латкиным (YADRO) на основе алгоритма, описанного в статье. Исходный код этой реализации доступен в публичном репозитории. Эта реализация была написана под Lichee Pi, у которого 128-битный векторный регистр. Мною же была сделана оптимизация этой функции под Banana Pi c 256-битным векторным регистром. Код для этой реализации доступен в репозитории.
Для сравнения использовали cblas_sgemm из OpenBLAS, mini_gemm и прямую реализацию функции умножения матриц. На графиках они обозначены как OpenBLAS, mini_gemm и Reference соответственно.
Тестировали функции при перемножении квадратных матриц с различным размером. В итоге получились вот такие графики, по которым явно видно, что при большом N наша реализация выигрывает у OpenBLAS.


Обсуждение графиков
На плате Lichee Pi графики у обеих реализаций более менее гладкие. А вот на плате Banana Pi графики очень сильно не стабильные, особенно у нашей реализации. Причем пики производительности приходятся на N кратные 8, что можно объяснить тем, что в один векторный регистр помещается ровно 8, и при таком N выходит так что память векторных регистров используется полностью.
Если рассмотреть только N, делящиеся на 32 (потому, что размер микроядра 12x16 и в реализация лучше работает если N кратно размерностям микроядра), то график все равно получится более гладким.

Также видно что при N > 1000 на Banana Pi наша реализация начинает показывать производительность схожую с OpenBLAS.
Благодарности
Спасибо лаборатории YADRO НГУ за предоставленное для тестирования оборудование и компании YADRO за предоставленный код функции mini_gemm для Lichee Pi.
Список всех ссылок
Статья с Habr-а с реализацией эффективного матричного умножения на x86_64.
Ссылки на описания плат на которых тестировали: плата LicheePi 4A и плата Banana Pi BPI-F3.
Репозиторий с улучшенной под Banana Pi реализацией mini_gemm