Actual source code: ex5k.kokkos.cxx

  1: static char help[] = "Benchmarking MatMult() with AIJ and its subclass matrix types\n";

  3: /*
  4: Usage:
  5:   mpiexec -n <np> ./ex5k
  6:     -f <file>        : input PETSc matrix binary file; one can convert a file from MatrixMarket using mat/tests/ex72.c
  7:     -mat_type <type> : aij or its subclass. Default is aij.
  8:     -n <num>         : run MatMult() this many times and report average time. Default is 500.

 10: Notes:
 11:   It uses CPU-timer to measure the time.

 13: Examples:
 14:   On OLCF Summit (with GPU-aware MPI)
 15:     # 6 MPI ranks:
 16:     # 6 resource sets (-n 6), 1 MPI rank per RS (-a 1), 7 CPU cores per RS (-c 7), and 1 GPU per RS (-g 1), 6 RSs per node (-r 6)
 17:     jsrun --smpiargs "-gpu" -n 6 -a 1 -c 7 -g 1 -r 6 ./ex5k -f 1138_bus.aij -mat_type aijcusparse

 19:     # 1 MPI rank
 20:     jsrun --smpiargs "-gpu" -n 1 -a 1 -c 7 -g 1 -r 1 ./ex5k -f 1138_bus.aij -mat_type aijcusparse

 22:   On OLCF Crusher:
 23:     # 1 MPI rank
 24:     # run with 1 node (-N1), 1 mpi rank (-n1), 2 hardware threads per rank (-c2)
 25:     srun -N1 -n1 -c2 --gpus-per-node=8 --gpu-bind=closest ./ex5k -f HV15R.aij -mat_type aijkokkos

 27:     # 8 MPI ranks
 28:     srun -N1 -n8 -c2 --gpus-per-node=8 --gpu-bind=closest ./ex5k -f HV15R.aij -mat_type aijkokkos
 29: */
 30: #include <petscmat.h>

 32: #if PetscDefined(HAVE_CUDA)
 33: #include <petscdevice_cuda.h>
 34:   #define SyncDevice() PetscCallCUDA(cudaDeviceSynchronize())
 35: #elif PetscDefined(HAVE_HIP)
 36: #include <petscdevice_hip.h>
 37:   #define SyncDevice() PetscCallHIP(hipDeviceSynchronize())
 38: #elif PetscDefined(HAVE_KOKKOS)
 39:   #include <Kokkos_Core.hpp>
 40:   #define SyncDevice() Kokkos::fence()
 41: #else
 42:   #define SyncDevice()
 43: #endif

 45: int main(int argc, char **args)
 46: {
 47:   Mat            A, A2;
 48:   Vec            x, y, x2, y2;
 49:   PetscViewer    fd;
 50:   char           matfile[PETSC_MAX_PATH_LEN];
 51:   char           mattype[64];
 52:   PetscBool      flg;
 53:   PetscLogStage  stage;
 54:   PetscInt       i, n = 500, nskip = 5, M, N;
 55:   MatInfo        info;
 56:   PetscLogDouble tstart = 0, tend = 0, avgTime;
 57:   PetscRandom    rctx;
 58:   PetscReal      norm;
 59:   PetscMPIInt    size;

 61:   PetscFunctionBeginUser;
 62:   PetscCall(PetscInitialize(&argc, &args, nullptr, help));
 63:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));

 65:   /* Read options -n */
 66:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));

 68:   /* Load the matrix from a binary file */
 69:   PetscCall(PetscOptionsGetString(NULL, NULL, "-f", matfile, PETSC_MAX_PATH_LEN, &flg));
 70:   PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_USER_INPUT, "Must indicate a PETSc matrix binary file with the -f option");
 71:   PetscCall(PetscOptionsGetString(NULL, NULL, "-mat_type", mattype, sizeof(mattype), &flg));
 72:   if (!flg) PetscCall(PetscStrncpy(mattype, MATAIJ, sizeof(mattype)));

 74:   /* Read the matrix file to A2 */
 75:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, matfile, FILE_MODE_READ, &fd));
 76:   PetscCall(MatCreate(PETSC_COMM_WORLD, &A2));
 77:   PetscCall(MatSetType(A2, MATAIJ));
 78:   PetscCall(MatLoad(A2, fd));
 79:   PetscCall(MatCreateVecs(A2, &x2, &y2));
 80:   PetscCall(PetscViewerDestroy(&fd));

 82:   PetscCall(MatGetSize(A2, &M, &N));
 83:   PetscCall(MatGetInfo(A2, MAT_GLOBAL_SUM, &info));
 84:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Input matrix %s: %" PetscInt_FMT " x %" PetscInt_FMT "; %lld nonzeros; %.1f per row\n", matfile, M, N, (long long)info.nz_used, (double)info.nz_used / (double)M));

 86:   /* Copy A2 to A and convert A to the specified type */
 87:   PetscCall(MatDuplicate(A2, MAT_COPY_VALUES, &A));
 88:   PetscCall(MatConvert(A, mattype, MAT_INPLACE_MATRIX, &A));
 89:   PetscCall(MatCreateVecs(A, &x, &y));

 91:   /* Init x, x2 with the same value */
 92:   PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rctx));
 93:   PetscCall(VecSetRandom(x2, rctx));
 94:   PetscCall(PetscRandomDestroy(&rctx));
 95:   PetscCall(VecCopy(x2, x));

 97:   /* Compute the reference y2 = A2 x2 */
 98:   PetscCall(MatMult(A2, x2, y2));

100:   /* Measure y = Ax */
101:   PetscCall(PetscLogStageRegister("MatMult", &stage));
102:   for (i = 0; i < n + nskip; i++) {
103:     if (i == nskip) {
104:       SyncDevice();
105:       PetscCall(PetscLogStagePush(stage));
106:       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
107:       PetscCall(PetscTime(&tstart));
108:     }
109:     PetscCall(MatMult(A, x, y));
110:   }
111:   SyncDevice();
112:   PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
113:   PetscCall(PetscTime(&tend));
114:   avgTime = (tend - tstart) * 1e6 / n; /* microseconds */
115:   PetscCall(PetscLogStagePop());

117:   /* Validate y against y2 */
118:   PetscCall(VecAYPX(y2, -1, y));
119:   PetscCall(VecNorm(y2, NORM_2, &norm));
120:   PetscCheck(norm < 1e-6, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "MatMult() error with norm %g", (double)norm);
121:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "MatMult() average time (us) with %d MPI ranks = %8.2f\n", size, avgTime));

123:   PetscCall(MatDestroy(&A));
124:   PetscCall(VecDestroy(&x));
125:   PetscCall(VecDestroy(&y));
126:   PetscCall(MatDestroy(&A2));
127:   PetscCall(VecDestroy(&x2));
128:   PetscCall(VecDestroy(&y2));
129:   PetscCall(PetscFinalize());
130:   return 0;
131: }

133: /*TEST

135:   testset:
136:     args: -n 2 -f ${DATAFILESPATH}/matrices/small
137:     nsize: 1
138:     filter: grep "DOES_NOT_EXIST"
139:     output_file: output/empty.out
140:     requires: datafilespath !complex double !defined(PETSC_USE_64BIT_INDICES) kokkos_kernels

142:     test:
143:       suffix: 1
144:       requires: cuda
145:       args: -mat_type aijcusparse

147:     test:
148:       suffix: 2
149:       args: -mat_type aijkokkos

151:     test:
152:       suffix: 3
153:       requires: hip
154:       args: -mat_type aijhipsparse

156: TEST*/