コンテンツにスキップ

プログラムのコンパイル方法

概要

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

バージョン確認:

gcc --version
g++ --version
gfortran --version

NVIDIA HPC SDK(NVHPC)

NVHPCはNVIDIAが提供する高性能計算向けのコンパイラおよび関連ツール群です。OpenACCやCUDAによるGPUプログラミング、およびGPUライブラリを利用したアプリケーション開発に使用します。

利用できるコンパイラ:

言語 コマンド
C nvc
C++ nvc++
Fortran nvfortran

バージョン確認:

module load nvhpc
nvc --version
nvc++ --version
nvfortran --version

コンパイル

コンパイルとは、ソースコードから実行可能なプログラムを生成する処理です。基本的な開発手順は次のとおりです。

  1. ソースコードを作成する
  2. コンパイラを実行する
  3. エラーや警告を確認する
  4. 実行ファイルを生成する
  5. 実行結果を確認する

GCCによるコンパイル

C言語

gcc sample.c -o sample

C++

C++ ではコンパイラやライブラリのバージョンによりデフォルトの言語規格が異なる場合があります。移植性を高めるため、-stdオプションで使用する言語規格を明示することを推奨します。

g++ -std=c++17 sample.cpp -o sample

Fortran

C++ と同様に、-stdオプションで使用する言語規格を明示することを推奨します。

gfortran -std=f2008 sample.f90 -o sample

NVHPCによるコンパイル

NVHPCを使用するには、事前にmodule load nvhpcコマンドで環境を設定してください。

C言語

module load nvhpc
nvc sample.c -o sample

C++

module load nvhpc
nvc++ sample.cpp -o sample

Fortran

module load nvhpc
nvfortran sample.f90 -o sample

基本的なコンパイルオプション

出力ファイルの指定

-oオプションで出力ファイル名を指定します。-oオプションを省略した場合、実行ファイル名はa.outになります。

gcc sample.c -o myprogram

インクルードパスの指定

利用するライブラリのヘッダファイルが標準パス外に配置されている場合は、-Iオプションで検索先ディレクトリを追加してください。

gcc -I/path/to/include1 -I/path/to/include2 sample.c -o sample

ライブラリのリンク

コンパイル処理とリンク処理は別工程です。コンパイルが成功しても、対応するライブラリがリンクされていない場合はundefined referenceエラーが発生します。外部ライブラリをリンクする場合、-Lオプションでライブラリディレクトリを、-lオプションでライブラリ名を指定します。

gcc sample.c -L/usr/local/lib -lmylib -o sample

最適化オプション

コンパイラの最適化レベルを指定することで、実行速度を改善できます。最適化オプションは、コンパイラがプログラムの実行効率を改善するために行う変換処理を制御します。

オプション 説明 用途
-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で指定します。

gcc -fopenmp sample.c -o sample
export OMP_NUM_THREADS=4
./sample

NVHPC

コンパイル時に-mpオプションを使用します。実行時に使用するスレッド数を環境変数OMP_NUM_THREADSで指定します。

module load nvhpc
nvc -mp sample.c -o sample
export OMP_NUM_THREADS=4
./sample

MPIによる分散メモリ並列化

MPIは複数の計算ノード間でのプロセス間通信を実現します。module load nvhpcにより、NVHPCに同梱されたOpen MPIベースのMPI環境が利用可能になります。

MPIプログラムのコンパイルには、gccg++gfortrannvcnvc++nvfortranを直接使うのではなく、MPI用のラッパーコンパイラであるmpiccmpic++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オプションで確認できます。

mpicc --show
mpic++ --show
mpifort --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環境の確認

module load nvhpc
nvcc --version
nvidia-smi
nvidia-smi -L
nvidia-smi -q
コマンド 説明
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言語

module load nvhpc
nvc -acc sample.c -o sample

C++

module load nvhpc
nvc++ -acc sample.cpp -o sample

Fortran

module load nvhpc
nvfortran -acc sample.f90 -o sample

-Minfo=accelオプションにより、OpenACCコンパイル時にGPU化された処理内容を確認できます。

nvc -acc -Minfo=accel sample.c -o sample

出力例:

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言語

module load nvhpc
mpicc -acc sample.c -o sample
mpirun -np 4 ./sample

C++

module load nvhpc
mpic++ -acc sample.cpp -o sample
mpirun -np 4 ./sample

Fortran

