Actual source code: pbjacobi_cuda.cu
1: #include <petscdevice_cuda.h>
2: #include <petsc/private/cupmblasinterface.hpp>
3: #include <petsc/private/petsclegacycupmblas.h>
4: #include <../src/ksp/pc/impls/pbjacobi/pbjacobi.h>
6: #if PETSC_PKG_CUDA_VERSION_LT(11, 7, 0)
7: __global__ static void MatMultBatched(PetscInt bs, PetscInt mbs, const PetscScalar *A, const PetscScalar *x, PetscScalar *y, PetscBool transpose)
8: {
9: const PetscInt gridSize = gridDim.x * blockDim.x;
10: PetscInt row = blockIdx.x * blockDim.x + threadIdx.x;
11: const PetscInt bs2 = bs * bs;
13: /* One row per thread. The blocks are stored in column-major order */
14: for (; row < bs * mbs; row += gridSize) {
15: const PetscScalar *Ap, *xp;
16: PetscScalar *yp;
17: PetscInt i, j, k;
19: k = row / bs; /* k-th block */
20: i = row % bs; /* this thread deals with i-th row of the block */
21: Ap = &A[bs2 * k + i * (transpose ? bs : 1)]; /* Ap points to the first entry of i-th row */
22: xp = &x[bs * k];
23: yp = &y[bs * k];
24: /* multiply i-th row (column) with x */
25: yp[i] = 0.0;
26: for (j = 0; j < bs; j++) {
27: yp[i] += Ap[0] * xp[j];
28: Ap += (transpose ? 1 : bs); /* block is in column major order */
29: }
30: }
31: }
32: #endif
34: static PetscErrorCode PCApplyOrTranspose_PBJacobi_CUDA(PC pc, Vec x, Vec y, cublasOperation_t op)
35: {
36: const PetscScalar *xx;
37: PetscScalar *yy;
38: cublasHandle_t handle;
39: PC_PBJacobi *jac = (PC_PBJacobi *)pc->data;
40: const PetscScalar *A = (const PetscScalar *)jac->spptr;
41: const PetscInt bs = jac->bs, mbs = jac->mbs;
43: PetscFunctionBegin;
44: PetscCall(VecCUDAGetArrayRead(x, &xx));
45: PetscCall(VecCUDAGetArrayWrite(y, &yy));
46: PetscCall(PetscCUBLASGetHandle(&handle));
47: {
48: const Petsc::device::cupm::impl::BlasInterface<Petsc::device::cupm::DeviceType::CUDA>::CUPMBlasPointerModeGuard guard(handle, CUBLAS_POINTER_MODE_HOST);
50: #if PETSC_PKG_CUDA_VERSION_GE(11, 7, 0)
51: /* y = alpha op(A) x + beta y */
52: const PetscScalar alpha = 1.0, beta = 0.0;
53: PetscCallCUBLAS(cublasXgemvStridedBatched(handle, op, bs, bs, &alpha, A, bs, bs * bs, xx, 1, bs, &beta, yy, 1, bs, mbs));
54: #else
55: PetscInt gridSize = PetscMin((bs * mbs + 255) / 256, 2147483647); /* <= 2^31-1 */
56: MatMultBatched<<<gridSize, 256>>>(bs, mbs, A, xx, yy, op == CUBLAS_OP_T ? PETSC_TRUE : PETSC_FALSE);
57: PetscCallCUDA(cudaGetLastError());
58: #endif
59: }
60: PetscCall(VecCUDARestoreArrayRead(x, &xx));
61: PetscCall(VecCUDARestoreArrayWrite(y, &yy));
62: PetscCall(PetscLogGpuFlops(bs * bs * mbs * 2));
63: PetscFunctionReturn(PETSC_SUCCESS);
64: }
66: static PetscErrorCode PCApply_PBJacobi_CUDA(PC pc, Vec x, Vec y)
67: {
68: PetscFunctionBegin;
69: PetscCall(PCApplyOrTranspose_PBJacobi_CUDA(pc, x, y, CUBLAS_OP_N)); // No transpose
70: PetscFunctionReturn(PETSC_SUCCESS);
71: }
73: static PetscErrorCode PCApplyTranspose_PBJacobi_CUDA(PC pc, Vec x, Vec y)
74: {
75: PetscFunctionBegin;
76: PetscCall(PCApplyOrTranspose_PBJacobi_CUDA(pc, x, y, CUBLAS_OP_T)); // Transpose
77: PetscFunctionReturn(PETSC_SUCCESS);
78: }
80: static PetscErrorCode PCDestroy_PBJacobi_CUDA(PC pc)
81: {
82: PC_PBJacobi *jac = (PC_PBJacobi *)pc->data;
84: PetscFunctionBegin;
85: PetscCallCUDA(cudaFree(jac->spptr));
86: PetscCall(PCDestroy_PBJacobi(pc));
87: PetscFunctionReturn(PETSC_SUCCESS);
88: }
90: PETSC_INTERN PetscErrorCode PCSetUp_PBJacobi_CUDA(PC pc, Mat diagVB)
91: {
92: PC_PBJacobi *jac = (PC_PBJacobi *)pc->data;
93: size_t size;
95: PetscFunctionBegin;
96: PetscCall(PCSetUp_PBJacobi_Host(pc, diagVB)); /* Compute the inverse on host now. Might worth doing it on device directly */
97: size = sizeof(PetscScalar) * jac->bs * jac->bs * jac->mbs;
99: /* PBJacobi_CUDA is simple so that we use jac->spptr as if it is diag_d */
100: if (!jac->spptr) PetscCallCUDAVoid(cudaMalloc(&jac->spptr, size));
101: PetscCallCUDAVoid(cudaMemcpy(jac->spptr, jac->diag, size, cudaMemcpyHostToDevice));
102: PetscCall(PetscLogCpuToGpu(size));
104: pc->ops->apply = PCApply_PBJacobi_CUDA;
105: pc->ops->applytranspose = PCApplyTranspose_PBJacobi_CUDA;
106: pc->ops->destroy = PCDestroy_PBJacobi_CUDA;
107: PetscFunctionReturn(PETSC_SUCCESS);
108: }