Graviton4 向けの C++ ビルド環境を作成して OpenBLAS で行列計算を試してみた

Graviton4 向けの C++ ビルド環境を作成して OpenBLAS で行列計算を試してみた

2025.10.29

はじめに

C++ と OpenBLAS を使った行列計算プログラムを Graviton(ARM) へ移植できるか検討していました。AWS Graviton テクニカルガイドを読む中で、Graviton4 最適化ビルド環境に興味を持ちました。本記事では、環境構築、性能測定、Graviton4 最適化を試してみた結果を共有します。

https://github.com/aws/aws-graviton-getting-started/tree/main

背景と目的

AWS Graviton4 プロセッサで C++ ビルド環境構築方法を理解することが目的です。

業務上、C++ ビルド環境の理解を深める必要がありました。ただし私は C++ コーディング経験がありません。そのため本記事のサンプルコードは Claude Code で生成しています。本記事の焦点は C++ プログラミングではなく、ビルド環境の構築方法とコンパイラ最適化が性能に与える影響の理解です。

検証内容

Graviton4 プロセッサで C++ と OpenBLAS による行列計算性能を検証しました。環境構築から性能測定、最適化まで試した過程を記録します。

結論

OpenBLAS による行列計算では以下が確認できました。

シングルコアでの実行時間は約 86 秒でした。これに対し、2 コアを使用したマルチコア実行では約 48 秒となり、約 1.78 倍の高速化を達成しました。一方、Graviton4 最適化コンパイルによる追加の性能向上は見られませんでした。

理由は、今回のサンプルコードでは計算時間の 99% 以上が事前コンパイル済み OpenBLAS で消費されるためです。なお、OpenBLAS のような外部ライブラリに依存せず、独自の計算ロジックを C++ で実装している場合は、コンパイラ最適化オプションによる性能向上が期待できます。

検証環境

項目 仕様
リージョン ap-northeast-1(東京)
EC2 インスタンス c8g.large(AWS Graviton4 / ARM64 / 2vCPU)
OS Amazon Linux 2023
GCC 11.5.0
Clang 19.1.7
OpenBLAS 0.3.18
CMake 3.22.2

環境構築手順

システムアップデート

まずシステムを最新の状態に更新します。

sudo dnf update -y

開発ツールのインストール

C++ コンパイラ、ビルドツール、行列計算ライブラリをインストールします。

# Development Tools グループのインストール
sudo dnf groupinstall -y "Development Tools"

# C++ コンパイラとビルドツール
sudo dnf install -y gcc gcc-c++ cmake make git

# OpenBLAS ライブラリ
sudo dnf install -y openblas-devel lapack-devel

インストール確認

コンパイラバージョンの確認

インストールされたツールのバージョンを確認します。

$ gcc --version
gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-5)
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ --version
g++ (GCC) 11.5.0 20240719 (Red Hat 11.5.0-5)
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ cmake --version
cmake version 3.22.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).
$ make --version
GNU Make 4.3
Built for aarch64-amazon-linux-gnu
Copyright (C) 1988-2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[ec2-user@ip-10-0-0-195 ~]$

OpenBLAS のインストール確認

OpenBLAS パッケージが正しくインストールされているか確認します。

# OpenBLAS パッケージ情報
$ rpm -q openblas openblas-devel
openblas-0.3.18-1.amzn2023.0.3.aarch64
openblas-devel-0.3.18-1.amzn2023.0.3.aarch64

Graviton4 プロセッサの機能確認

CPU アーキテクチャと SIMD 拡張の確認

Graviton4 プロセッサの SIMD(Single Instruction Multiple Data)拡張命令セットを確認します。x86-64 の AVX に相当する SVE/SVE2 に対応しているかを確認するのが目的です。

実行結果の Features フィールドから、SVE2 をサポートしていることを確認できました。SVE2 により、行列計算などの並列処理が高速に実行できます。

$ cat /proc/cpuinfo | grep Features
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti

# コアごとに同じ結果が出力されるため省略

CPU 実装情報も確認します。

$ cat /proc/cpuinfo | grep -E "CPU (implementer|architecture|part)"
CPU implementer	: 0x41
CPU architecture: 8
CPU part	: 0xd4f
CPU implementer	: 0x41
CPU architecture: 8
CPU part	: 0xd4f

CPU part 0xd4fは、Neoverse V2 を示しています。

参考: https://gpages.juszkiewicz.com.pl/arm-socs-table/arm-cpu-cores.html

OpenBLAS ビルド情報の実行時確認