module load nvhpc
mpifort -acc sample.f90 -o sample
mpirun -np 4 ./sample

Note

MPIプロセスとGPUを組み合わせて利用するアプリケーションでは、1 GPUに対して1 MPIプロセスを割り当てる構成がよく利用されます。

CUDAによるコンパイル

CUDA関連機能を利用する場合は、CUDAコンパイラおよびライブラリの利用が必要です。NVHPCでは-cudaオプションを指定することでCUDA機能を有効化できます。

C言語

module load nvhpc
nvc -cuda sample.c -o sample

C++

module load nvhpc
nvc++ -cuda sample.cpp -o sample

Fortran

module load nvhpc
nvfortran -cuda sample.f90 -o sample

Compute Capabilityの指定

生成するGPUコードの世代は-gpu=ccXXオプションで指定します。本システムに搭載されているGPUはNVIDIA GB200(Grace-Blackwell)で、Compute Capabilityは10.0です。したがって指定する値はcc100になります。

nvc -cuda -gpu=cc100 sample.c -o sample

-gpuオプションを省略した場合は、コンパイルを実行したノードのGPUに合わせたコードが生成されます。本システムではログインノードと計算ノードのいずれもGB200を搭載しているため、通常は省略してもcc100向けのコードが生成されます。

搭載GPUのCompute CapabilityはnvaccelinfoコマンドのDefault Target欄で確認できます。

module load nvhpc
nvaccelinfo | grep "Default Target"

Note

Compute CapabilityはGPU世代に依存する値です。本システム以外の環境向けにビルドする場合は、対象環境の値を-gpu=ccXXで明示的に指定してください。詳細はNVIDIA HPC SDKのドキュメントを参照してください。

MPIとCUDAの併用

MPIとCUDAを組み合わせることで、複数ノード・複数GPUを利用した大規模並列計算を実行できます。ラッパーコンパイラに対しても-cudaオプションを指定します。

C言語

module load nvhpc
mpicc -cuda sample.c -o sample
mpirun -np 4 ./sample

C++

module load nvhpc
mpic++ -cuda sample.cpp -o sample
mpirun -np 4 ./sample

Fortran

module load nvhpc
mpifort -cuda sample.f90 -o sample
mpirun -np 4 ./sample

Note

MPIプロセスとGPUを組み合わせて利用するアプリケーションでは、1 GPUに対して1 MPIプロセスを割り当てる構成がよく利用されます。

GPUライブラリの利用

NVHPCにはGPU向けの高性能ライブラリが統合されています。

ライブラリ 説明
cuBLAS 基本的な線形代数演算
cuFFT 高速フーリエ変換
cuSPARSE 疎行列演算

CUDAコンパイル時にライブラリをリンクする例は次のとおりです。

module load nvhpc
nvc -cuda -lcublas sample.c -o sample

トラブルシューティング

nvcが見つからない

現象: nvc: command not found

原因: NVHPCのモジュールが読み込まれていません。

解決方法:

module load nvhpc
which nvc

module loadで環境変数が設定されることを確認してください。

数学関数のリンクエラー

現象: undefined reference to 'pow'

原因: 数学ライブラリがリンクされていません。

解決方法:

gcc sample.c -lm -o sample

-lmオプションで数学ライブラリを明示的にリンクしてください。

外部ライブラリのリンクエラー

現象: undefined reference to 'myfunction'

原因: 外部ライブラリがリンクされていない、またはライブラリの探索パスが指定されていません。

解決方法:

gcc sample.c -L/usr/local/lib -lmylib -o sample

-Lオプションでライブラリディレクトリを、-lオプションでライブラリ名を指定してください。

環境変数設定

configuremakeを使うビルドでは、使用するコンパイラやオプションを環境変数から取得します。あらかじめ設定しておくと、ビルドのたびにコンパイラを指定する必要がなくなります。

環境変数 用途
CC Cコンパイラ
CXX C++ コンパイラ
FC Fortranコンパイラ
CFLAGS Cコンパイル時のオプション

これらを.bashrc.bash_profileに記述しておくと、新しいシェルセッションで自動的に設定されます。

# ~/.bashrc に追記
export CC=gcc
export CXX=g++
export FC=gfortran
export CFLAGS="-O2 -Wall"

NVHPCを使用する場合は、次のように設定します。

module load nvhpc
export CC=nvc
export CXX=nvc++
export FC=nvfortran
export CFLAGS="-O2"