AWS Graviton4でARM Performance Librariesを使ってOpenBLASと性能比較してみた

AWS Graviton4でARM Performance Librariesを使ってOpenBLASと性能比較してみた

2026.01.31

はじめに

前回の検証では、Graviton4 向けに OpenBLAS をソースビルドし、apt でインストール版と比べ約 8〜10% の性能向上を確認しました。ARM 社公式の高性能数学ライブラリ ARMPL を利用した場合はどうなのか気になったので検証してみました。

https://dev.classmethod.jp/articles/openblas-graviton4-optimized-build-benchmark/

検証結果早見

単純な行列計算の時間の比較では、ARMPL は apt インストール版の OpenBLAS より 31〜41% 高速でした。OpenBLAS Graviton4 最適化版との比較でも 20〜31% の性能向上を確認できました。早い!

ARMPL とは

ARM Performance Libraries(ARMPL)は、ARM 社が提供する高性能な数学ライブラリです。

  • BLAS(基本線形代数サブプログラム)
  • LAPACK(線形代数パッケージ)
  • FFT(高速フーリエ変換)
  • libm(数学関数ライブラリ)

https://developer.arm.com/Tools and Software/Arm Performance Libraries#Downloads

無償ライセンス

商用利用・製品への組み込み・条件付きで再配布が可能ですが、保証・サポートはありません。パフォーマンをレポートすること自体も問題なかったので検証することにしました。

"Your Reports" means any written reports or other information relating to the behavior or performance of Your Software or Your Hardware, in html, binary, text or any other format, generated by you from or using the Arm Tools and any modifications thereto.
license_agreement.txt より

検証環境

項目 バージョンなど
インスタンスタイプ m8g.xlarge(4 vCPU, 16 GiB)
OS Ubuntu 24.04.3 LTS
CPU AWS Graviton4(Neoverse-V2)
GCC 13.3.0
OpenBLAS(apt) 0.3.26
OpenBLAS(Graviton4 最適化) 0.3.31.dev
ARMPL 26.01
リージョン us-east-1

前回検証で構築した環境をそのまま使用しています。

検証手順

ARMPL のインストール

ARM 社の公式サイトからパッケージを取得します。

https://developer.arm.com/downloads/-/arm-performance-libraries

ちょうど今月リリースされた最新版があったのでそちらをダウンロードします。

cd ~
wget https://developer.arm.com/-/cdn-downloads/permalink/Arm-Performance-Libraries/Version_26.01/arm-performance-libraries_26.01_deb_gcc.tar

展開してインストールします。-a オプションはライセンス同意を自動で承諾します。

tar -xvf arm-performance-libraries_26.01_deb_gcc.tar
cd arm-performance-libraries_26.01_deb/
sudo ./arm-performance-libraries_26.01_deb.sh -a
実行結果
Unpacking...
Setting up arm-performance-libraries-26.01-gcc (26.01-1333) ...
Setting up armpl-26.01-gcc (26.01.0-5095) ...
The environment-modules package does not appear to be installed.

インストール先を確認します。

ls /opt/arm/
実行結果
arm-performance-libraries_26.01_gcc  armpl_26.01_gcc  modulefiles

ライブラリファイルを確認します。

ls /opt/arm/armpl_26.01_gcc/lib/ | head -5
実行結果
libamath.a
libamath.so
libamath_repro.a
libamath_repro.so
libarmpl.a

主要ファイルは以下のとおりです。

  • libarmpl.so:シリアル版(シングルスレッド)
  • libarmpl_mp.so:OpenMP 版(マルチスレッド対応)

ベンチマークプログラムの準備

前回検証と同じ DGEMM ベンチマークを使用します。ソースコードは同一で、リンクするライブラリのみを差し替えてビルドします。

mkdir -p ~/benchmark-armpl
cd ~/benchmark-armpl
benchmark_dgemm.cpp
#include <iostream>
#include <vector>
#include <chrono>
#include <random>
#include <cblas.h>

