Running HPL with Volcano on Kubernetes

Author Avatar

SiriusKoan

  ·  4 min read

文中提到的檔案皆放在 SiriusKoan/hpc-benchmarks-container

What’s HPL #

HPL (High Performance Linpack) 是一個利用求解多元線性方程組來評估超級電腦效能的程式,主要被用來測試全球的超級電腦的速度 (TOP500)。

超級電腦是由多台小電腦所組成的,程式可以使用 MPI (Message Passing Interface) 來在多台機器之間溝通。HPL 便支援 MPI,所以可以作為評測的工具。

HPL 的設定檔是 HPL.dat,範例如下:

HPLinpack benchmark input file
Innovative Computing Laboratory, University of Tennessee
HPL.out      output file name (if any)
6            device out (6=stdout,7=stderr,file)
4            # of problems sizes (N)
29 30 34 35  Ns
4            # of NBs
1 2 3 4      NBs
0            PMAP process mapping (0=Row-,1=Column-major)
1            # of process grids (P x Q)
4            Ps
4            Qs
16.0         threshold
3            # of panel fact
0 1 2        PFACTs (0=left, 1=Crout, 2=Right)
2            # of recursive stopping criterium
2 4          NBMINs (>= 1)
1            # of panels in recursion
2            NDIVs
3            # of recursive panel fact.
0 1 2        RFACTs (0=left, 1=Crout, 2=Right)
1            # of broadcast
0            BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM)
1            # of lookahead depth
0            DEPTHs (>=0)
2            SWAP (0=bin-exch,1=long,2=mix)
64           swapping threshold
0            L1 in (0=transposed,1=no-transposed) form
0            U  in (0=transposed,1=no-transposed) form
1            Equilibration (0=no,1=yes)
8            memory alignment in double (> 0)

What’s Volcano #

Volcano 是一個 Kubernetes-native 的 batch scheduling 系統,專門設計給 HPC 使用。

他補足了原生 Kubernetes scheduler 的不足,支援更多 HPC 常用的排程方式及 feature,如 Gang Scheduling(讓同一個 job 的 workers 一起被佈署,避免只有部份 workers 上線的狀況)、多層的 queue、preemption、異質裝置支援(如 GPU)等等。

Volcano 也支援許多 HPC、AI/ML 相關的系統,例如前面提到的 MPI、Kubeflow(在 Kubernetes 上的 ML 開發及佈署平台)、TensorFlow 等等。

Containerize HPL #

HPL 目前沒有方便直接用的 Docker image,所以參考了 ExplorerRay/hpc-container-def 的做法,生了一個 Dockerfile 的版本。

FROM debian:trixie-slim AS build

# Environment variables for ignoring some harmless errors (from %environment)
ENV PMIX_MCA_gds="^ds12"
ENV PMIX_MCA_psec="^munge"

