Gromacs with AWS ParallelCluster を体験

# はじめに

ParallelCluster で GROMACS を動かす方法を学習する英語のワークショップ [Gromacs with AWS ParallelCluster ](https://catalog.workshops.aws/gromacs-on-aws-parallelcluster/en-US)があります。ParallelCluster は AWS が提供する OSS で、AWS でハイパフォーマンスコンピューティング (HPC) クラスターをデプロイして管理

英語のワークショップを日本語に整理してまとめます。



# 概要

GROMACS を ParallelCluster で動かすワークショップです。Spack を利用して GROMACS をインストールして、複数 ComputeNode で稼働する内容を確認します。

この記事では、 hpc6a を利用するためリージョンは、オハイオを利用します。



# ParallelCluster UI を導入

ParallelCluster UI を導入します。ParallelCluster は CLI でも実行できますが、より視覚的にわかりやすく管理できる UI が便利なので、これで行います。

https://catalog.workshops.aws/gromacs-on-aws-parallelcluster/en-US/01-hpc-cluster/01-own-account/01-pcluster-manager

上記のリンクを参照して Deploy ParallelCluster UI ボタンを押します。

![image-20240203093050880.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/7492edbd-15b5-6adf-ceb7-ecebfce86cfa.png)



メールアドレスを指定します。テンポラリーパスワードが送付されます。

![image-20240201235601926.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ee5e24b3-020f-760a-c613-18a1ba014d05.png)



Ohio リージョンを指定していることを確認して Create stack を押します。だいたい 20 分待機すると、ParallelCluster の UI が立ち上がってきます。

![image-20240201235634205.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/bab56c67-e067-cf38-1fa2-6f547d174c74.png)



テンポラリーパスワードのお知らせがメールで送られます。

![image-20240202003956096.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/46796cfb-e386-c07b-38e6-2084312070b7.png)



ParallelCluster UI の URL を Output で確認可能

![image-20240202004057065.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/fc50137e-26de-bf5c-35a9-dca1db6c2509.png)



Cognito の画面が表示され、メールアドレスとパスワードを入れてログインします。

![image-20240202004143597.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b557398a-ffc3-b563-3c1d-30b202a3a45c.png)



ParallelCluster UI の画面が開かれます。

![image-20240202004242814.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/f962c56d-c6d1-217e-290c-4d632bc8f87b.png)



1 画面から複数の Region を選択可能です。us-east-2 を選択します。

![image-20240202004316901.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/139761c9-68d5-dbfa-a698-ca8cf6ac355b.png)



# ParallelCluster の作成

ParallelCluster UI 上で、クラスターを作成します。今回の手順で作成する AWS リソースを表形式で紹介します

| **Parameter**  | **Description**                                              |
| -------------- | ------------------------------------------------------------ |
| Shared Storage | 1.2 TB の容量を持つ FSx for Luster を作成し、/shared にマウントする |
| HeadNode       | HeadNode で c5a.2xlarge のインスタンスを作成する。8 vCPU, 16 GB メモリ。 |
| Compute Queue  | hpc6a.48xlarge のインスタンスを利用。96 物理コアと 384 GB メモリ。 |
| Spot Queue     | c6i.32xlarge のインスタンスを、スポットインスタンスとして指定。64 物理コアと 288 GB メモリを利用。重要なのはスポットインスタンスを指定するため、最大 90% の低価格なインスタンスを指定可能。 |



Note : インスタンスの違い

| **Instance Size** | **Cores** | **Memory (GiB)** | **EFA Network Bandwidth (Gbps)** | **Network Bandwidth (Gbps)\*** | **On-Demand Price** |
| :---------------: | :-------: | :--------------: | :------------------------------: | :----------------------------: | :-----------------: |
|  hpc6a.48xlarge   |    96     |       384        |               100                |               25               |        $2.88        |
|   c6i.32xlarge    |    64     |       288        |                50                |               25               |        $5.44        |



ワークショップの URL に添付されている Download Template でテンプレートファイル (gromacs-config-multi-queue.yaml) をダウンロードします。



Create cluster を with a template を選択します。

![image-20240202005154065.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/88881dd2-b9cb-ae2a-3d87-c7ac8272a4d3.png)





Cluster の名前や VPC や OS などを選択します。Slurm としての外部のデータベース (MySQL or MariaDB) を用意するとジョブの実行履歴を保存できるようになしますが、今回は設定しません。

![image-20240202005739135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b7aadc13-05b4-de68-c67b-ee3d2b415c35.png)



HeadNode に関する設定を入れます。Allowed IPs は、環境にあわせて変更してください。

![image-20240202010728900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/4c1a32dd-5344-a78e-b827-2cf54034da9b.png)



ComputeNode の Subnet を指定します。

- ※ Subnet の設定で、「Auto-assign public IPv4 address」が Yes でないと、Cluster の作成に失敗するので事前に確認する。
- ※ 指定した Subnet で hpc6a が利用できるか確認する。以下の実行例だと、オハイオリージョンでは、us-east-2b AZ のみ利用可能なことがわかる。

```
> aws ec2 describe-instance-type-offerings \
      --location-type "availability-zone" \
      --filters "Name=instance-type,Values=hpc6a.48xlarge" \
      --region us-east-2 \
      --query "InstanceTypeOfferings[*].[Location]" \
      --output text
us-east-2b
```



以下の画像の指定は Subnet の指定を間違っているので、のちの手順で起動が失敗しています。正しく `us-east-2b` の Subnet を選択しましょう。

![image-20240202011102759.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/8d68e4bd-7fcc-4256-4327-d7a131cda26c.png)



Shared Storage は、デフォルトのまま FSx for Luster で次に行きます。

![image-20240202011437417.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c5b9b4a5-c9a7-1922-62b7-515956bca137.png)



Create を押します。

![image-20240202011600562.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a001a9fa-7bea-eeed-26c4-832aded22dd5.png)



Cluster が作成される様子が確認できます。

![image-20240202011626520.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3a52d7b8-75c4-d9e8-62b9-d7aaafefbcef.png)



約 15 分後、ParallelCluster の作成が Complete になりました。

![image-20240202203350231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/d0007ccc-5406-bee5-9d6a-b28ab249aacc.png)



以下の代表的なリソースが作成されています。

- HeadNode
- FSx for Luster



# HeadNode 上で Spack のインストール

Spack は Linux などで利用できるパッケージマネージャーです。科学技術系で利用されるソフトウェアを簡単にインストールできます。Spack は特定の言語に関連付けられていません。 Python または R でソフトウェア スタックを構築し、C、C++、または Fortran で書かれたライブラリにリンクし、コンパイラやターゲット固有のマイクロアーキテクチャを簡単に交換できます。

HeadNode に SSH を行います。Shell のボタンで Systems Manager 経由でリモートアクセスが可能です。

![image-20240202205116612.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/12c615df-3f8c-ffcc-8e7f-665346d314ea.png)



個人的には別途 SSH を行う方がすきなので、SSH をします。

```
ssh ec2-user@....
```



mount の状況を確認すると、`/shared` に FSx for Luster がマウントされています。

```
[root@ip-10-6-13-4 ec2-user]# df -hT
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  3.9G     0  3.9G   0% /dev
tmpfs                   tmpfs     3.9G     0  3.9G   0% /dev/shm
tmpfs                   tmpfs     3.9G  1.2M  3.9G   1% /run
tmpfs                   tmpfs     3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/nvme0n1p1          xfs       200G   20G  181G  10% /
tmpfs                   tmpfs     784M   12K  784M   1% /run/user/42
tmpfs                   tmpfs     784M   40K  784M   1% /run/user/1000
10.6.3.36@tcp:/wtkr5bev lustre    1.2T  324M  1.2T   1% /shared
```



NFS で公開している領域もあります。

```
[root@ip-10-6-13-4 ec2-user]# exportfs
/home           10.6.0.0/16
/opt/parallelcluster/shared
                10.6.0.0/16
/opt/parallelcluster/shared_login_nodes
                10.6.0.0/16
/opt/intel      10.6.0.0/16
/opt/slurm      10.6.0.0/16
```



Spack をインストールするため、root で git clone を行います。この環境変数で指定している `/shared/spack` は、FSx for Luster の領域です。HeadNode 上でインストール作業を行いますが、インストール先は FSx for Luster となっており、ComputeNode からアクセスができるようになります。

Spack を git clone でダウンロードしています。

```
sudo su
export SPACK_ROOT=/shared/spack
mkdir -p $SPACK_ROOT
git clone -c feature.manyFiles=true https://github.com/spack/spack $SPACK_ROOT
```



root から ec2-user にもどります。

```
exit
```



Spack を利用するための bashrc の設定や、スクリプトの設定をします。

```
echo "export SPACK_ROOT=/shared/spack" >> $HOME/.bashrc
echo "source \$SPACK_ROOT/share/spack/setup-env.sh" >> $HOME/.bashrc
source $HOME/.bashrc
sudo chown -R $USER:$USER $SPACK_ROOT
```



Spack Binary Cache をビルドのスピードアップのために利用します。

```
spack mirror add binary_mirror  https://binaries.spack.io/releases/v0.18
spack buildcache keys --install --trust
```



# Intel Compiler のインストール

Spack を使って、Intel Compiler をインストールします。10 分くらいかかります。

```
spack install intel-oneapi-compilers@2022.0.2
```



compiler の一覧を表示します。

```
[ec2-user@ip-10-6-13-4 ~]$ spack compilers
==> Available compilers
-- gcc amzn2-x86_64 ---------------------------------------------
gcc@7.3.1
```



Spack に新しいコンパイラを認識させます

```
spack load intel-oneapi-compilers
spack compiler find
spack unload
```



再度、compiler の一覧を表示し、intel や oneapi が追加されているのがわかります。

```
[ec2-user@ip-10-6-13-4 ~]$ spack compilers
==> Available compilers
-- dpcpp amzn2-x86_64 -------------------------------------------
dpcpp@2022.0.0

-- gcc amzn2-x86_64 ---------------------------------------------
gcc@7.3.1

-- intel amzn2-x86_64 -------------------------------------------
intel@2021.5.0

-- oneapi amzn2-x86_64 ------------------------------------------
oneapi@2022.0.0
```



# GROMACS のインストール

以下のコマンドで最適化された GROMACS をインストールします。時間がかかるらしいので、

```
spack install -j 8 gromacs@2022.2 +blas +lapack %intel ^intel-oneapi-mpi
```



次の最適化しない (?) コマンドでインストールを行います。(といってもこれでも 45 分くらかかりました・・・)

```
spack install -v -j 8 gromacs@2022.2
```



spack find でインストールされているパッケージ一覧を確認できます。

```
[ec2-user@ip-10-6-13-4 ~]$ spack find
-- linux-amzn2-zen / gcc@7.3.1 ----------------------------------
autoconf@2.72                       cmake@3.27.9       gdbm@1.23                        krb5@1.20.1           libtool@2.4.7     numactl@2.0.14   perl@5.38.0    util-macros@1.19.3
automake@1.16.5                     curl@8.4.0         gettext@0.22.4                   libedit@3.1-20210216  libxcrypt@4.4.35  openblas@0.3.26  pigz@2.8       xz@5.4.1
berkeley-db@18.1.40                 diffutils@3.9      gmake@4.4.1                      libevent@2.1.12       libxml2@2.10.3    openmpi@5.0.1    pkgconf@1.9.5  zlib-ng@2.1.5
bison@3.8.2                         fftw@3.3.10        gromacs@2022.2                   libiconv@1.17         m4@1.4.19         openssh@9.5p1    pmix@5.0.1     zstd@1.5.5
bzip2@1.0.8                         findutils@4.9.0    hwloc@2.9.1                      libpciaccess@0.17     ncurses@6.4       openssl@3.1.3    readline@8.2
ca-certificates-mozilla@2023-05-30  gcc-runtime@7.3.1  intel-oneapi-compilers@2022.0.2  libsigsegv@2.14       nghttp2@1.57.0    patchelf@0.17.2  tar@1.34
==> 46 installed packages
```



spack コマンドを使って、gromacs をロードして実行できます。

ロードする前では、次のように GROMACS のコマンド実行がエラーになります。

```
$ gmx_mpi
bash: gmx_mpi: command not found
```



Spack コマンドでロードします。

```
spack load gromacs
```



コマンドが実行できます。バージョン 2022.2 が動いていることがわかります。

```
$ gmx_mpi
                    :-) GROMACS - gmx_mpi, 2022.2-spack (-:

Executable:   /shared/spack/opt/spack/linux-amzn2-zen/gcc-7.3.1/gromacs-2022.2-t7uvycqtxmmeevzv2v3bwan26exqhgin/bin/gmx_mpi
Data prefix:  /shared/spack/opt/spack/linux-amzn2-zen/gcc-7.3.1/gromacs-2022.2-t7uvycqtxmmeevzv2v3bwan26exqhgin
Working dir:  /home/ec2-user
Command line:
  gmx_mpi

```



# サンプルデータセットのダウンロード

`/shared` ディレクトリにサンプルデータセットをダウンロードします。このディレクトリは FSx for Luster なので、すべての ComputeNode から同一のデータセットにアクセスができるようになります。

```
mkdir -p /shared/input/gromacs
mkdir -p /shared/logs
mkdir -p /shared/jobs

cd /shared/input/gromacs
wget https://www.mpinat.mpg.de/benchMEM.zip
wget https://www.mpinat.mpg.de/benchPEP.zip
wget https://www.mpinat.mpg.de/benchPEP-h.zip
wget https://www.mpinat.mpg.de/benchRIB.zip

# unzip
unzip benchMEM.zip
unzip benchPEP.zip
unzip benchPEP-h.zip
unzip benchRIB.zip
```



# Run Multi-Node MPI

## Custer の詳細を確認する

クラスターの詳細を確認してきます。

200 万分子のシミュレーションを行うベンチマークの benchRIB を利用します。slurm の使い方は、以下の Document のサイトを参照してください。

https://slurm.schedmd.com/quickstart.html

sinfo を実行すると、現在稼動しているインスタンスと稼動していないインスタンスの両方が表示されます (これはキュー制限のようなもの)。初期状態では、全てのノードが idle~ の状態にあり、インスタンスが稼働していないことを意味しています。

ジョブを投入すると、いくつかのインスタンスが alloc の状態になります。ジョブが完了すると、インスタンスは数分間 (デフォルトのクールダウンは10分) idle% 状態になります。これは混乱しやすいので、下の表で単純化してみました：

| **State** | **Description**                                              |
| --------- | ------------------------------------------------------------ |
| `idle~`   | インスタンスは起動されていないが、ジョブが投入されると起動できる。 |
| `idle%`   | インスタンスは起動されており [ScaledownIdletime ](https://docs.aws.amazon.com/parallelcluster/latest/ug/Scheduling-v3.html#yaml-Scheduling-SlurmSettings-ScaledownIdletime) (default 10 mins) が経過されると自動シャットダウンされる。 |
| `mix`     | インスタンスが部分的に割り当てられている                     |
| `alloc`   | インスタンスが完全に割り当てられている                       |



sinfo で Node の状態を確認します。hpc6a と c6i の node 定義が見えます。100 node を新たに立ち上げられるようになっていますが、いまは node は存在していません。

```
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
hpc6a*       up   infinite    100  idle~ hpc6a-dy-compute-[1-100]
c6i          up   infinite    100  idle~ c6i-dy-spot-[1-100]
```



module は、環境変数（PATH、LD_LIBRARY_PATHなど）を動的に変更するために使用される、HPCではかなり標準的なツールです。

以下のコマンドで利用可能なモジュールの一覧を表示しています。 すべてのクラスタには intelmpi と openmpi がプリインストールされています。これらのMPIバージョンは高速インターコネクトEFAをサポートしてコンパイルされています。

```
$ module av

--------------------------------------------------------------------------- /usr/share/Modules/modulefiles ----------------------------------------------------------------------------
dot                         module-git                  modules                     openmpi/4.1.6
libfabric-aws/1.19.0amzn4.0 module-info                 null                        use.own

------------------------------------------------------------------------ /opt/intel/mpi/2021.9.0/modulefiles/ -------------------------------------------------------------------------
intelmpi
```



特定のモジュールをロードします。この場合、このコマンドは IntelMPI を環境にロードし、mpirun のパスをチェックします。

```
module load intelmpi
mpirun -V
```



実行例

```
$ module load intelmpi
Loading intelmpi version 2021.9.0

$ mpirun -V
Intel(R) MPI Library for Linux* OS, Version 2021.9 Build 20230307 (id: d82b3071db)
Copyright 2003-2023, Intel Corporation.
```



いくつかのボリュームはヘッドノードで共有され、起動時にコンピュートインスタンスにマウントされる。sharedと/homeは全ノードからアクセス可能です。

```
$ showmount -e localhost
Export list for localhost:
/opt/slurm                              10.6.0.0/16
/opt/intel                              10.6.0.0/16
/opt/parallelcluster/shared_login_nodes 10.6.0.0/16
/opt/parallelcluster/shared             10.6.0.0/16
/home                                   10.6.0.0/16
```



FSx for Luster をマウントしていることがわかります。1.2T の Size の '/shared' を確認できます。

```
$ df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 3.9G     0  3.9G   0% /dev
tmpfs                    3.9G   72K  3.9G   1% /dev/shm
tmpfs                    3.9G  1.2M  3.9G   1% /run
tmpfs                    3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/nvme0n1p1           200G   20G  181G  10% /
tmpfs                    784M   12K  784M   1% /run/user/42
tmpfs                    784M   40K  784M   1% /run/user/1000
10.6.3.36@tcp:/wtkr5bev  1.2T  7.6G  1.2T   1% /shared
```



## Submit Job

シミュレーションジョブを実行します。`gromacs.sbatch` のファイルを作成します。

- `#SBATCH --job-name=gromacs-threadmpi` : ジョブの識別名を指定
- `#SBATCH --exclusive` : このジョブが実行される時、割り当てられたノードを他のジョブと共有しないようにします。ジョブがノードのリソースを独占的に使用します。
- `#SBATCH --output=/shared/logs/%x_%j.out` : ジョブの標準出力と標準エラー出力を指定したパスにリダイレクトします。`%x`はジョブ名、`%j`はジョブIDに展開されます。
- `#SBATCH -N 2` : ジョブを 2 つの ComputeNode に割り振ります
- `#SBATCH -n 96` : 層タスク数 (MPI プロセス数) を 96 に指定します
- `NTOMP=1` : OpenMPスレッドの数を1に設定します。これは、各MPIプロセスが使用するスレッドの数を指します。

```
cd /home/ec2-user

cat <<'EOF' > gromacs.sbatch
#!/bin/bash
#SBATCH --job-name=gromacs-threadmpi
#SBATCH --exclusive
#SBATCH --output=/shared/logs/%x_%j.out
#SBATCH -N 2
#SBATCH -n 96
NTOMP=1

# ジョブの実行に必要なディレクトリを作成し、そこに移動します。${SLURM_JOBID}はSLURMによって割り当てられたジョブIDです。
mkdir -p /shared/jobs/${SLURM_JOBID}
cd /shared/jobs/${SLURM_JOBID}

# Spackパッケージマネージャを使用してGROMACSをロードし、OpenMPIモジュールをロードします。これにより、GROMACSとMPIが利用可能になります。
spack load gromacs
module load openmpi

# mpirunを使用して、指定されたタスク数（SLURM_NTASKSで設定）でGROMACSのmdrunコマンドを実行します。
# -ntompオプションで各MPIプロセスのOpenMPスレッド数を設定し、-sオプションで入力ファイルを指定します。
set -x
time mpirun -np ${SLURM_NTASKS} gmx_mpi mdrun -ntomp ${NTOMP} -s /shared/input/gromacs/benchRIB.tpr -resethway
EOF
```



sbatch コマンドでジョブを実行します。

```
sbatch gromacs.sbatch
```



実行例 : ジョブ番号 1 で実行されました

```
$ sbatch gromacs.sbatch
Submitted batch job 1
```



## Monitor Job

以下のコマンドを実行すると、

```
squeue -i 1
```



1 秒ごとに Queue の状況を確認できます。ST が CF となっており、これは インスタンスが立ち上がるのを待機している状態です。

```
Sat Feb 03 00:38:35 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user CF       0:28      2 hpc6a-dy-compute-[1-2]

Sat Feb 03 00:38:36 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user CF       0:29      2 hpc6a-dy-compute-[1-2]

Sat Feb 03 00:38:37 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user CF       0:30      2 hpc6a-dy-compute-[1-2]
```



sinfo コマンドで、Node の状況も確認できます。2 台の Node が新たに立ち上がろうとしています。

```
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
hpc6a*       up   infinite      2 alloc# hpc6a-dy-compute-[1-2]
hpc6a*       up   infinite     98  idle~ hpc6a-dy-compute-[3-100]
c6i          up   infinite    100  idle~ c6i-dy-spot-[1-100]
```



EC2 のマネジメントコンソール画面でも、新たに `hpc6a.46xlarge` が立ち上がってくる様子が確認できます。

![image-20240203094128386.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/34f9bce5-7c16-c279-4a46-3f83cc8214df.png)



一定時間後、Running となっています。

```
Sat Feb 03 00:42:59 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user  R       2:22      2 hpc6a-dy-compute-[1-2]

Sat Feb 03 00:43:00 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user  R       2:23      2 hpc6a-dy-compute-[1-2]

Sat Feb 03 00:43:01 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 1     hpc6a gromacs- ec2-user  R       2:24      2 hpc6a-dy-compute-[1-2]
```



次のコマンドで SSH もできます。

```
$ ssh hpc6a-dy-compute-1
```



FSx for Luster を `/shared` にマウントしている様子が確認できます。同様に、HeadNode の NFS 領域もマウントしています。

```
$ df -hT
Filesystem                              Type      Size  Used Avail Use% Mounted on
devtmpfs                                devtmpfs  185G     0  185G   0% /dev
tmpfs                                   tmpfs     185G   56M  185G   1% /dev/shm
tmpfs                                   tmpfs     185G  1.2M  185G   1% /run
tmpfs                                   tmpfs     185G     0  185G   0% /sys/fs/cgroup
/dev/nvme0n1p1                          xfs        40G   20G   21G  50% /
10.6.29.198:/opt/parallelcluster/shared nfs4      200G   20G  181G  10% /opt/parallelcluster/shared
10.6.29.198:/home                       nfs4      200G   20G  181G  10% /home
10.6.29.198:/opt/intel                  nfs4      200G   20G  181G  10% /opt/intel
10.6.16.198@tcp:/5urb7bev               lustre    1.2T  7.7G  1.2T   1% /shared
10.6.29.198:/opt/slurm                  nfs4      200G   20G  181G  10% /opt/slurm
tmpfs                                   tmpfs      37G     0   37G   0% /run/user/1000
```



負荷状況を確認するため htop をインストールし実行します。

```
sudo yum install -y htop && htop
```



このような結果が確認できます。

![image-20240203095050150.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/04028194-f55f-43ec-caae-4ac7dfa3ff71.png)



HeadNode に戻ります。

```
exit
```



GROMACS コマンドを実行したときの標準出力のログは、以下のディレクトリに出力されています。

```
/shared/logs/gromacs-threadmpi_1.out
```



内容を確認します。この出力はGROMACSシミュレーションのパフォーマンス状況などを示しています。主なポイントは以下の通りのようです。

- 96個のMPIプロセスを用いてシミュレーションが実行されました。
- 1つのOpenMPスレッドが各MPIプロセスに割り当てられました。
- シミュレーションは10000ステップ、40ピコ秒実行されました。
- 平均の負荷不均衡は2.8%でした。
- 負荷不均衡による待ち時間はシミュレーション時間の2.1%でした。
- 1ステップ当たりの計算時間はコア時間で17945.160秒、ウォールクロック時間で186.929秒でした。
- シミュレーションのパフォーマンスは9.246 ns/dayでした。

```
$ cat /shared/logs/gromacs-threadmpi_1.out
+ mpirun -np 96 gmx_mpi mdrun -ntomp 1 -s /shared/input/gromacs/benchRIB.tpr -resethway
                   :-) GROMACS - gmx mdrun, 2022.2-spack (-:

Executable:   /shared/spack/opt/spack/linux-amzn2-zen/gcc-7.3.1/gromacs-2022.2-t7uvycqtxmmeevzv2v3bwan26exqhgin/bin/gmx_mpi
Data prefix:  /shared/spack/opt/spack/linux-amzn2-zen/gcc-7.3.1/gromacs-2022.2-t7uvycqtxmmeevzv2v3bwan26exqhgin
Working dir:  /shared/jobs/1
Command line:
  gmx_mpi mdrun -ntomp 1 -s /shared/input/gromacs/benchRIB.tpr -resethway

Highest SIMD level supported by all nodes in run: AVX2_256
SIMD instructions selected at compile time:       AVX2_128
Compiled SIMD newer than supported; program might crash.
Reading file /shared/input/gromacs/benchRIB.tpr, VERSION 4.6.2-dev-20130529-36d170c (single precision)
Note: file tpx version 83, software tpx version 127
Changing nstlist from 25 to 80, rlist from 1 to 1.096

Using 96 MPI processes

Non-default thread affinity set, disabling internal thread affinity

Using 1 OpenMP thread per MPI process

starting mdrun 'Protein'
10000 steps,     40.0 ps.

step 5000: resetting all time and cycle counters

Writing final coordinates.


Dynamic load balancing report:
 DLB was turned on during the run due to measured imbalance.
 Average load imbalance: 2.8%.
 The balanceable part of the MD step is 76%, load imbalance is computed from this.
 Part of the total run time spent waiting due to load imbalance: 2.1%.
 Steps where the load balancing was limited by -rdd, -rcon and/or -dds: X 0 % Y 0 % Z 0 %
 Average PME mesh/force load: 0.872
 Part of the total run time spent waiting due to PP/PME imbalance: 2.6 %


               Core t (s)   Wall t (s)        (%)
       Time:    17945.160      186.929     9600.0
                 (ns/day)    (hour/ns)
Performance:        9.246        2.596

GROMACS reminds you: "If it weren't for C, we'd all be programming in BASI and OBOL." (Anonymous)


real    6m26.474s
user    609m28.690s
sys     4m7.930s
```



実際のシミュレーション結果についてです。今回のスクリプトでは、以下の指定があります。

GROMACS では、実行コマンドを実行したカレントディレクトリに出力されています。

```
# ジョブの実行に必要なディレクトリを作成し、そこに移動します。${SLURM_JOBID}はSLURMによって割り当てられたジョブIDです。
mkdir -p /shared/jobs/${SLURM_JOBID}
cd /shared/jobs/${SLURM_JOBID}
```



今回は jobid が 1 なので、以下のディレクトリにシミュレーション結果が出力されています。

```
$ ls -la /shared/jobs/1
total 137768
drwxrwxr-x 2 ec2-user ec2-user     33280 Feb  3 00:47 .
drwxrwxr-x 3 ec2-user ec2-user     33280 Feb  3 00:40 ..
-rw-rw-r-- 1 ec2-user ec2-user 147412535 Feb  3 00:47 confout.gro
-rw-rw-r-- 1 ec2-user ec2-user     13832 Feb  3 00:47 ener.edr
-rw-rw-r-- 1 ec2-user ec2-user     29663 Feb  3 00:47 md.log
-rw-rw-r-- 1 ec2-user ec2-user  51275984 Feb  3 00:47 state.cpt
```



md.log には難しい内容が出力されています。一部抜粋しつつ、以下のような意味の内容らしいですが、なにもわかりません。

- ポテンシャルエネルギー: -3.80x10^7 kJ/mol の範囲
- 運動エネルギー: 約5.07x10^6 kJ/mol
- 全エネルギー: -3.30x10^7 kJ/mol の範囲
- 温度: 300 K前後
- 圧力: 作用する圧力に関する詳細なデータが提供されていますが、平均圧力は-16.08 bar前後

```
<省略>
Energy conservation over simulation part #1 of length 40 ps, time 0 to 40 ps
  Conserved energy drift: -8.07e-04 kJ/mol/ps per atom


        <======  ###############  ==>
        <====  A V E R A G E S  ====>
        <==  ###############  ======>

        Statistics over 10001 steps using 101 frames

   Energies (kJ/mol)
  Connect Bonds          Angle    Proper Dih. Ryckaert-Bell.          LJ-14
    0.00000e+00    3.47717e+05    1.19011e+04    7.61049e+05    2.87457e+05
     Coulomb-14        LJ (SR)   Coulomb (SR)   Coul. recip.      Potential
   -1.18734e+06    5.15936e+06   -4.37575e+07    3.53117e+05   -3.80242e+07
    Kinetic En.   Total Energy  Conserved En.    Temperature Pressure (bar)
    5.06755e+06   -3.29567e+07   -3.25538e+07    3.00145e+02   -1.60770e+01
   Constr. rmsd
    0.00000e+00
<省略>
```



# Run on SPOT Instances

hpc6a をサポートしていないリージョンといったように、hpc6a インスタンスを使用できない場合は、Amazon EC2 Spot Instances インスタンスを使用するオプションも検討できます。このインスタンスでは、GROMACS シミュレーションをコスト効率よく実行でき、オンデマンドの価格から最大 90% の割引が適用されるため、HPC インスタンスと同様の価格帯で利用できます。スポットインスタンスのトレードオフは、2 分前の警告はありつつ、いつでも仮想マシンが停止される点にあります。

複雑なシミュレーションの実行時間は数時間から数日に及ぶこともあり、シミュレーションの実行時間が長くなればなるほど、中断リスクの可能性が高まるため、これが問題になる場合があります。そのため、シミュレーションの進行状況を維持しながら実行することが重要になります。シミュレーションのチェックポイントは、これを実現する方法です。GROMACSネイティブのチェックポイントとスポットインスタンスを組み合わせることで、シミュレーションを再開することができ、中断が発生しても進捗を最小限に抑えることができます。

このセクションでは、GromacsのチェックポイントとSpot pricing、Slurmのスケジューリングを組み合わせることで、Gromacsシミュレーションを実行するための費用対効果の高いソリューションを作成していきます



## Configure Checkpointing

Amazon EC2のスポットインスタンスで、シミュレーションを中断が発生した場合、途中から再開する仕組みがあります。中断時の作業ロスを最小限に抑えるには、GROMACSでチェックポイントを行い、シミュレーションの実行状態を保存します。一度保存したら、中断したインスタンスを置き換えてSlurmジョブを再投入し、シミュレーションを終了します。

GROMACSは、ユーザーが定義した間隔でシミュレーションのチェックポイントをサポートします。GROMACSの主要な計算化学エンジンであるMdrunのコマンドラインフラグを使ってチェックポイントを設定可能です。次の表は、選択したフラグを説明するものです。

|       Flag and value        |                 Explanation                  |
| :-------------------------: | :------------------------------------------: |
|          `- cpt 1`          |   ユーザー定義のチェックポイント間隔 (分)    |
|    `- cpi spot-cpu.cpt`     | 保存状態を読み込むためのユーザー定義ファイル |
| `- cpo spot-cpu-output.cpt` |   状態を書き込むためのユーザー定義ファイル   |



cpt フラグをオンにすると、ノードの中断時に GROMACS シミュレーションを継続するために必要なデータを保存します。インスタンスが中断された場合、AWS ParallelClusterは自動的に新しいインスタンスをデプロイし、新しいインスタンスにSlurmジョブを再キューします。

デフォルトのチェックポイント時間は15分毎です。



## Submit Job

HeadNode で `gromacs-spot.sbatch` ファイルを作成します。

- `--partition=spot` : これは、ジョブがスポット・パーティション（キュー）に投入され、スポット・インスタンスで実行されることを保証します。
- `-cpt 1 -cpi spot-cpu-${SLURM_JOBID}.cpt -cpo spot-cpu-${SLURM_JOBID}.cpt` : この指定で、チェックポイントを 1 分ごとに書き出す設定を入れています。

```
cd /home/ec2-user

cat <<'EOF' > gromacs-spot.sbatch
#!/bin/bash
#SBATCH --job-name=spot-gromacs-demo
#SBATCH --exclusive
#SBATCH --output=/shared/logs/%x_%j.out
#SBATCH --partition=spot
NTOMP=2

mkdir -p /shared/jobs/${SLURM_JOBID}
cd /shared/jobs/${SLURM_JOBID}

echo ">>> loading gromacs module "
spack load gromacs
module load intelmpi 

set -x
mpirun gmx_mpi mdrun -nsteps 500000 -pme cpu -ntomp ${NTOMP} -s /shared/input/gromacs/benchMEM.tpr -resethway -cpt 1 -cpi spot-cpu-${SLURM_JOBID}.cpt -cpo spot-cpu-${SLURM_JOBID}.cpt -e spot-cpu-${SLURM_JOBID}.edr -g spot-cpu-${SLURM_JOBID}.log

EOF
```



sinfo コマンドで、SpotInstance 用の PARTITION 名である `c6i` を確認します。

```
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
hpc6a*       up   infinite    100  idle~ hpc6a-dy-compute-[1-100]
c6i          up   infinite    100  idle% c6i-dy-spot-[1-100]
```



パーティション `c6i` を指定して、ジョブを実行します。

```
sbatch -p c6i gromacs-spot.sbatch
```



実行例

```
$ sbatch -p c6i gromacs-spot.sbatch
Submitted batch job 3
```



queue の確認

```
$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 3       c6i spot-gro ec2-user CF       0:10      1 c6i-dy-spot-1
```



sinfo

```
$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
hpc6a*       up   infinite      1  idle% hpc6a-dy-compute-1
hpc6a*       up   infinite     98  idle~ hpc6a-dy-compute-[2-5,7-100]
hpc6a*       up   infinite      1   idle hpc6a-dy-compute-6
c6i          up   infinite      1  down# c6i-dy-spot-1
c6i          up   infinite     99  idle~ c6i-dy-spot-[2-100]
```



## デバッグ : Spot Instance が立ち上がらないエラー

立ち上がらない・・・容量エラーのように見えます。

```
$ sinfo -R
REASON               USER      TIMESTAMP           NODELIST
(Code:InsufficientIn root      2024-02-03T01:57:14 c6i-dy-spot-1
```



ログ

```
less /var/log/parallelcluster/slurm_resume.log
```



対象の IAM Role が権限がないように見える。

```
2024-02-03 01:57:10,035 - 18082 - [botocore.credentials:load] - INFO - Found credentials from IAM Role: gromacs-workshop-RoleHeadNode-aZVxChHBAO57
```

```
2024-02-03 01:57:14,889 - 18082 - [slurm_plugin.fleet_manager:_launch_instances] - ERROR - JobID 4 - Error in CreateFleet request (10f11dc8-7cbc-4695-995a-53006a46163d): AuthFailure.ServiceLinkedRoleCreationNotPermitted - The provided credentials do not have permission to create the service-linked role for EC2 Spot Instances.
```



こっちのログもきになる

```
less /var/log/parallelcluster/clustermgtd
```

```
2024-02-03 02:04:07,242 - [slurm_plugin.clustermgtd:_reset_timeout_expired_compute_resources] - INFO - The following compute resources are in down state due to insufficient capacity: {'c6i': {'spot': ComputeResourceFailureEvent(timestamp=datetime.datetime(2024, 2, 3, 1, 58, 1, 448839, tzinfo=datetime.timezone.utc), error_code='InsufficientInstanceCapacity')}}, compute resources will be reset after insufficient capacity timeout (600.0 seconds) expired
```



以下のドキュメントを確認すると、以下の Role を作成する必要がありました。

https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/troubleshooting-v3-scaling-issues.html

Role の作成

```
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com
```



実行例

```
> aws iam create-service-linked-role --aws-service-name spot.amazonaws.com
{
    "Role": {
        "Path": "/aws-service-role/spot.amazonaws.com/",
        "RoleName": "AWSServiceRoleForEC2Spot",
        "RoleId": "AROAVNVNXMHCKHV6DG7TC",
        "Arn": "arn:aws:iam::xxxxxxxxxxx:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot",
        "CreateDate": "2024-02-03T02:18:21+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "sts:AssumeRole"
                    ],
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "spot.amazonaws.com"
                        ]
                    }
                }
            ]
        }
    }
}
```







## 再度 Submit Job

```
cd /home/ec2-user
sbatch -p c6i gromacs-spot.sbatch
```



これで対象のスポットインスタンスが立ち上がるようになりました。

![image-20240203112613215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/06091419-edcd-dd99-ae44-54bcbf82f140.png)



一定時間後、実行されている様子が確認できます。

```
$ ls -la /shared/logs/spot-gromacs-demo_8.out
-rw-rw-r-- 1 ec2-user ec2-user 4915 Feb  3 02:27 /shared/logs/spot-gromacs-demo_8.out
```



## Simulate SPOT Interruption

このセクションでは、スポットの中断をシミュレートする方法を確認します。これは、チェックポイントと再起動の機能が正しく動作することをテストするのに役立ちます。この例ではEC2 Spotコンソールを使用しますが、Fault Injection Simulator（FIS）を使用しても同じ結果です。

再度 Job を Submit します。

```
cd /home/ec2-user
sbatch -p c6i gromacs-spot.sbatch
```



queue が実行されています。

```
$ squeue
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                 9       c6i spot-gro ec2-user CF       0:16      1 c6i-dy-spot-1
```



実行状態

```
Sat Feb 03 03:06:34 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user  R       0:25      1 c6i-dy-spot-1
```





EC2 Spot の画面を開き、対象のインスタンス選択したあと、Initiate interruption を選択して中断させます。

![image-20240203114924382.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/6659b398-fe49-cd94-af41-62eea76df42f.png)



実行

![image-20240203114953222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/364b09b6-0a8d-1c6f-9b72-4fe1d6ee6cb9.png)



R から CG

```
Sat Feb 03 03:10:08 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user  R       3:59      1 c6i-dy-spot-1

Sat Feb 03 03:10:09 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user  R       4:00      1 c6i-dy-spot-1

Sat Feb 03 03:10:10 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user CG       0:00      1 c6i-dy-spot-1

Sat Feb 03 03:10:11 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user CG       0:00      1 c6i-dy-spot-1
```



対象のインスタンスがシャットダウンされました。

![image-20240203121110449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/647398f0-4cfd-996b-84c3-1fdcf437763b.png)



この手順では、新しいインスタンスが立ち上がるわけではありませんでした。

```
Sat Feb 03 03:19:16 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user PD       0:00      1 (BadConstraints)
```



新しいインスタンスを立ち上げるために、以下の内容に従って、コマンドを実行してみます。

https://github.com/aws/aws-parallelcluster/issues/5731

```
scontrol update jobid=10 NumNodes=1-1
```



すると新たな ComputeNode が立ち上がりました。

![image-20240203122032941.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/fe867d54-0ce0-ae81-909a-9c2c814a6454.png)



Status が Running に代わり、ジョブが再開されます。

```
Sat Feb 03 03:22:38 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user CF       2:49      1 c6i-dy-spot-1

Sat Feb 03 03:22:39 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user CF       2:50      1 c6i-dy-spot-1

Sat Feb 03 03:22:40 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user  R       0:01      1 c6i-dy-spot-1

Sat Feb 03 03:22:41 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
                10       c6i spot-gro ec2-user  R       0:02      1 c6i-dy-spot-1

Sat Feb 03 03:22:42 2024
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
```



ジョブが完了しました

```
[ec2-user@ip-10-6-29-198 10]$ ls -la /shared/jobs/10/
total 87896
drwxrwxr-x 2 ec2-user ec2-user   41472 Feb  3 03:09 .
drwxrwxr-x 8 ec2-user ec2-user   33280 Feb  3 03:06 ..
-rw-rw-r-- 1 ec2-user ec2-user 1963788 Feb  3 03:09 spot-cpu-10.cpt
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 spot-cpu-10.edr
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.1#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.10#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.11#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.12#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.13#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.14#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.15#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.16#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.17#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.18#
-rw-rw-r-- 1 ec2-user ec2-user    1056 Feb  3 03:07 #spot-cpu-10.edr.19#
```



# 検証を通じてわかったこと

- Slurm の sbatch といったコマンドに関する Document は、AWS ではなく以下のサイトで参照する。
  - https://slurm.schedmd.com/quickstart.html
- デフォルトでは、ジョブを実行したあとに ComputeNode がシャットダウンされるまで、10 分間の待機時間が発生する。これは、設定変更で変更が可能。1 に指定すると、すぐに ComputeNode がシャットダウンされる。再利用性が低くなるデメリットもある。
  - https://docs.aws.amazon.com/parallelcluster/latest/ug/Scheduling-v3.html#yaml-Scheduling-SlurmSettings-ScaledownIdletime
- ParallelCluster に複数のインスタンスタイプを指定可能
- スポットインスタンスとオンデマンドインスタンスを、それぞれの Queue として定義可能
- FSx for Luster は必須ではない。多くの ComputeNode を立ち上げるときに高性能なパフォーマンスを求める場合に利用可能。
- FSx for Luster や HeadNode の NFS 公開領域に GROMACS をインストールすることで、すべての ComputeNode から GROMASC を実行可能になる。
- HeadNode は 1 台構成となる。可用性を気にする場合は、複数の ParallelCluster を立ち上げる方法が考えられる。
- ベストプラクティス
  - https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/best-practices-v3.html
- ジョブの実行履歴の保存に関して
  - デフォルトの ParallelCluster が Slurm のジョブ実行履歴を管理しません。あとから「このジョブどれくらい時間かかったんだっけ？」を確認したいと思っても、確認ができないのがデフォルトの構成です。
  - 考えられる 2 つの方法があります。
  - 1 : ParallellCluster の構築で Slurm アカウンティングを有効にする方法
    - MySQL や MariaDB のサーバーを構成して、データベースにジョブ実行履歴を保存する方法。RDS などの場合はある程度の費用が発生する。
    - https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/tutorials_07_slurm-accounting-v3.html
    - https://dev.classmethod.jp/articles/exploring-database-services-for-slurm-accounting/
  - 2 : 簡易的に HeadNode のジョブ実行時に、ジョブの実行状態を監視して時間を計測するような Shell Script を仕込む
    - HeadNode ないにファイルを出力する形になり、あとから統計的に確認などはできないが、まず費用が掛からないリーズナブルな方法。軽量な Shell Script を作る必要はあるのが、たまにきず。