int main(int argc, char *argv[]) {
    int N = (argc > 1) ? std::stoi(argv[1]) : 10000;
    int REPEAT = (argc > 2) ? std::stoi(argv[2]) : 3;

    // 行列メモリ確保
    std::vector<double> A(N * N);
    std::vector<double> B(N * N);
    std::vector<double> C(N * N, 0.0);

    // 乱数初期化
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<double> dist(0.0, 1.0);

    for (int i = 0; i < N * N; ++i) {
        A[i] = dist(gen);
        B[i] = dist(gen);
    }

    std::cout << "Matrix size: " << N << " x " << N << std::endl;
    std::cout << "Repeat: " << REPEAT << " times" << std::endl;

    // ベンチマーク実行
    auto start = std::chrono::high_resolution_clock::now();

    for (int r = 0; r < REPEAT; ++r) {
        cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                    N, N, N, 1.0, A.data(), N, B.data(), N, 0.0, C.data(), N);
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    // 結果出力
    double elapsed_sec = elapsed_ms / 1000.0;
    double gflops = (2.0 * N * N * N * REPEAT) / elapsed_sec / 1e9;
    std::cout << "Time: " << elapsed_ms << " ms" << std::endl;
    std::cout << "GFLOPS: " << gflops << std::endl;

    return 0;
}

各ライブラリ向けビルド

同一ソースコードから 3 種類のバイナリをビルドします。

OpenBLAS apt 版のビルドです。

g++ -O3 benchmark_dgemm.cpp -o bench_openblas_apt -lopenblas

OpenBLAS Graviton4 最適化版のビルドです。

g++ -O3 benchmark_dgemm.cpp -o bench_openblas_neoversev2 \
    -I/opt/openblas-neoversev2/include \
    -L/opt/openblas-neoversev2/lib -lopenblas \
    -Wl,-rpath,/opt/openblas-neoversev2/lib

ARMPL 版のビルドです。OpenMP 版(libarmpl_mp.so)をリンクします。

g++ -O3 benchmark_dgemm.cpp -o bench_armpl_mp \
    -I/opt/arm/armpl_26.01_gcc/include \
    -L/opt/arm/armpl_26.01_gcc/lib -larmpl_mp -lm -fopenmp \
    -Wl,-rpath,/opt/arm/armpl_26.01_gcc/lib

リンク先を確認します。

ldd ./bench_openblas_apt | grep -E "openblas|armpl"
実行結果
        libopenblas.so.0 => /lib/aarch64-linux-gnu/libopenblas.so.0 (0x0000f2b4b3090000)
ldd ./bench_openblas_neoversev2 | grep -E "openblas|armpl"
実行結果
        libopenblas.so.0 => /opt/openblas-neoversev2/lib/libopenblas.so.0 (0x0000faea603c0000)
ldd ./bench_armpl_mp | grep -E "openblas|armpl"
実行結果
        libarmpl_mp.so => /opt/arm/armpl_26.01_gcc/lib/libarmpl_mp.so (0x0000f165cfbf0000)

ソースコードを変更せずにライブラリを差し替えできることを確認しました。

ベンチマーク実行

10000 x 10000 の行列積を 3 回実行しました。

OpenBLAS apt 版

# 1スレッド
export OMP_NUM_THREADS=1
./bench_openblas_apt 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 238419 ms
GFLOPS: 25.1658
# 4スレッド
export OMP_NUM_THREADS=4
./bench_openblas_apt 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 79173 ms
GFLOPS: 75.7834

OpenBLAS Graviton4 最適化版

# 1スレッド
export OMP_NUM_THREADS=1
./bench_openblas_neoversev2 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 217550 ms
GFLOPS: 27.5799
# 4スレッド
export OMP_NUM_THREADS=4
./bench_openblas_neoversev2 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 73311 ms
GFLOPS: 81.8431

ARMPL

