In this exercise you will optimize a naive GPU matrix-matrix multiplication by replacing the manual HIP kernel implementation with a call to HIPBLAS. General Matrix Matrix Multiplication (GEMM) is one of the most important kernels in HPC and AI:
You will:
- Understand a simple HIP GEMM kernel
- Benchmark naive matrix multiplication
- Replace the implementation using
hipblasSgemm - Compare performance between:
- naive kernel
- hipBLAS implementation
The code gemm.cpp contains a naive implementation that launches one thread per output element.
Compile:
hipcc -o gemm gemm.cpp -O3 --offload-arch=gfx90aTo run the code, one provides the matrix dimension and number of repeates as command line arguments:
srun ... ./gemm 2048 10You may try to run the code also under rocprofv3 with the summary mode:
srun ... rocprofv3 -r -T -S -- ./gemm 2048 10You can check the meaning of rocprofv3 input parameters and how to print summary
output to a file with rocprofv3 --help
hipBLAS documentation is available at https://rocm.docs.amd.com/projects/hipBLAS, however, note that cuBLAS (which has practically the same API) contains more detailed documentation on the usage. cuBLAS documentation can be found at https://docs.nvidia.com/cuda/cublas/
In short the steps needed for using hip/cuBLAS are:
- include the
<hipblas/hipblas.h>header - create a hipBLAS handle with
hipblasCreatefunction - call
hipblasSgemm- as operation (whether matrices are transposed or not) we use here
HIPBLAS_OP_Nfor both input matrices - hipBLAS performs the general operation
C = alpha * A * B + beta * C, for our basic matrix multiplicationalpha = 1.0andbeta = 0.0 - the leading dimensions
lda,ldbandldcare here the same as the first matrix dimensions
- as operation (whether matrices are transposed or not) we use here
- link the code agains
-lhipblashipcc -o gemm gemm.cpp -O3 --offload-arch=gfx90a -lhipblas
- it is good practive to destroy all hipBLAS handles with
hipblasDestroyonce they are no longer needed
Compare the performance of hipBLAS to naive implementation with various matrix sizes
As a fun bonus task, you can check how the hipBLAS performance can depend a lot on the type of input data.
By default, the input matrices are made of random floats, but by building the code with INTEGER_INIT
preprocessor define integers (converted to floats) are used:
hipcc -o gemm -DINTEGER_INIT gemm.cpp -O3 --offload-arch=gfx90a -lhipblas
You should notice that with integers the performance is improved a lot. The reason for this seems to be in the power management of AMD MI250x, when using integers GPU needs to "flip fewer" bits and it can run on higher clock frequency.
The feature does not probably provide any optimization prospects, but it is good to be aware that it may bias results when comparing performance of microbenchmarks to that of real applications if initialization is not done properly.