プログラムのコンパイル方法¶
概要¶
GCCおよびNVIDIA HPC SDK(NVHPC)によるプログラムのコンパイル方法について説明します。
利用可能なコンパイラ¶
GCC(GNU Compiler Collection)¶
GCCはLinux環境で広く利用されているオープンソースコンパイラです。C、C++、Fortranに対応しており、CPU向けアプリケーション開発のコンパイラとして利用できます。一般的な数値計算プログラムやオープンソースソフトウェアのビルドではGCCを使用します。また、OpenMPによる共有メモリ並列化や、MPI環境と組み合わせたCPU並列プログラム開発にも利用できます。
利用できるコンパイラ:
| 言語 | コマンド |
|---|---|
| C | gcc |
| C++ | g++ |
| Fortran | gfortran |
バージョン確認:
NVIDIA HPC SDK(NVHPC)¶
NVHPCはNVIDIAが提供する高性能計算向けのコンパイラおよび関連ツール群です。OpenACCやCUDAによるGPUプログラミング、およびGPUライブラリを利用したアプリケーション開発に使用します。
利用できるコンパイラ:
| 言語 | コマンド |
|---|---|
| C | nvc |
| C++ | nvc++ |
| Fortran | nvfortran |
バージョン確認:
コンパイル¶
コンパイルとは、ソースコードから実行可能なプログラムを生成する処理です。基本的な開発手順は次のとおりです。
- ソースコードを作成する
- コンパイラを実行する
- エラーや警告を確認する
- 実行ファイルを生成する
- 実行結果を確認する
GCCによるコンパイル¶
C言語¶
C++¶
C++ ではコンパイラやライブラリのバージョンによりデフォルトの言語規格が異なる場合があります。移植性を高めるため、-stdオプションで使用する言語規格を明示することを推奨します。
Fortran¶
C++ と同様に、-stdオプションで使用する言語規格を明示することを推奨します。
NVHPCによるコンパイル¶
NVHPCを使用するには、事前にmodule load nvhpcコマンドで環境を設定してください。
C言語¶
C++¶
Fortran¶
基本的なコンパイルオプション¶
出力ファイルの指定¶
-oオプションで出力ファイル名を指定します。-oオプションを省略した場合、実行ファイル名はa.outになります。
インクルードパスの指定¶
利用するライブラリのヘッダファイルが標準パス外に配置されている場合は、-Iオプションで検索先ディレクトリを追加してください。
ライブラリのリンク¶
コンパイル処理とリンク処理は別工程です。コンパイルが成功しても、対応するライブラリがリンクされていない場合はundefined referenceエラーが発生します。外部ライブラリをリンクする場合、-Lオプションでライブラリディレクトリを、-lオプションでライブラリ名を指定します。
最適化オプション¶
コンパイラの最適化レベルを指定することで、実行速度を改善できます。最適化オプションは、コンパイラがプログラムの実行効率を改善するために行う変換処理を制御します。
| オプション | 説明 | 用途 |
|---|---|---|
-O0 |
最適化なし | デバッグ時。コンパイルが高速 |
-O1 |
基本的な最適化 | デバッグと実行速度のバランス |
-O2 |
標準最適化(推奨) | ほとんどの場合に適する |
-O3 |
高度な最適化 | 最大速度追求。コンパイル時間が長い |
-Ofast |
最も積極的な最適化 | 最大速度追求。精度に注意 |
一般的な利用では-O2を推奨します。-O3や-Ofastは性能を重視する場合に利用します。
Note
開発中はデバッグ情報(-g)や警告表示(-Wall)を有効にし、問題がないことを確認してから最適化オプションを適用することを推奨します。-gオプションはデバッグ情報を埋め込み、gdbなどのデバッガで解析を行う際に利用します。-Wallオプションは一般的な警告を有効化します。コンパイルが成功していても警告が表示される場合は、コードに問題が潜んでいる可能性があるため確認してください。
Tip
最適化レベルが高いほどデバッグが難しくなります。問題解析時は-O0または-O1の利用を推奨します。
Warning
-O3や-Ofastで最適化したプログラムは、特に浮動小数点計算において計算結果が変わる可能性があります。
並列化¶
OpenMPによる共有メモリ並列化¶
OpenMPはシングルノード内の複数CPUコアを利用した共有メモリ並列化を実現します。
GCC¶
コンパイル時に-fopenmpオプションを指定します。実行時に使用するスレッド数を環境変数OMP_NUM_THREADSで指定します。
NVHPC¶
コンパイル時に-mpオプションを使用します。実行時に使用するスレッド数を環境変数OMP_NUM_THREADSで指定します。
MPIによる分散メモリ並列化¶
MPIは複数の計算ノード間でのプロセス間通信を実現します。module load nvhpcにより、NVHPCに同梱されたOpen MPIベースのMPI環境が利用可能になります。
MPIプログラムのコンパイルには、gcc、g++、gfortranやnvc、nvc++、nvfortranを直接使うのではなく、MPI用のラッパーコンパイラであるmpicc、mpic++、mpifortを利用します。これらのラッパーは、MPIライブラリのインクルードパスとリンク指定を自動的に付与したうえで、内部でNVHPCのコンパイラ(nvcなど)を呼び出します。
コンパイルしたMPIプログラムを実行するにはmpirunコマンドを使用します。-np 4は4プロセスで実行することを指定しています。
module load nvhpc
mpicc sample.c -o sample # C 言語
mpic++ sample.cpp -o sample # C++
mpifort sample.f90 -o sample # Fortran
mpirun -np 4 ./sample
ラッパーコンパイラが内部で使用するコンパイラおよびオプションは、--showオプションで確認できます。
MPIとOpenMPのハイブリッド並列化¶
複数ノードの複数CPUコアを効率的に利用するため、MPIとOpenMPを組み合わせたハイブリッド並列化が有効です。ラッパーコンパイラは内部でNVHPCのコンパイラを呼び出すため、OpenMPを有効化するオプションは前述のNVHPCと同じ-mpを指定します。
module load nvhpc
mpicc -mp hybrid_sample.c -o hybrid_sample
export OMP_NUM_THREADS=2
mpirun -np 4 ./hybrid_sample
この例は4プロセスを起動し、各プロセスが2スレッドで実行される設定です。
GPU開発¶
GPU環境の確認¶
| コマンド | 説明 |
|---|---|
nvcc --version |
CUDAコンパイラのバージョンを表示します。 |
nvidia-smi |
GPU使用率、メモリ使用量、ドライバ情報を表示します。 |
nvidia-smi -L |
システムで認識されているGPU一覧を表示します。 |
nvidia-smi -q |
GPUの詳細情報(温度、クロック、ECC状態など)を表示します。 |
OpenACCによるGPUプログラミング¶
OpenACCは、C/C++ およびFortranプログラムをGPUにオフロードするための指示文ベースのプログラミングモデルです。CUDAのようにGPU向けの処理やメモリ管理を明示的に実装する必要がなく、ソースコードへ指示文を追加することでGPUを利用できます。
OpenACCのメリットとして、次の点が挙げられます。
- 既存コードのGPU化が容易
- ソースコードの修正量が少ない
- 学習コストが比較的低い
CUDAのメリットとして、次の点が挙げられます。
- GPU固有機能を詳細に利用可能
- より細かな性能チューニングが可能
一方、CUDAはGPU向けの処理を明示的に記述する必要があるため、実装や保守の負担は大きくなります。
性能チューニングやGPU固有機能を最大限活用したい場合はCUDAの利用も選択肢となりますが、多くの科学技術計算コードではOpenACCによるGPU化から検討することを推奨します。
OpenACCのコンパイル¶
OpenACCを利用する場合は-accオプションを指定します。
C言語¶
C++¶
Fortran¶
-Minfo=accelオプションにより、OpenACCコンパイル時にGPU化された処理内容を確認できます。
出力例:
main:
4, Generating implicit firstprivate(n,i)
Generating NVIDIA GPU code
6, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
4, Generating implicit copyin(a[:1000]) [if not already present]
Generating implicit copyout(c[:1000]) [if not already present]
Generating implicit copyin(b[:1000]) [if not already present]
MPIとOpenACCの併用¶
MPIとOpenACCを組み合わせることで、複数ノード・複数GPUを利用した並列計算を実行できます。MPIはノード間の通信を担当し、OpenACCは各MPIプロセスに割り当てられたGPU上で計算処理を実行します。
C言語¶
C++¶
Fortran¶
Note
MPIプロセスとGPUを組み合わせて利用するアプリケーションでは、1 GPUに対して1 MPIプロセスを割り当てる構成がよく利用されます。
CUDAによるコンパイル¶
CUDA関連機能を利用する場合は、CUDAコンパイラおよびライブラリの利用が必要です。NVHPCでは-cudaオプションを指定することでCUDA機能を有効化できます。
C言語¶
C++¶
Fortran¶
Compute Capabilityの指定¶
生成するGPUコードの世代は-gpu=ccXXオプションで指定します。本システムに搭載されているGPUはNVIDIA GB200(Grace-Blackwell)で、Compute Capabilityは10.0です。したがって指定する値はcc100になります。
-gpuオプションを省略した場合は、コンパイルを実行したノードのGPUに合わせたコードが生成されます。本システムではログインノードと計算ノードのいずれもGB200を搭載しているため、通常は省略してもcc100向けのコードが生成されます。
搭載GPUのCompute CapabilityはnvaccelinfoコマンドのDefault Target欄で確認できます。
Note
Compute CapabilityはGPU世代に依存する値です。本システム以外の環境向けにビルドする場合は、対象環境の値を-gpu=ccXXで明示的に指定してください。詳細はNVIDIA HPC SDKのドキュメントを参照してください。
MPIとCUDAの併用¶
MPIとCUDAを組み合わせることで、複数ノード・複数GPUを利用した大規模並列計算を実行できます。ラッパーコンパイラに対しても-cudaオプションを指定します。
C言語¶
C++¶
Fortran¶
Note
MPIプロセスとGPUを組み合わせて利用するアプリケーションでは、1 GPUに対して1 MPIプロセスを割り当てる構成がよく利用されます。
GPUライブラリの利用¶
NVHPCにはGPU向けの高性能ライブラリが統合されています。
| ライブラリ | 説明 |
|---|---|
| cuBLAS | 基本的な線形代数演算 |
| cuFFT | 高速フーリエ変換 |
| cuSPARSE | 疎行列演算 |
CUDAコンパイル時にライブラリをリンクする例は次のとおりです。
トラブルシューティング¶
nvcが見つからない¶
現象: nvc: command not found
原因: NVHPCのモジュールが読み込まれていません。
解決方法:
module loadで環境変数が設定されることを確認してください。
数学関数のリンクエラー¶
現象: undefined reference to 'pow'
原因: 数学ライブラリがリンクされていません。
解決方法:
-lmオプションで数学ライブラリを明示的にリンクしてください。
外部ライブラリのリンクエラー¶
現象: undefined reference to 'myfunction'
原因: 外部ライブラリがリンクされていない、またはライブラリの探索パスが指定されていません。
解決方法:
-Lオプションでライブラリディレクトリを、-lオプションでライブラリ名を指定してください。
環境変数設定¶
configureやmakeを使うビルドでは、使用するコンパイラやオプションを環境変数から取得します。あらかじめ設定しておくと、ビルドのたびにコンパイラを指定する必要がなくなります。
| 環境変数 | 用途 |
|---|---|
CC |
Cコンパイラ |
CXX |
C++ コンパイラ |
FC |
Fortranコンパイラ |
CFLAGS |
Cコンパイル時のオプション |
これらを.bashrcや.bash_profileに記述しておくと、新しいシェルセッションで自動的に設定されます。
NVHPCを使用する場合は、次のように設定します。