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*/