# 1スレッド
export OMP_NUM_THREADS=1
./bench_armpl_mp 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 181214 ms
GFLOPS: 33.11
# 4スレッド
export OMP_NUM_THREADS=4
./bench_armpl_mp 10000 3
実行結果
Matrix size: 10000 x 10000
Repeat: 3 times
Time: 55981 ms
GFLOPS: 107.179

実行結果と分析

想像よりずっと早い。

結果まとめ

ライブラリ スレッド数 時間 GFLOPS apt 比
OpenBLAS(apt) 1 238 秒 25.17 -
OpenBLAS(apt) 4 79 秒 75.78 -
OpenBLAS(Graviton4 最適化) 1 218 秒 27.58 +9.6%
OpenBLAS(Graviton4 最適化) 4 73 秒 81.84 +8.0%
ARMPL 1 181 秒 33.11 +31.5%
ARMPL 4 56 秒 107.18 +41.4%

性能比較

apt でインストール OpenBLAS vs OpenBLAS Graviton4 最適化

前回検証と同様の結果を確認しました。Graviton4 向けにソースビルドすることで約 8〜10% の性能向上が得られました。

理由は以下のとおりです。

  • apt 版は DYNAMIC_ARCH でビルドされており、実行時に neoversev1 カーネルを使用
  • Graviton4 最適化版はビルド時に明示的に neoversev2 カーネルを使用

OpenBLAS Graviton4 最適化 vs ARMPL

ARMPL は OpenBLAS より大幅に高速でした。

スレッド数 OpenBLAS(Graviton4 最適化) ARMPL
1 27.58 GFLOPS 33.11 GFLOPS +20.1%
4 81.84 GFLOPS 107.18 GFLOPS +31.0%

apt 版 OpenBLAS との比較では 31〜41% の性能向上です。ARMPL は ARM 社が Neoverse 向けに最適化しているため高いパフォーマンスを発揮しているようです。ここまで違いがあるとは思っていませんでした。

マルチスレッドスケーリング

ARMPL はスケーリング効率も良好です。4 コアまでしか試していないため参考程度に。

ライブラリ 1→4 スレッド倍率
OpenBLAS(apt) 3.01 倍
OpenBLAS(Graviton4 最適化) 2.97 倍
ARMPL 3.24 倍

まとめ

Graviton4 環境で OpenBLAS と ARMPL の性能を比較しました。

  • ARMPL は apt 版 OpenBLAS より 31〜41% 高速
  • ARMPL は OpenBLAS Graviton4 最適化版より 20〜31% 高速
  • ソースコード変更なしでライブラリを差し替え可能

Graviton4 で数値計算性能を最大化するなら ARMPL の採用検討の余地ありでした。

おわりに

ARMPL は OpenBLAS より大幅に高速でした。BLAS 標準 API のため既存コードの変更も不要でした。もっとめんどくさいことになるものだと勝手に思っていました。ということで x86-64 から Graviton へ移行する際は ARMPL を検討する価値がありました。

ARMPL 利用時の注意点

ARMPL にはシリアル版(libarmpl.so)と OpenMP 版(libarmpl_mp.so)があります。通常マルチスレッドで使用しますので OpenMP 版をリンクしてください。

今回の検証で最初にシリアル版をリンクしてしまい、スレッド数を増やしても性能が変わらなく間違いに気が付きました。

# シリアル版(libarmpl.so)をリンクした場合
export OMP_NUM_THREADS=1
./bench_armpl 10000 3
# Time: 181176 ms, GFLOPS: 33.117

export OMP_NUM_THREADS=4
./bench_armpl 10000 3
# Time: 181121 ms, GFLOPS: 33.127  ← 性能が変わらない!

スレッド数を 1 から 4 に増やしても実行時間がほぼ同じです。OMP_NUM_THREADS を変更しても効果がない場合はリンクしているライブラリを確認してください。

ldd ./bench_armpl | grep armpl
# libarmpl.so が表示される → シリアル版

ldd ./bench_armpl_mp | grep armpl
# libarmpl_mp.so が表示される → OpenMP版(正しい)

参考

この記事をシェアする

FacebookHatena blogX

関連記事