HPL (High Performance Linpack)을 POWER9 AC922에서 CUDA를 이용하여 수행하는 방법을 정리했습니다. 주로 아래 site의 내용대로 테스트한 것입니다.
https://www.slothparadise.com/compile-hpl-linpack/
먼저 아래와 같이 필요한 package들을 설치합니다.
[user1@ac922 files]$ sudo yum install openmpi openmpi-devel mpich openblas openblas-static mpich-3.0-devel atlas lapack
그리고, atlas 뿐만 아니라 atlas-devel이 필요한데, 이는 Redhat optional DVD에 들어있습니다. 저는 그것이 없는 관계로 부득이 아래 rpmfind.net에서 ppc64le fedora용 atlas-3.10.2와 atlas-devel-3.10.2를 download 받아 설치했습니다.
[user1@ac922 files]$ wget https://rpmfind.net/linux/fedora-secondary/releases/25/Everything/ppc64le/os/Packages/a/atlas-3.10.2-12.fc24.ppc64le.rpm
[user1@ac922 files]$ wget https://rpmfind.net/linux/fedora-secondary/releases/25/Everything/ppc64le/os/Packages/a/atlas-devel-3.10.2-12.fc24.ppc64le.rpm
[user1@ac922 files]$ sudo rpm -Uvh atlas-3.10.2-12.fc24.ppc64le.rpm atlas-devel-3.10.2-12.fc24.ppc64le.rpm
liblapack.so 대신 liblapack.so.3.4.2라는 이름만 만들어져 있으므로, 이를 soft link를 걸어 생성해 줍니다.
[user1@ac922 files]$ sudo ln -s /usr/lib64/liblapack.so.3.4.2 /usr/lib64/liblapack.so
[user1@ac922 files]$ sudo ln -s /usr/lib64/libopenblaso-r0.2.20.so /usr/lib64/libopenblaso.so
이제 (x86_64 버전이긴 하지만) HPL의 CUDA 버전 소스코드를 받아야 합니다. 이는 아래의 NVIDIA site에 login을 하고 받을 수 있습니다. Login ID를 만들기 위해서 회원 가입을 해야 하는데, 무료입니다.
https://developer.nvidia.com/rdp/assets/cuda-accelerated-linpack-linux64
위에서 license 등에 동의하면 아래와 같이 hpl-2.0_FERMI_v15.solitairetheme8을 download 받을 수 있습니다. 이는 tar.gz 형태의 파일입니다.
[user1@ac922 files]$ tar -zxvf hpl-2.0_FERMI_v15.solitairetheme8
[user1@ac922 files]$ cd hpl-2.0_FERMI_v15
먼저, Intel MKL compiler에 편향된 cuda_dgemm.c의 source를 약간 수정해야 합니다.
[user1@ac922 hpl-2.0_FERMI_v15]$ vi ./src/cuda/cuda_dgemm.c
...
// handle2 = dlopen ("libmkl_intel_lp64.so", RTLD_LAZY);
handle2 = dlopen ("libopenblas.so", RTLD_LAZY);
...
// dgemm_mkl = (void(*)())dlsym(handle, "dgemm");
dgemm_mkl = (void(*)())dlsym(handle, "dgemm_");
...
// handle = dlopen ("libmkl_intel_lp64.so", RTLD_LAZY);
handle = dlopen ("libopenblas.so", RTLD_LAZY);
...
// mkl_dtrsm = (void(*)())dlsym(handle2, "dtrsm");
mkl_dtrsm = (void(*)())dlsym(handle2, "dtrsm_");
...
위의 수정들을 하지 않으면 run_linpack 수행시 다음과 같은 runtime error가 납니다. 이는 ppc64le 아키텍처 상에서는 libmkl_intel_lp64 대신 오픈소스인 openblas를 사용하기 때문입니다.
libmkl_intel_lp64.so: cannot open shared object file: No such file or directory
libopenblas.so.0: undefined symbol: dtrsm
libopenblas.so.0: undefined symbol: dgemm
이제 compile을 위해 Make.CUDA를 수정합니다. ppc64le 아키텍처라고 해서 크게 바뀔 건 없습니다. 아래 libmpich.a 대신 장황하게 -L과 -lmpich 등을 쓴 것은 역시 optional Redhat DVD가 없어 제 환경에는 mpich-devel을 설치하지 못하여 libmpich.a가 없기 때문입니다. 특히 -lmkl 대신 -lopenblas를 쓴 것에 주목하십시요.
[user1@ac922 hpl-2.0_FERMI_v15]$ vi Make.CUDA
...
#TOPdir = /home/mfatica/hpl-2.0_FERMI_v15
TOPdir = /home/user1/files/hpl-2.0_FERMI_v15
...
#MPdir = /opt/intel/mpi/3.0
#MPinc = -I$(MPdir)/include64
#MPlib = $(MPdir)/lib64/libmpi.a
#MPlib = $(MPdir)/lib64/libmpich.a
MPdir = /usr/lib64/openmpi
MPinc = -I /usr/include/openmpi-ppc64le
MPlib = -L /usr/lib64/openmpi/lib -lmpi -L /usr/lib64/mpich/lib -lmpich
...
#LAdir = $(TOPdir)/../../lib/em64t
#LAdir = /share/apps/intel/mkl/10.2.4.032/libem64t
#LAinc =
# CUDA
#LAlib = -L /home/cuda/Fortran_Cuda_Blas -ldgemm -L/usr/local/cuda/lib -lcublas -L$(LAdir) -lmkl -lguide -lpthread
LAdir = /usr/lib64
LAinc = -I /usr/include/openblas -I /usr/include
#LAlib = ${LAdir}/libopenblas.a
LAlib = -L $(TOPdir)/src/cuda -ldgemm -L /usr/lib64/atlas -lsatlas -ltatlas -L /usr/local/cuda-9.1/targets/ppc64le-linux/lib/stubs -lcuda -lcublas -L /usr/local/cuda-9.1/lib64 -lcudart -L$(LAdir) -lpthread -lopenblas -lopenblaso -lm -L /usr/lib/gcc/ppc64le-redhat-linux/4.8.2 -lgfortran ${LAdir}/libopenblas.a
...
#CC = mpicc
CC = /usr/lib64/openmpi/bin/mpicc
이제 아래와 같이 환경변수를 맞춰주고, make arch=CUDA를 수행하면 일사천리로 compile이 수행됩니다.
[user1@ac922 hpl-2.0_FERMI_v15]$ export PATH=/usr/lib64/openmpi/bin:$PATH
[user1@ac922 CUDA]$ export LD_LIBRARY_PATH=/usr/lib64/openmpi/lib:/usr/lib64/mpich/lib:$LD_LIBRARY_PATH
[user1@ac922 hpl-2.0_FERMI_v15]$ make arch=CUDA
...
/usr/lib64/openmpi/bin/mpicc -DAdd__ -DF77_INTEGER=int -DStringSunStyle -DCUDA -I/home/user1/files/hpl-2.0_FERMI_v15/include -I/home/user1/files/hpl-2.0_FERMI_v15/include/CUDA -I /usr/include/openblas -I /usr/include -I /usr/include/openmpi-ppc64le -I/usr/local/cuda/include -fomit-frame-pointer -O3 -funroll-loops -W -Wall -fopenmp -o /home/user1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl HPL_pddriver.o HPL_pdinfo.o HPL_pdtest.o /home/user1/files/hpl-2.0_FERMI_v15/lib/CUDA/libhpl.a -L /home/user1/files/hpl-2.0_FERMI_v15/src/cuda -ldgemm -L /usr/lib64/atlas -lsatlas -ltatlas -L /usr/local/cuda-9.1/targets/ppc64le-linux/lib/stubs -lcuda -lcublas -L /usr/local/cuda-9.1/lib64 -lcudart -L/usr/lib64 -lpthread -L /usr/lib64/openmpi/lib -lmpi -L /usr/lib64/mpich/lib -lmpich
make TOPdir=/home/user1/files/hpl-2.0_FERMI_v15 /home/user1/files/hpl-2.0_FERMI_v15/bin/CUDA/HPL.dat
make[3]: Entering directory `/home/user1/files/hpl-2.0_FERMI_v15/testing/ptest/CUDA'
make[3]: `/home/user1/files/hpl-2.0_FERMI_v15/bin/CUDA/HPL.dat' is up to date.
make[3]: Leaving directory `/home/user1/files/hpl-2.0_FERMI_v15/testing/ptest/CUDA'
touch dexe.grd
make[2]: Leaving directory `/home/user1/files/hpl-2.0_FERMI_v15/testing/ptest/CUDA'
make[1]: Leaving directory `/home/user1/files/hpl-2.0_FERMI_v15'
실행 파일은 아래와 같이 bin/CUDA 밑에 xhpl이라는 이름으로 만들어져 있습니다.
[user1@ac922 hpl-2.0_FERMI_v15]$ cd bin/CUDA
[user1@ac922 CUDA]$ ls -l
total 264
-rw-r--r--. 1 user1 user1 1344 Jul 17 2012 HPL.dat
-rw-r--r--. 1 user1 user1 1333 Jul 17 2012 HPL.dat_example
-rw-r--r--. 1 user1 user1 6816 Jul 17 2012 output_example
-rwxr-xr-x. 1 user1 user1 607 Jul 17 2012 run_linpack
-rwxrwxr-x. 1 user1 user1 284552 Mar 22 17:56 xhpl
수행할 때 xhpl을 그대로 쓰지는 않고, 미리 준비된 run_linpack script를 수행합니다. 여기서는 HPL_DIR 정도만 수정하면 됩니다.
[user1@ac922 CUDA]$ vi run_linpack
...
#HPL_DIR=/home/mfatica/hpl-2.0_FERMI_v15
HPL_DIR=/home/user1/files/hpl-2.0_FERMI_v15
그리고 input 파일이라고 할 수 있는 HPL.dat 파일을 수정해야 합니다. 이에 대해서는 아래 URL을 참조하여 수정합니다.
http://www.netlib.org/benchmark/hpl/tuning.html
HPL.dat의 주요 input 항목의 의미에 대해서는 아래 URL을 참조하시면 됩니다.
http://www.netlib.org/benchmark/hpl/tuning.html
여기서 중요한 것은 problem size(Ns)를 얼마로 두느냐와 이걸 어떤 process grid(P x Q)에 어떤 block size (NBs)로 태우느냐입니다.
problem size(Ns)를 구하는 원래의 공식은 다음과 같습니다.
sqrt(memory 크기 * node 수 * 적정 mem% / double precision 64-bit in byte)
저는 처음에 이 CUDA 버전에서는 GPU 메모리, 즉 여기서는 16GB memory를 가진 GPU 4장을 사용하니까 다음과 같이 해야 하나 생각했습니다.
sqrt(GPU mem size * # of GPUs * 적정 mem% / double precision 64-bit in byte)
sqrt(16 * 1024^3 * 4 * 0.8 / 8) = 82897
그런데 실제 해보니 Ns를 무엇으로 주더라도 GPU mem 사용량은 개당 약 2.5GB 정도만 쓰더라고요. 결국 저 Ns는 서버의 main memory에 대해서 계산해야 합니다. 즉, 만약 512GB의 RAM을 가진 서버라면 다음과 같이 해야 합니다.
sqrt(512 * 1024^3 * 0.8 / 8 ) = 234468
process grid(P x Q)는 AC922에 장착된 GPU 개수에 맞추면 됩니다. 2 x 2 =4로 하든, 1 x 4 =4로 하든, 또는 둘 다 수행하든 택하면 됩니다. 여기서는 그냥 flat grid인 1 x 4로 하겠습니다.
Process grid에 어떤 Block size(NBs)로 태울 것인가 하는 것은, CPU인 경우 32 ~ 256 정도에서 택하되 CUDA인 경우 1000 단위로 크게 하라는데, 2048보다는 1024가 더 나은 것 같습니다.
[user1@ac922 CUDA]$ vi 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)
1 # of problems sizes (N)
234000 Ns
1 # of NBs
1024 NBs
0 PMAP process mapping (0=Row-,1=Column-major)
1 # of process grids (P x Q)
1 Ps
4 Qs
16.0 threshold
1 # of panel fact
0 PFACTs (0=left, 1=Crout, 2=Right)
1 # of recursive stopping criterium
2 NBMINs (>= 1)
1 # of panels in recursion
2 NDIVs
1 # of recursive panel fact.
2 RFACTs (0=left, 1=Crout, 2=Right)
1 # of broadcast
3 BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM)
1 # of lookahead depth
0 DEPTHs (>=0)
1 SWAP (0=bin-exch,1=long,2=mix)
64 swapping threshold
1 L1 in (0=transposed,1=no-transposed) form
0 U in (0=transposed,1=no-transposed) form
1 Equilibration (0=no,1=yes)
32 memory alignment in double (> 0)
이제 수행하면 됩니다. PxQ = 4이므로 여기서는 mpirun을 이용하여 4개를 수행합니다.
user1@ac922 CUDA]$ nohup time mpirun -np 4 ./run_linpack > linpack_out16.txt &
결과가 궁금하실텐데, 여기서 제가 개발새발 수행한 것을 공개하는 것은 곤란하군요. 다만, 이 hpl-2.0_FERMI_v15로 구현된 것은 2011년 정도에 당시 GPU에 맞춰서 HPL을 CUDA로 변환한 것이라서, 현대적인 P100이나 V100 GPU에서는 제 성능을 내지 못 합니다. (https://devtalk.nvidia.com/default/topic/991058/cuda-programming-and-performance/poor-results-from-cuda-linpack-on-k80/post/5074677/ 참조) 신규 GPU에 맞춰 NVIDIA가 작성한 HPL-CUDA가 있을텐데, 그건 일반 공개되지는 않는다고 합니다. 실제로 제가 돌려본 결과도 이론치(Rpeak)에 훨씬 미치지 못 합니다.
이때 CPU의 사용 형태는 아래와 같이 np 당 1개씩의 core만 100% 씁니다.
lnmonq16gqqqqqq[H for help]qqqHostname=ac922qqqqqqqqRefresh= 2secs qqq10:15.1
5 CPU Utilisation qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqx
x---------------------------+-----------------------------------------------x
xCPU User% Sys% Wait% Idle|0 |25 |50 |75 1x
x 1 0.0 0.0 0.0 100.0| > x
x 2 100.0 0.0 0.0 0.0|UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUx
x 3 0.0 0.0 0.0 100.0| > x
x 4 5.1 1.4 0.0 93.5|UU> x
x 5 1.0 0.0 0.0 99.0| > x
x 6 1.0 0.0 0.0 99.0| > x
x 7 1.5 0.0 0.0 98.5| > x
x 8 0.5 0.0 0.0 99.5| > x
x 9 2.0 1.5 0.0 96.6| > x
x 10 1.0 0.0 0.0 99.0| > x
x 11 1.0 0.0 0.0 99.0| > x
x 12 100.0 0.0 0.0 0.0|UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUx
x 13 0.0 0.0 0.0 100.0| > x
x 14 0.0 0.0 0.0 100.0| > x
x 15 0.0 0.0 0.0 100.0| > x
x 16 0.0 0.0 0.0 100.0| > x
x 17 100.0 0.0 0.0 0.0|UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUx
x 18 0.0 0.0 0.0 100.0| > x
x 19 1.0 0.0 0.0 99.0| > x
x 20 99.5 0.5 0.0 0.0|UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUx
x 21 0.0 0.0 0.0 100.0| x
x 22 0.0 0.0 0.0 100.0| > x
x 23 1.5 0.0 0.0 98.5| > x
x 24 1.5 0.5 0.0 98.0| > x
x 25 1.0 0.0 0.0 99.0| > x
x 26 2.0 0.0 0.0 98.0| > x
x 27 1.5 0.0 0.0 98.5| > x
x 28 1.0 0.0 0.0 99.0| > x
x 29 0.0 0.0 0.0 100.0| > x
x 30 0.0 0.0 0.0 100.0|> x
x 31 0.0 0.0 0.0 100.0|> x
x 32 0.0 0.0 0.0 100.0| > x
x---------------------------+-----------------------------------------------x
xAvg 13.2 0.1 0.0 86.7|UUUUUU > x
x---------------------------+-----------------------------------------------x
x Top Processes Procs=1297-mode=3-1=Base 3=Perf 4=Size 5=I/O[RootOnly] u=Argx
x PID %CPU Size Res Res Res Res Shared Faults Command x
x Used KB Set Text Data Lib KB Min Maj x
x 112610 108.3 34164m14482m 256 14442m 0 1742724413 0 xhpl x
그리고 GPU 사용률은 계속 100%를 쓰는 것이 아니라 이따금씩 100%를 쓰는 정도로서, 높지는 않습니다. 제 추측과는 달리, Ns를 얼마로 주든 간에 GPU memory usage는 아래처럼 언제나 2516MiB로 나오네요.
Wed Mar 28 10:14:39 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.36 Driver Version: 387.36 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000004:04:00.0 Off | 0 |
| N/A 41C P0 62W / 300W | 2586MiB / 16128MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... On | 00000004:05:00.0 Off | 0 |
| N/A 46C P0 64W / 300W | 2586MiB / 16128MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... On | 00000035:03:00.0 Off | 0 |
| N/A 43C P0 63W / 300W | 2586MiB / 16128MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... On | 00000035:04:00.0 Off | 0 |
| N/A 48C P0 63W / 300W | 2586MiB / 16128MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 112607 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 1 112609 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 2 112610 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 3 112611 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
+-----------------------------------------------------------------------------+
Wed Mar 28 10:14:44 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.36 Driver Version: 387.36 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... On | 00000004:04:00.0 Off | 0 |
| N/A 45C P0 219W / 300W | 2586MiB / 16128MiB | 100% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... On | 00000004:05:00.0 Off | 0 |
| N/A 51C P0 235W / 300W | 2586MiB / 16128MiB | 100% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... On | 00000035:03:00.0 Off | 0 |
| N/A 46C P0 64W / 300W | 2586MiB / 16128MiB | 100% Default |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... On | 00000035:04:00.0 Off | 0 |
| N/A 50C P0 64W / 300W | 2586MiB / 16128MiB | 89% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 112607 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 1 112609 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 2 112610 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
| 3 112611 C ...1/files/hpl-2.0_FERMI_v15/bin/CUDA/xhpl 2516MiB |
+-----------------------------------------------------------------------------+
댓글 없음:
댓글 쓰기