Actual source code: ex16k.kokkos.cxx

  1: static char help[] = "Tests VecKokkosPlaceArray() and array-less vectors from VecCreate{Seq,MPI}KokkosWithArray().\n\n";

  3: #include <petscvec.h>
  4: #include <Kokkos_Core.hpp>

  6: int main(int argc, char **argv)
  7: {
  8:   PetscInt     n = 10;
  9:   PetscMPIInt  size;
 10:   Vec          x, y, z;
 11:   PetscReal    norm;
 12:   PetscScalar *array;

 14:   PetscFunctionBeginUser;
 15:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
 16:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
 17:   {
 18:     // Create a VecKokkos x and init it
 19:     PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
 20:     PetscCall(VecSetSizes(x, n, PETSC_DECIDE));
 21:     PetscCall(VecSetType(x, VECKOKKOS));
 22:     PetscCall(VecSet(x, 4.0));

 24:     // Allocate a Kokkos View kv and init it with a different value
 25:     auto kv = Kokkos::View<PetscScalar *>("kv", n);
 26:     PetscCallCXX(Kokkos::deep_copy(kv, 2.0));

 28:     // Use kv's array to replace the device array in x
 29:     PetscCall(VecKokkosPlaceArray(x, kv.data())); // x = {2.0, 2.0, ...}
 30:     PetscCall(VecScale(x, 0.5));                  // x = {1.0, 1.0, ...}
 31:     PetscCall(VecGetArray(x, &array));            // must see the placed array, not the original one
 32:     PetscCheck(array[0] == 1.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "VecGetArray() did not return the array placed with VecKokkosPlaceArray()");
 33:     PetscCall(VecRestoreArray(x, &array));
 34:     PetscCall(VecKokkosResetArray(x)); // x = {4.0, 4.0, ...}, kv = {1,0, 1.0, ...}

 36:     // Create a vector y with kv
 37:     PetscCall(VecCreateMPIKokkosWithArray(PETSC_COMM_WORLD, 1, n, PETSC_DECIDE, kv.data(), &y));

 39:     // Check both x and y have correct values
 40:     PetscCall(VecAXPY(x, -4.0, y)); // x -= 4 * y
 41:     PetscCall(VecNorm(x, NORM_2, &norm));
 42:     PetscCheck(norm < PETSC_SMALL, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with VecKokkosPlaceArray");

 44:     PetscCall(VecDestroy(&x));
 45:     PetscCall(VecDestroy(&y));
 46:   }
 47:   {
 48:     // Create an array-less VecKokkos z: no host or device memory is allocated until an array is placed
 49:     if (size == 1) PetscCall(VecCreateSeqKokkosWithArray(PETSC_COMM_SELF, 1, n, NULL, &z));
 50:     else PetscCall(VecCreateMPIKokkosWithArray(PETSC_COMM_WORLD, 1, n, PETSC_DECIDE, NULL, &z));

 52:     // Place a device array, use z on device and on host, and take the array back
 53:     auto kz = Kokkos::View<PetscScalar *>("kz", n);
 54:     PetscCallCXX(Kokkos::deep_copy(kz, 2.0));
 55:     PetscCall(VecKokkosPlaceArray(z, kz.data())); // z = {2.0, 2.0, ...}
 56:     PetscCall(VecScale(z, 0.5));                  // z = {1.0, 1.0, ...}
 57:     PetscCall(VecNorm(z, NORM_1, &norm));
 58:     PetscCheck(PetscAbsReal(norm - (PetscReal)(n * size)) < PETSC_SMALL, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with VecKokkosPlaceArray() on an array-less vector");
 59:     PetscCall(VecGetArray(z, &array));
 60:     array[0] = 3.0; // z = {3.0, 1.0, ...}
 61:     PetscCall(VecRestoreArray(z, &array));
 62:     PetscCall(VecKokkosResetArray(z)); // kz = {3.0, 1.0, ...}
 63:     PetscCallCXX(Kokkos::fence());
 64:     {
 65:       auto kz_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), kz);

 67:       PetscCheck(kz_h(0) == 3.0 && kz_h(n - 1) == 1.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with VecKokkosResetArray() on an array-less vector");
 68:     }

 70:     // Place a host array, as MatDenseGetColumnVec() does, use z, and take the array back
 71:     PetscCall(PetscMalloc1(n, &array));
 72:     for (PetscInt i = 0; i < n; i++) array[i] = 1.0;
 73:     PetscCall(VecPlaceArray(z, array));
 74:     PetscCall(VecScale(z, 4.0)); // z = {4.0, 4.0, ...}
 75:     PetscCall(VecNorm(z, NORM_INFINITY, &norm));
 76:     PetscCheck(PetscAbsReal(norm - 4.0) < PETSC_SMALL, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with VecPlaceArray() on an array-less vector");
 77:     PetscCall(VecResetArray(z)); // array = {4.0, 4.0, ...}
 78:     PetscCheck(array[0] == 4.0 && array[n - 1] == 4.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with VecResetArray() on an array-less vector");
 79:     PetscCall(PetscFree(array));

 81:     // Place the device array once more; z must still work after the arrays were reset
 82:     PetscCall(VecKokkosPlaceArray(z, kz.data())); // z = {3.0, 1.0, ...}
 83:     PetscCall(VecNorm(z, NORM_INFINITY, &norm));
 84:     PetscCheck(PetscAbsReal(norm - 3.0) < PETSC_SMALL, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Test failed with a second VecKokkosPlaceArray() on an array-less vector");
 85:     PetscCall(VecKokkosResetArray(z));
 86:     PetscCall(VecDestroy(&z));
 87:   }
 88:   PetscCall(PetscFinalize());
 89:   return 0;
 90: }

 92: /*TEST

 94:     test:
 95:       requires: kokkos_kernels
 96:       nsize: {{1 2}}
 97:       output_file: output/empty.out

 99: TEST*/