Actual source code: bjkokkoskernels.kokkos.cxx
1: #include <petsc/private/pcbjkokkosimpl.h>
3: #if defined(PETSC_HAVE_KOKKOS_KERNELS_BATCH)
4: #include <fstream>
6: #include "Kokkos_Timer.hpp"
7: #include "Kokkos_Random.hpp"
8: #include "Kokkos_UnorderedMap.hpp"
9: #include "Kokkos_Sort.hpp"
11: /// KokkosKernels headers
12: #include "KokkosBatched_Util.hpp"
13: #include "KokkosBatched_Vector.hpp"
15: #include <Kokkos_ArithTraits.hpp>
16: #include <KokkosBatched_Util.hpp>
17: #include <KokkosBatched_Vector.hpp>
18: #include <KokkosBatched_Copy_Decl.hpp>
19: #include <KokkosBatched_Copy_Impl.hpp>
20: #include <KokkosBatched_AddRadial_Decl.hpp>
21: #include <KokkosBatched_AddRadial_Impl.hpp>
22: #include <KokkosBatched_Gemm_Decl.hpp>
23: #include <KokkosBatched_Gemm_Serial_Impl.hpp>
24: #include <KokkosBatched_Gemm_Team_Impl.hpp>
25: #include <KokkosBatched_Gemv_Decl.hpp>
26: // #include <KokkosBatched_Gemv_Serial_Impl.hpp>
27: #include <KokkosBatched_Gemv_Team_Impl.hpp>
28: #include <KokkosBatched_Trsm_Decl.hpp>
29: #include <KokkosBatched_Trsm_Serial_Impl.hpp>
30: #include <KokkosBatched_Trsm_Team_Impl.hpp>
31: #include <KokkosBatched_Trsv_Decl.hpp>
32: #include <KokkosBatched_Trsv_Serial_Impl.hpp>
33: #include <KokkosBatched_Trsv_Team_Impl.hpp>
34: #include <KokkosBatched_LU_Decl.hpp>
35: #include <KokkosBatched_LU_Serial_Impl.hpp>
36: #include <KokkosBatched_LU_Team_Impl.hpp>
37: #include <KokkosSparse_CrsMatrix.hpp>
38: #include "KokkosBatched_Spmv.hpp"
39: #include "KokkosBatched_CrsMatrix.hpp"
40: #include "KokkosBatched_Krylov_Handle.hpp"
42: #include "KokkosBatched_GMRES.hpp"
43: #include "KokkosBatched_JacobiPrec.hpp"
45: template <typename DeviceType, typename ValuesViewType, typename IntView, typename VectorViewType, typename KrylovHandleType>
46: struct Functor_TestBatchedTeamVectorGMRES {
47: const ValuesViewType _D;
48: const ValuesViewType _diag;
49: const IntView _r;
50: const IntView _c;
51: const VectorViewType _X;
52: const VectorViewType _B;
53: const int _N_team, _team_size, _vector_length;
54: const int _N_iteration;
55: const double _tol;
56: const int _ortho_strategy;
57: const int _scratch_pad_level;
58: KrylovHandleType _handle;
60: KOKKOS_INLINE_FUNCTION
61: Functor_TestBatchedTeamVectorGMRES(const ValuesViewType &D, const IntView &r, const IntView &c, const VectorViewType &X, const VectorViewType &B, const int N_team, const int team_size, const int vector_length, const int N_iteration, const double tol, const int ortho_strategy, const int scratch_pad_level, KrylovHandleType &handle) :
62: _D(D), _r(r), _c(c), _X(X), _B(B), _N_team(N_team), _team_size(team_size), _vector_length(vector_length), _N_iteration(N_iteration), _tol(tol), _ortho_strategy(ortho_strategy), _scratch_pad_level(scratch_pad_level), _handle(handle)
63: {
64: }
66: KOKKOS_INLINE_FUNCTION
67: Functor_TestBatchedTeamVectorGMRES(const ValuesViewType &D, const ValuesViewType &diag, const IntView &r, const IntView &c, const VectorViewType &X, const VectorViewType &B, const int N_team, const int team_size, const int vector_length, const int N_iteration, const double tol, int ortho_strategy, const int scratch_pad_level, KrylovHandleType &handle) :
68: _D(D), _diag(diag), _r(r), _c(c), _X(X), _B(B), _N_team(N_team), _team_size(team_size), _vector_length(vector_length), _N_iteration(N_iteration), _tol(tol), _ortho_strategy(ortho_strategy), _scratch_pad_level(scratch_pad_level), _handle(handle)
69: {
70: }
72: template <typename MemberType>
73: KOKKOS_INLINE_FUNCTION void operator()(const MemberType &member) const
74: {
75: const int first_matrix = static_cast<int>(member.league_rank()) * _N_team;
76: const int N = _D.extent(0);
77: const int last_matrix = (static_cast<int>(member.league_rank() + 1) * _N_team < N ? static_cast<int>(member.league_rank() + 1) * _N_team : N);
78: const int graphID = static_cast<int>(member.league_rank());
79: using TeamVectorCopy1D = KokkosBatched::TeamVectorCopy<MemberType, KokkosBatched::Trans::NoTranspose, 1>;
81: auto d = Kokkos::subview(_D, Kokkos::make_pair(first_matrix, last_matrix), Kokkos::ALL);
82: auto x = Kokkos::subview(_X, Kokkos::make_pair(first_matrix, last_matrix), Kokkos::ALL);
83: auto b = Kokkos::subview(_B, Kokkos::make_pair(first_matrix, last_matrix), Kokkos::ALL);
84: using ScratchPadIntViewType = Kokkos::View<typename IntView::non_const_value_type *, typename IntView::array_layout, typename IntView::execution_space::scratch_memory_space>;
85: using ScratchPadValuesViewType = Kokkos::View<typename ValuesViewType::non_const_value_type **, typename ValuesViewType::array_layout, typename ValuesViewType::execution_space::scratch_memory_space>;
87: using Operator = KokkosBatched::CrsMatrix<ValuesViewType, ScratchPadIntViewType>;
88: ScratchPadIntViewType r(member.team_scratch(1), _r.extent(1));
89: ScratchPadIntViewType c(member.team_scratch(1), _c.extent(1));
91: TeamVectorCopy1D::invoke(member, Kokkos::subview(_r, graphID, Kokkos::ALL), r);
92: TeamVectorCopy1D::invoke(member, Kokkos::subview(_c, graphID, Kokkos::ALL), c);
93: Operator A(d, r, c);
95: ScratchPadValuesViewType diag(member.team_scratch(1), last_matrix - first_matrix, _diag.extent(1));
96: using PrecOperator = KokkosBatched::JacobiPrec<ScratchPadValuesViewType>;
98: KokkosBatched::TeamVectorCopy<MemberType>::invoke(member, Kokkos::subview(_diag, Kokkos::make_pair(first_matrix, last_matrix), Kokkos::ALL), diag);
99: PrecOperator P(diag);
100: P.setComputedInverse();
102: KokkosBatched::TeamVectorGMRES<MemberType>::template invoke<Operator, VectorViewType, PrecOperator, KrylovHandleType>(member, A, b, x, P, _handle);
103: }
104: inline double run(PC pc)
105: {
106: //typedef typename ValuesViewType::value_type value_type;
107: std::string name("KokkosBatched::Test::TeamVectorGMRES");
108: Kokkos::Timer timer;
109: Kokkos::Profiling::pushRegion(name.c_str());
111: Kokkos::TeamPolicy<DeviceType> auto_policy(ceil(1. * _D.extent(0) / _N_team), Kokkos::AUTO(), Kokkos::AUTO());
112: Kokkos::TeamPolicy<DeviceType> tuned_policy(ceil(1. * _D.extent(0) / _N_team), _team_size, _vector_length);
113: Kokkos::TeamPolicy<DeviceType> policy;
115: if (_team_size < 1) policy = auto_policy;
116: else policy = tuned_policy;
118: _handle.set_max_iteration(_N_iteration);
119: _handle.set_tolerance(_tol);
120: _handle.set_ortho_strategy(_ortho_strategy);
121: _handle.set_scratch_pad_level(_scratch_pad_level);
122: _handle.set_compute_last_residual(true);
124: int maximum_iteration = _handle.get_max_iteration();
126: using ScalarType = typename ValuesViewType::non_const_value_type;
127: using Layout = typename ValuesViewType::array_layout;
128: using EXSP = typename ValuesViewType::execution_space;
130: using ViewType2D = Kokkos::View<ScalarType **, Layout, EXSP>;
131: using IntViewType1D = Kokkos::View<PetscInt *, Layout, EXSP>;
133: size_t bytes_1D = ViewType2D::shmem_size(_N_team, 1);
134: size_t bytes_row_ptr = IntViewType1D::shmem_size(_r.extent(1));
135: size_t bytes_col_idc = IntViewType1D::shmem_size(_c.extent(1));
136: size_t bytes_2D_1 = ViewType2D::shmem_size(_N_team, _X.extent(1));
137: size_t bytes_2D_2 = ViewType2D::shmem_size(_N_team, maximum_iteration + 1);
139: size_t bytes_diag = bytes_2D_1;
140: size_t bytes_tmp = 2 * bytes_2D_1 + 2 * bytes_1D + bytes_2D_2;
142: policy.set_scratch_size(0, Kokkos::PerTeam(bytes_tmp));
143: policy.set_scratch_size(1, Kokkos::PerTeam(bytes_col_idc + bytes_row_ptr + bytes_diag));
144: PetscCall(PetscInfo(pc, "%d scratch memory(0) = %d + %d + %d bytes_diag=%d; %d scratch memory(1); %d maximum_iterations\n", (int)(bytes_tmp), 2 * (int)bytes_2D_1, 2 * (int)bytes_1D, (int)bytes_2D_2, (int)bytes_diag, (int)(bytes_row_ptr + bytes_col_idc + bytes_diag), (int)maximum_iteration));
145: exec_space().fence();
146: timer.reset();
147: Kokkos::parallel_for(name.c_str(), policy, *this);
148: exec_space().fence();
149: double sec = timer.seconds();
151: return sec;
152: }
153: };
155: PETSC_INTERN PetscErrorCode PCApply_BJKOKKOSKERNELS(PC pc, const PetscScalar *glb_bdata, PetscScalar *glb_xdata, const PetscInt *glb_Aai, const PetscInt *glb_Aaj, const PetscScalar *glb_Aaa, const PetscInt team_size, MatInfo info, const PetscInt batch_sz, PCFailedReason *pcreason)
156: {
157: PC_PCBJKOKKOS *jac = (PC_PCBJKOKKOS *)pc->data;
158: Mat A = pc->pmat;
159: const PetscInt maxit = jac->ksp->max_it, nBlk = jac->nBlocks;
160: const int Nsolves = nBlk;
161: int Nsolves_team = jac->nsolves_team, fill_idx = 0;
162: int Nloc = jac->const_block_size; // same grids
163: const int nnz = (int)info.nz_used / Nsolves; // fix for variable grid size
164: PetscReal rtol = jac->ksp->rtol;
165: const PetscScalar *glb_idiag = jac->d_idiag_k->data();
166: const PetscInt *d_bid_eqOffset = jac->d_bid_eqOffset_k->data();
167: const PetscInt *d_isicol = jac->d_isicol_k->data(), *d_isrow = jac->d_isrow_k->data();
169: PetscFunctionBegin;
170: if (Nsolves_team > batch_sz) Nsolves_team = batch_sz; // silently fix this
171: PetscCheck(jac->const_block_size, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Kokkos (GMRES) solver requires constant block size (but can be made to work with species ordering or N_team==1)");
172: PetscCheck(Nsolves % Nsolves_team == 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Nsolves.mod(Nsolves_team) != 0: Nsolves = %d, Nsolves_team = %d", Nsolves, Nsolves_team);
173: PetscCheck(((int)info.nz_used) % Nsolves == 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "info.nz_used.mod(Nsolves) != 0: info.nz_used = %g, Nsolves = %d", info.nz_used, Nsolves);
174: #if defined(PETSC_HAVE_CUDA)
175: nvtxRangePushA("gmres-kk");
176: #endif
177: Kokkos::View<PetscScalar **, layout, exec_space, Kokkos::MemoryTraits<Kokkos::Unmanaged>> inv_diag((PetscScalar *)glb_idiag, Nsolves, Nloc); // in correct order
178: if (!jac->rowOffsets) {
179: jac->rowOffsets = new IntView("rowOffsets", Nsolves / Nsolves_team, Nloc + 1); // same grids
180: jac->colIndices = new IntView("colIndices", Nsolves / Nsolves_team, nnz);
181: jac->batch_b = new XYType("batch rhs", Nsolves, Nloc);
182: jac->batch_x = new XYType("batch sol", Nsolves, Nloc);
183: jac->batch_values = new AMatrixValueView("batch values", Nsolves, nnz);
184: fill_idx = 1;
185: PetscCall(PetscInfo(pc, "Setup indices Nloc=%d, nnz=%d\n", Nloc, nnz));
186: }
187: IntView &rowOffsets = *jac->rowOffsets;
188: IntView &colIndices = *jac->colIndices;
189: XYType &batch_b = *jac->batch_b;
190: XYType &batch_x = *jac->batch_x;
191: AMatrixValueView &batch_values = *jac->batch_values;
193: Kokkos::deep_copy(batch_x, 0.);
194: PetscCall(PetscInfo(pc, "\tjac->n = %d, Nloc = %d, Nsolves = %d, nnz = %d, Nsolves_team = %d, league size = %d, maxit = %d\n", (int)jac->n, Nloc, Nsolves, nnz, Nsolves_team, Nsolves / Nsolves_team, (int)maxit));
195: Kokkos::parallel_for(
196: "rowOffsets+map", Kokkos::TeamPolicy<>(Nsolves, team_size, PCBJKOKKOS_VEC_SIZE), KOKKOS_LAMBDA(const team_member team) {
197: const int blkID = team.league_rank(), start = d_bid_eqOffset[blkID], end = d_bid_eqOffset[blkID + 1];
198: if (fill_idx) {
199: if (blkID % Nsolves_team == 0) { // first matrix on this member
200: Kokkos::parallel_for(Kokkos::TeamVectorRange(team, start, end), [=](const int rowb) { // Nloc
201: int rowa = d_isicol[rowb];
202: int n = glb_Aai[rowa + 1] - glb_Aai[rowa];
203: rowOffsets(blkID / Nsolves_team, rowb + 1 - start) = n; // save sizes
204: });
205: }
206: }
207: // map b into field major space
208: Kokkos::parallel_for(Kokkos::TeamVectorRange(team, start, end), [=](int rowb) {
209: int rowa = d_isicol[rowb];
210: batch_b(blkID, rowb - start) = glb_bdata[rowa];
211: });
212: });
213: Kokkos::fence();
214: if (fill_idx) {
215: Kokkos::parallel_for(
216: "prefix sum", Kokkos::TeamPolicy<>(Nsolves / Nsolves_team, 1, 1), KOKKOS_LAMBDA(const team_member team) {
217: const int graphID = team.league_rank();
218: rowOffsets(graphID, 0) = 0;
219: for (int i = 0; i < Nloc; ++i) rowOffsets(graphID, i + 1) += rowOffsets(graphID, i);
220: });
221: Kokkos::fence();
222: }
223: Kokkos::parallel_for(
224: "copy matrix", Kokkos::TeamPolicy<>(Nsolves /* /batch_sz */, team_size, PCBJKOKKOS_VEC_SIZE), KOKKOS_LAMBDA(const team_member team) {
225: const int blkID = team.league_rank(), start = d_bid_eqOffset[blkID], end = d_bid_eqOffset[blkID + 1], graphID = blkID / Nsolves_team;
226: Kokkos::parallel_for(Kokkos::TeamThreadRange(team, start, end), [=](const int rowb) {
227: int rowa = d_isicol[rowb];
228: int n = glb_Aai[rowa + 1] - glb_Aai[rowa];
229: const PetscInt *aj = glb_Aaj + glb_Aai[rowa]; // global index
230: const PetscScalar *aa = glb_Aaa + glb_Aai[rowa];
231: Kokkos::parallel_for(Kokkos::ThreadVectorRange(team, n), [=](const int &i) {
232: PetscScalar val = aa[i];
233: if (fill_idx && blkID % Nsolves_team == 0) colIndices(graphID, rowOffsets(graphID, rowb - start) + i) = d_isrow[aj[i]] - blkID * Nloc; // local" global - block start
234: batch_values(blkID, rowOffsets(graphID, rowb - start) + i) = val;
235: });
236: });
237: });
238: Kokkos::fence();
239: // setup solver
240: using ScalarType = typename AMatrixValueView::non_const_value_type;
241: using MagnitudeType = typename Kokkos::Details::ArithTraits<ScalarType>::mag_type;
242: //using NormViewType = Kokkos::View<MagnitudeType *, layout, exec_space>;
243: using Norm2DViewType = Kokkos::View<MagnitudeType **, layout, exec_space>;
244: using Scalar3DViewType = Kokkos::View<ScalarType ***, layout, exec_space>;
245: using IntViewType = Kokkos::View<int *, layout, exec_space>;
246: using KrylovHandleType = KokkosBatched::KrylovHandle<Norm2DViewType, IntViewType, Scalar3DViewType>;
247: const int n_iterations = maxit;
248: //const int team_size = -1;
249: const int vector_length = -1;
250: const double tol = rtol;
251: const int ortho_strategy = 0;
252: KrylovHandleType handle(Nsolves, Nsolves_team, n_iterations, true);
253: handle.Arnoldi_view = Scalar3DViewType("", Nsolves, n_iterations, Nloc + n_iterations + 3);
254: // solve
255: Functor_TestBatchedTeamVectorGMRES<exec_space, AMatrixValueView, IntView, XYType, KrylovHandleType>(batch_values, inv_diag, rowOffsets, colIndices, batch_x, batch_b, Nsolves_team, -1, vector_length, n_iterations, tol, ortho_strategy, 0, handle).run(pc);
256: Kokkos::fence();
257: // get data back
258: Kokkos::parallel_for(
259: "map", Kokkos::TeamPolicy<>(Nsolves /* /batch_sz */, -1, PCBJKOKKOS_VEC_SIZE), KOKKOS_LAMBDA(const team_member team) {
260: const int blkID = team.league_rank(), start = d_bid_eqOffset[blkID], end = d_bid_eqOffset[blkID + 1]; // 0
261: // map x into Plex/PETSc
262: Kokkos::parallel_for(Kokkos::TeamVectorRange(team, start, end), [=](int rowb) {
263: int rowa = d_isicol[rowb];
264: glb_xdata[rowa] = batch_x(blkID, rowb - start);
265: });
266: });
267: // output assume species major - clone from Kokkos solvers
268: #if PCBJKOKKOS_VERBOSE_LEVEL >= 3
269: #if PCBJKOKKOS_VERBOSE_LEVEL >= 4
270: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "Iterations\n"));
271: #else
272: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "max iterations per species (gmres) :"));
273: #endif
274: for (PetscInt dmIdx = 0, s = 0, head = 0; dmIdx < jac->num_dms; dmIdx += batch_sz) {
275: for (PetscInt f = 0, idx = head; f < jac->dm_Nf[dmIdx]; f++, s++, idx++) {
276: #if PCBJKOKKOS_VERBOSE_LEVEL >= 4
277: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "%2D:", s));
278: for (int bid = 0; bid < batch_sz; bid++) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "%3D ", handle.get_iteration_host(idx + bid * jac->dm_Nf[dmIdx])));
279: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "\n"));
280: #else
281: int count = 0, ii;
282: for (int bid = 0; bid < batch_sz; bid++) {
283: if ((ii = handle.get_iteration_host(idx + bid * jac->dm_Nf[dmIdx])) > count) count = ii;
284: }
285: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "%3d", count));
286: #endif
287: }
288: head += batch_sz * jac->dm_Nf[dmIdx];
289: }
290: #if PCBJKOKKOS_VERBOSE_LEVEL == 3
291: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), "\n"));
292: #endif
293: #endif
294: // return error code, get max it
295: PetscInt count = 0, mbid = 0;
296: if (handle.is_converged_host()) {
297: *pcreason = PC_NOERROR;
298: if (!jac->max_nits) {
299: for (int blkID = 0; blkID < nBlk; blkID++) {
300: if (handle.get_iteration_host(blkID) > jac->max_nits) {
301: jac->max_nits = handle.get_iteration_host(blkID);
302: mbid = blkID;
303: }
304: }
305: }
306: } else {
307: PetscCall(PetscPrintf(PETSC_COMM_SELF, "There is at least one system that did not converge."));
308: *pcreason = PC_SUBPC_ERROR;
309: }
310: // output - assume species major order
311: for (int blkID = 0; blkID < nBlk; blkID++) {
312: if (jac->reason) { // -pc_bjkokkos_ksp_converged_reason
313: if (jac->batch_target == blkID) {
314: if (batch_sz != 1)
315: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), " Linear solve %s in %d iterations, batch %" PetscInt_FMT ", species %" PetscInt_FMT "\n", handle.is_converged_host(blkID) ? "converged" : "diverged", handle.get_iteration_host(blkID), blkID % batch_sz, blkID / batch_sz));
316: else PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), " Linear solve %s in %d iterations, block %" PetscInt_FMT "\n", handle.is_converged_host(blkID) ? "converged" : "diverged", handle.get_iteration_host(blkID), blkID));
317: } else if (jac->batch_target == -1 && handle.get_iteration_host(blkID) >= count) {
318: jac->max_nits = count = handle.get_iteration_host(blkID);
319: mbid = blkID;
320: }
321: if (!handle.is_converged_host(blkID)) PetscCall(PetscPrintf(PETSC_COMM_SELF, "ERROR species %d, batch %d did not converge with %d iterations\n", (int)(blkID / batch_sz), (int)blkID % batch_sz, handle.get_iteration_host(blkID)));
322: }
323: }
324: if (jac->batch_target == -1 && jac->reason) {
325: if (batch_sz != 1)
326: PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), " Linear solve %s in %d iteration, batch %" PetscInt_FMT ", specie %" PetscInt_FMT "\n", handle.is_converged_host(mbid) ? "converged" : "diverged", jac->max_nits, mbid % batch_sz, mbid / batch_sz));
327: else PetscCall(PetscPrintf(PetscObjectComm((PetscObject)A), " Linear solve %s in %d iteration, block %" PetscInt_FMT "\n", handle.is_converged_host(mbid) ? "converged" : "diverged", jac->max_nits, mbid));
328: }
329: #if defined(PETSC_HAVE_CUDA)
330: nvtxRangePop();
331: #endif
333: return PETSC_SUCCESS;
334: }
335: #endif