# Install dependencies and build HPL
RUN apt-get -y update && \
    DEBIAN_FRONTEND=noninteractive apt-get -y install \
        make g++ gcc gfortran wget openmpi-bin libopenmpi-dev libopenblas-dev && \
    apt-get clean autoclean && \
    apt-get autoremove --yes && \
    rm -rf /var/lib/apt/lists/*

RUN cd /opt && \
    wget https://www.netlib.org/benchmark/hpl/hpl-2.3.tar.gz && \
    tar -xzf hpl-2.3.tar.gz && \
    cd hpl-2.3/setup && \
    cp Make.Linux_PII_CBLAS ../Make.linux && \
    cd .. && \
    sed -i 's|^TOPdir       = $(HOME)/hpl|TOPdir       = /opt/hpl-2.3|' Make.linux && \
    sed -i 's|^ARCH         = .*$|ARCH         = linux|' Make.linux && \
    sed -i 's|^MPdir        = .*$|MPdir        = /usr/lib/x86_64-linux-gnu/openmpi|' Make.linux && \
    sed -i 's|^MPlib        = .*$|MPlib        = $(MPdir)/lib/libmpi.so|' Make.linux && \
    sed -i 's|^LAdir        = .*$|LAdir        = /usr/lib/x86_64-linux-gnu/openblas-pthread|' Make.linux && \
    sed -i 's|^LAlib        = .*$|LAlib        = $(LAdir)/libopenblas.a|' Make.linux && \
    sed -i 's|^CC           = .*$|CC           = /usr/bin/mpicc|' Make.linux && \
    sed -i 's|^LINKER       = .*$|LINKER       = /usr/bin/mpicc|' Make.linux && \
    echo "Building HPL Benchmarks..." && \
    make arch=linux && \
    rm /opt/hpl-2.3.tar.gz

FROM debian:trixie-slim

ENV PMIX_MCA_gds="^ds12"
ENV PMIX_MCA_psec="^munge"

WORKDIR /opt/hpl-2.3/bin/linux

RUN apt update && \
    apt install -y openmpi-bin libopenmpi-dev libopenblas-dev openssh-server && \
    apt-get clean autoclean && \
    apt-get autoremove --yes && \
    rm -rf /var/lib/apt/lists/*
COPY --from=build /opt/hpl-2.3/bin/linux /opt/hpl-2.3/bin/linux

CMD ["sleep", "infinity"]

此 image 已經上傳至 DockerHub

Running HPL with Volcano #

為了避免每次修改 HPL 參數都要重新 build container image,可以採用把 HPL.dat 用 ConfigMap 掛進 container 的方法。

$ kubectl create cm hpl --from-file=HPL.dat

接著準備 Volcano Job 的 YAML 檔:

apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: hpl-mpi-job
spec:
  minAvailable: 1
  schedulerName: volcano
  plugins:
    mpi: ["--master=mpimaster","--worker=mpiworker","--port=22"]  ## MPI plugin register
  tasks:
    - replicas: 1
      name: mpimaster
      policies:
        - event: TaskCompleted
          action: CompleteJob
      template:
        spec:
          volumes:
            - name: hpl-config
              configMap:
                name: hpl
          containers:
            - command:
                - /bin/sh
                - -c
                - |
                  mkdir -p /var/run/sshd; /usr/sbin/sshd;
                  mpirun --allow-run-as-root --host "$MPI_HOST" ./xhpl;
              image: siriuskoan/hpl:latest
              name: mpimaster
              workingDir: /opt/hpl-2.3/bin/linux
              volumeMounts:
                - name: hpl-config
                  mountPath: /opt/hpl-2.3/bin/linux/HPL.dat
                  subPath: HPL.dat
          restartPolicy: OnFailure
    - replicas: 4
      name: mpiworker
      template:
        spec:
          volumes:
            - name: hpl-config
              configMap:
                name: hpl
          containers:
            - command:
                - /bin/sh
                - -c
                - |
                  mkdir -p /var/run/sshd; /usr/sbin/sshd -D;
              image: siriuskoan/hpl:latest
              name: mpiworker
              workingDir: /opt/hpl-2.3/bin/linux
              volumeMounts:
                - name: hpl-config
                  mountPath: /opt/hpl-2.3/bin/linux/HPL.dat
                  subPath: HPL.dat
              resources:
                requests:
                  cpu: 1
                limits:
                  cpu: 1
          restartPolicy: OnFailure

Volcano 的 MPI plugin 會將 MPI_HOST 設定好,讓 MPI master 可以直接知道 topology 裡面有哪些 worker。

另外建議可以設定好 worker 的 resources,Kubernetes 才會給他比較高的 QoS。

最後使用以下指令就可以看到 job 在跑了:

$ kubectl apply -f job
$ kubectl get vcjob

Multi-cores 的執行 #

雖然 Volcano 會幫忙完成 topology discover 並設定好 MPI_HOST,但它不會知道使用者和 Kubernetes 要求多少資源給 worker。換句話說,如果把要求的 CPU 加到 4,HPL 依然只會跑在一個 CPU 上。

目前沒有找到 Volcano 提供的解法,但可以直接用 Linux 指令來修改一下 MPI_HOST 來讓它帶有 CPU 核心數的資料。將原本 MPI master 的 mpirun 指令改成以下這行:

mpirun --allow-run-as-root --host "$(echo $MPI_HOST | sed 's/,/:4,/g; s/$/:4/')" ./xhpl;

其中的 4 為 worker 請求的 CPU 核心數。

Todo #

Volcano 本身是為了 HPC 特化的 Kubernetes scheduler,他提供的 MPI 連線方式是最簡單的 SSH,且需要在 worker 上手動開啟 SSH server,較為麻煩。未來可以嘗試用專門做 MPI 的 Kubernetes 的 MPI Operator 跑跑看。

References #