OpenBLAS が ARM に最適化されているか確認するため、情報を表示するプログラムを作成します。以下は Claude Code で生成したコードです。

ファイル名: openblas_info.cpp

#include <stdio.h>

extern "C" {
    char* openblas_get_config(void);
    char* openblas_get_corename(void);
    int openblas_get_parallel(void);
    int openblas_get_num_threads(void);
}

int main() {
    printf("=== OpenBLAS Configuration ===\n");
    printf("%s\n", openblas_get_config());
    printf("\n=== Runtime Information ===\n");
    printf("Core Name: %s\n", openblas_get_corename());
    printf("Parallel: %d\n", openblas_get_parallel());
    printf("Threads: %d\n", openblas_get_num_threads());
    return 0;
}

コンパイルして実行します。

# コンパイル
g++ openblas_info.cpp -o openblas_info -lopenblas

# 実行
./openblas_info

実行結果の armv8 表記から、ARM に最適化されていることが確認できました。

$ ./openblas_info
=== OpenBLAS Configuration ===
OpenBLAS 0.3.18 DYNAMIC_ARCH NO_AFFINITY armv8 SINGLE_THREADED

=== Runtime Information ===
Core Name: armv8
Parallel: 0
Threads: 1

サンプルプログラムの作成

行列計算ベンチマーク

10000×10000 の行列乗算を 3 回実行し、性能を測定するプログラムを作成します。こちらも Claude Code で生成したコードです。

ファイル名: performance_test.cpp

#include <cblas.h>
#include <chrono>
#include <iostream>
#include <vector>
#include <unistd.h>

void run_benchmark(const char* label) {
    const int N = 10000;
    std::vector<double> A(N*N, 1.0);
    std::vector<double> B(N*N, 2.0);
    std::vector<double> C(N*N, 0.0);

    auto start = std::chrono::high_resolution_clock::now();

    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 duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    std::cout << label << ": " << duration.count() << " ms" << std::endl;
}

int main() {
    std::cout << "Available CPUs: " << sysconf(_SC_NPROCESSORS_ONLN) << std::endl;

    const char* num_threads = getenv("OPENBLAS_NUM_THREADS");
    std::cout << "OPENBLAS_NUM_THREADS: "
              << (num_threads ? num_threads : "not set") << std::endl;

    std::cout << "\nRunning 10000x10000 matrix multiplication...\n" << std::endl;

    run_benchmark("Test 1");
    run_benchmark("Test 2");
    run_benchmark("Test 3");

    return 0;
}

OpenBLASライブラリのバージョン指定

Amazon Linux 2023 では、OpenBLAS が複数のバージョンで提供されています。知らないとコンパイルのときに困りますね。

リンカオプション ライブラリファイル 種類 説明
-lopenblas libopenblas.so Serial 版 シングルスレッド(1 コアのみ使用)
-lopenblasp libopenblasp.so OpenMP 版 マルチスレッド(複数コア使用)
-lopenblaso libopenblaso.so pthread 版 マルチスレッド(複数コア使用)

コンパイルと実行

シングルスレッド版とマルチスレッド版(OpenMP 版)の 2 つをコンパイルして性能を比較します。

# Serial 版のコンパイル
g++ -O3 performance_test.cpp -o test_serial -lopenblas

# OpenMP 版のコンパイル、OpenMP 有効化のフラグ付き
g++ -O3 performance_test.cpp -o test_parallel -lopenblasp -fopenmp
Serial 版の実行結果
# Serial 版テスト(1 コアを明示的に指定)
$ export OPENBLAS_NUM_THREADS=1
$ ./test_serial

Available CPUs: 2
OPENBLAS_NUM_THREADS: 1

Running 10000x10000 matrix multiplication...

Test 1: 86053 ms
Test 2: 86054 ms
Test 3: 86072 ms
OpenMP 版の実行結果
# OpenMP 版テスト(2 コアを明示的に指定)
$  export OPENBLAS_NUM_THREADS=2
$  ./test_parallel

Available CPUs: 2
OPENBLAS_NUM_THREADS: 2

Running 10000x10000 matrix multiplication...

Test 1: 48214 ms
Test 2: 48250 ms
Test 3: 48217 ms

実行結果

シングルコアでは約 86 秒、マルチコア(2 コア)では約 48 秒となり、約 1.78 倍の高速化を確認できました。コア数が 2 倍になったため、想定通りの結果です。

Graviton4 最適化を試してみる

参考にした AWS 公式ガイド

