Actual source code: ex314.c
1: static char help[] = "Tests that MatSetValues_MPISELL() invalidates the device copy when it inserts a new nonzero.\n\n";
3: /*
4: The matrix is assembled and multiplied once so that both local submatrices hold current device
5: data, then new nonzeros are inserted into the diagonal block and into the off-diagonal block. If
6: MatSetValues_MPISELL() fails to mark the host copy authoritative, MatSeqSELLCUDACopyToGPU() skips
7: the transfer and the second MatMult() returns the pre-insertion result.
9: The off-diagonal insertion deliberately reuses a global column that another local row already
10: references. An unseen column would trigger MatDisAssemble_MPISELL(), which installs a fresh
11: submatrix whose offload mask starts out unallocated, and the stale-data path would not be taken.
12: */
14: #include <petscmat.h>
16: int main(int argc, char **args)
17: {
18: Mat A, B;
19: PetscInt i, rstart, rend, col;
20: PetscMPIInt rank, size;
21: PetscScalar value = 1.0;
22: PetscBool flg;
24: PetscFunctionBeginUser;
25: PetscCall(PetscInitialize(&argc, &args, NULL, help));
26: PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
27: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
28: PetscCheck(size == 2, PETSC_COMM_WORLD, PETSC_ERR_USER, "This test requires 2 processes");
30: /* A is the matrix under test, B an MATMPIAIJ reference that receives the same values */
31: PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
32: PetscCall(MatSetSizes(A, 4, 4, PETSC_DETERMINE, PETSC_DETERMINE));
33: PetscCall(MatSetType(A, MATSELL));
34: PetscCall(MatSetFromOptions(A));
35: PetscCall(MatMPISELLSetPreallocation(A, 4, NULL, 4, NULL));
37: PetscCall(MatCreate(PETSC_COMM_WORLD, &B));
38: PetscCall(MatSetSizes(B, 4, 4, PETSC_DETERMINE, PETSC_DETERMINE));
39: PetscCall(MatSetType(B, MATAIJ));
40: PetscCall(MatMPIAIJSetPreallocation(B, 4, NULL, 4, NULL));
42: /* both matrices gain nonzeros after their first assembly */
43: PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
44: PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
46: PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
47: for (i = rstart; i < rend; i++) {
48: PetscCall(MatSetValues(A, 1, &i, 1, &i, &value, INSERT_VALUES));
49: PetscCall(MatSetValues(B, 1, &i, 1, &i, &value, INSERT_VALUES));
50: }
51: /* one off-diagonal entry, so that its global column enters garray */
52: col = rank ? 0 : 4;
53: PetscCall(MatSetValues(A, 1, &rstart, 1, &col, &value, INSERT_VALUES));
54: PetscCall(MatSetValues(B, 1, &rstart, 1, &col, &value, INSERT_VALUES));
55: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
56: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
57: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
58: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
60: /* pull both submatrices onto the device */
61: PetscCall(MatMultEqual(A, B, 4, &flg));
62: PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "MatMult() differs before insertion");
64: /* new nonzero in the diagonal block */
65: i = rstart + 1;
66: col = rstart + 2;
67: value = 2.0;
68: PetscCall(MatSetValues(A, 1, &i, 1, &col, &value, INSERT_VALUES));
69: PetscCall(MatSetValues(B, 1, &i, 1, &col, &value, INSERT_VALUES));
70: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
71: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
72: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
73: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
74: PetscCall(MatMultEqual(A, B, 4, &flg));
75: PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "MatMult() differs after inserting into the diagonal block");
77: /* new nonzero in the off-diagonal block, in a column garray already knows */
78: i = rstart + 1;
79: col = rank ? 0 : 4;
80: value = 3.0;
81: PetscCall(MatSetValues(A, 1, &i, 1, &col, &value, INSERT_VALUES));
82: PetscCall(MatSetValues(B, 1, &i, 1, &col, &value, INSERT_VALUES));
83: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
84: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
85: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
86: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
87: PetscCall(MatMultEqual(A, B, 4, &flg));
88: PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "MatMult() differs after inserting into the off-diagonal block");
90: PetscCall(MatDestroy(&A));
91: PetscCall(MatDestroy(&B));
92: PetscCall(PetscFinalize());
93: return 0;
94: }
96: /*TEST
98: test:
99: suffix: 1
100: nsize: 2
101: args: -mat_type sell
102: output_file: output/empty.out
104: test:
105: suffix: cuda
106: nsize: 2
107: requires: cuda !complex
108: args: -mat_type sellcuda
109: output_file: output/empty.out
111: test:
112: suffix: hip
113: nsize: 2
114: requires: hip !complex
115: args: -mat_type sellhip
116: output_file: output/empty.out
118: TEST*/