Graviton4 向けの最適化方法について、AWS の公式 GitHub リポジトリで公開されている以下のガイドを参考にしました。

https://github.com/aws/aws-graviton-getting-started/blob/main/c-c++.md

このガイドによると、Graviton4(Neoverse V2)向けの最適化には以下が推奨されています。

  • 推奨コンパイラバージョン: GCC 13 以上または Clang/LLVM 16 以上
  • パフォーマンス優先: -mcpu=neoverse-v2 フラグを使用

Amazon Linux 2023 の GCC バージョンは 11.5 でした。Graviton4 の性能を最大限引き出すには GCC 13 以上へのアップグレードが必要です。GCC のアップグレードより Clang をインストールする方が楽だったため、現時点で最新だった Clang 19 を利用しました。

$ sudo dnf install -y clang19
$ clang++-19 --version
clang version 19.1.7 (AWS 19.1.7-13.amzn2023.0.1)
Target: aarch64-amazon-linux-gnu

Clang 19 で Graviton4 最適化したコンパイル

上記ガイドを参考に、Graviton4(Neoverse V2)専用の最適化オプションを使ってコンパイルします。

clang++-19 -O3 -mcpu=neoverse-v2 -moutline-atomics performance_test.cpp -o test_g4_optimized -lopenblasp -fopenmp

実行します。

export OPENBLAS_NUM_THREADS=2
./test_g4_optimized

Available CPUs: 2
OPENBLAS_NUM_THREADS: 2

Running 10000x10000 matrix multiplication...

Test 1: 48238 ms
Test 2: 48254 ms
Test 3: 48215 ms

実行結果

結果として、Graviton4 最適化でも実行時間は約 48 秒となり、GCC でコンパイルした OpenMP 版とほぼ同じ性能でした。

性能測定結果のまとめ

実行結果一覧

設定 コンパイラ オプション コア数 実行時間 速度比
Serial 版 GCC 11.5 -O3 -lopenblas 1 86,053ms 1.00x
OpenMP 版 GCC 11.5 -O3 -lopenblasp -fopenmp 2 48,214ms 1.78x
Graviton4 最適化 Clang 19 -O3 -mcpu=neoverse-v2 -moutline-atomics 2 48,238ms 1.78x

マルチコア対応により、2 コア使用で約 1.78 倍の性能向上を確認しました。一方、Graviton4 最適化では、GCC の OpenMP 版とほぼ同等の性能で、更なる高速化は見られませんでした。

結論として、計算時間の大部分が事前に ARMv8 向け(汎用)にコンパイル済みの OpenBLAS ライブラリ内で消費されるためです。C++ コードを Graviton4 最適化オプションでコンパイルしても性能に影響しませんでした。

まとめ

Graviton4 での C++ ビルド環境構築と行列計算の性能検証を通じて、以下のことを学びました。

ビルド環境について

AWS は Graviton 向けのテクニカルガイドを用意しています。このガイドに従うことで、ARM アーキテクチャでも環境構築できました。

性能測定結果について

行列計算は OpenBLAS を利用したサンプルプログラムで検証しました。Graviton4 最適化オプションによる追加の性能向上は見られませんでした。

  1. OpenBLAS は事前コンパイル済みライブラリである

    • C++ のプログラムのコンパイル時のフラグは OpenBLAS 内部に影響しない(当然)
    • OpenBLAS 自体は既に ARMv8 最適化されている
  2. 計算時間の 99% 以上が OpenBLAS 内部で消費される

    • 今回のコードは単に OpenBLAS を呼び出すだけのプログラム
    • コンパイルによる最適化の余地が非常に少ない

なお、自前の計算ロジックが多い場合は、コンパイラ最適化による性能変化が期待できます。

おわりに

当初は「Graviton(ARM)の方が難しそう」という先入観から興味本位で着手しました。今回、Graviton4 での C++ ビルド環境構築と性能検証を試みました。C++ の知識が乏しい状態からのスタートでしたが、AWS の Graviton ガイドと Claude Code のコード生成により、環境構築から性能測定まで試すことができました。

行列計算で OpenBLAS 使って、最適化するなら OpenBLAS をソースコードからビルドしないと効果薄いなと学びがありました。OpenBLAS について深く考えたことなかったのでよい勉強の機会となりました。次は業務で必要な x86-64(Intel/AMD)環境で試してみます。

本記事が Graviton 環境での C++ 開発を検討されている方の参考になれば幸いです。

参考

この記事をシェアする

FacebookHatena blogX

関連記事