1*0e6b6b59SJacob Faibussowitsch static const char help[] = "Tests PetscDeviceAllocate().\n\n"; 2*0e6b6b59SJacob Faibussowitsch 3*0e6b6b59SJacob Faibussowitsch #include "petscdevicetestcommon.h" 4*0e6b6b59SJacob Faibussowitsch 5*0e6b6b59SJacob Faibussowitsch #define DebugPrintf(comm, ...) PetscPrintf((comm), "[DEBUG OUTPUT] " __VA_ARGS__) 6*0e6b6b59SJacob Faibussowitsch 7*0e6b6b59SJacob Faibussowitsch static PetscErrorCode IncrementSize(PetscRandom rand, PetscInt *value) { 8*0e6b6b59SJacob Faibussowitsch PetscReal rval; 9*0e6b6b59SJacob Faibussowitsch 10*0e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 11*0e6b6b59SJacob Faibussowitsch // set the interval such that *value += rval never goes below 0 or above 500 12*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetInterval(rand, -(*value), 500 - (*value))); 13*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomGetValueReal(rand, &rval)); 14*0e6b6b59SJacob Faibussowitsch *value += (PetscInt)rval; 15*0e6b6b59SJacob Faibussowitsch PetscCall(DebugPrintf(PetscObjectComm((PetscObject)rand), "n: %" PetscInt_FMT "\n", *value)); 16*0e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 17*0e6b6b59SJacob Faibussowitsch } 18*0e6b6b59SJacob Faibussowitsch 19*0e6b6b59SJacob Faibussowitsch static PetscErrorCode TestAllocate(PetscDeviceContext dctx, PetscRandom rand, PetscMemType mtype) { 20*0e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 21*0e6b6b59SJacob Faibussowitsch PetscInt n = 10; 22*0e6b6b59SJacob Faibussowitsch 23*0e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 24*0e6b6b59SJacob Faibussowitsch if (PetscMemTypeDevice(mtype)) { 25*0e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 26*0e6b6b59SJacob Faibussowitsch 27*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 28*0e6b6b59SJacob Faibussowitsch // host device context cannot handle this 29*0e6b6b59SJacob Faibussowitsch if (dtype == PETSC_DEVICE_HOST) PetscFunctionReturn(0); 30*0e6b6b59SJacob Faibussowitsch } 31*0e6b6b59SJacob Faibussowitsch // test basic allocation, deallocation 32*0e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 33*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 34*0e6b6b59SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceMalloc() return NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 35*0e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 36*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) ptr[i] = (PetscScalar)i; 37*0e6b6b59SJacob Faibussowitsch } 38*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 39*0e6b6b59SJacob Faibussowitsch 40*0e6b6b59SJacob Faibussowitsch // test that calloc() produces cleared memory 41*0e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 42*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, mtype, n, &ptr)); 43*0e6b6b59SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceCalloc() return NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 44*0e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 45*0e6b6b59SJacob Faibussowitsch tmp_ptr = ptr; 46*0e6b6b59SJacob Faibussowitsch } else { 47*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 48*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 49*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 50*0e6b6b59SJacob Faibussowitsch } 51*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCheck(tmp_ptr[i] == (PetscScalar)0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceCalloc() returned memory that was not cleared, ptr[%" PetscInt_FMT "] %g != 0", i, (double)PetscAbsScalar(tmp_ptr[i])); 52*0e6b6b59SJacob Faibussowitsch if (tmp_ptr == ptr) { 53*0e6b6b59SJacob Faibussowitsch tmp_ptr = NULL; 54*0e6b6b59SJacob Faibussowitsch } else { 55*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 56*0e6b6b59SJacob Faibussowitsch } 57*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 58*0e6b6b59SJacob Faibussowitsch 59*0e6b6b59SJacob Faibussowitsch // test that devicearrayzero produces cleared memory 60*0e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 61*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 62*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(dctx, ptr, n)); 63*0e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, &tmp_ptr)); 64*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceRegisterMemory(tmp_ptr, PETSC_MEMTYPE_HOST, n * sizeof(*tmp_ptr))); 65*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) tmp_ptr[i] = (PetscScalar)i; 66*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 67*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 68*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCheck(tmp_ptr[i] == (PetscScalar)0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceArrayZero() did not not clear memory, ptr[%" PetscInt_FMT "] %g != 0", i, (double)PetscAbsScalar(tmp_ptr[i])); 69*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 70*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 71*0e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 72*0e6b6b59SJacob Faibussowitsch } 73*0e6b6b59SJacob Faibussowitsch 74*0e6b6b59SJacob Faibussowitsch static PetscErrorCode TestAsyncCoherence(PetscDeviceContext dctx, PetscRandom rand) { 75*0e6b6b59SJacob Faibussowitsch const PetscInt nsub = 2; 76*0e6b6b59SJacob Faibussowitsch const PetscInt n = 1024; 77*0e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 78*0e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 79*0e6b6b59SJacob Faibussowitsch PetscDeviceContext *sub; 80*0e6b6b59SJacob Faibussowitsch 81*0e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 82*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 83*0e6b6b59SJacob Faibussowitsch // ensure the streams are nonblocking 84*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextForkWithStreamType(dctx, PETSC_STREAM_GLOBAL_NONBLOCKING, nsub, &sub)); 85*0e6b6b59SJacob Faibussowitsch // do a warmup to ensure each context acquires any necessary data structures 86*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nsub; ++i) { 87*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_HOST, n, &ptr)); 88*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 89*0e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 90*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_DEVICE, n, &ptr)); 91*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 92*0e6b6b59SJacob Faibussowitsch } 93*0e6b6b59SJacob Faibussowitsch } 94*0e6b6b59SJacob Faibussowitsch 95*0e6b6b59SJacob Faibussowitsch // allocate on one 96*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 97*0e6b6b59SJacob Faibussowitsch // free on the other 98*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 99*0e6b6b59SJacob Faibussowitsch 100*0e6b6b59SJacob Faibussowitsch // allocate on one 101*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 102*0e6b6b59SJacob Faibussowitsch // zero on the other 103*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(sub[1], ptr, n)); 104*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[1])); 105*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 106*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCheck(ptr[i] == (PetscScalar)0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceArrayZero() was not properly serialized, ptr[%" PetscInt_FMT "] %g != 0", i, (double)PetscAbsScalar(ptr[i])); 107*0e6b6b59SJacob Faibussowitsch } 108*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 109*0e6b6b59SJacob Faibussowitsch 110*0e6b6b59SJacob Faibussowitsch // test the transfers are serialized 111*0e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 112*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, PETSC_MEMTYPE_DEVICE, n, &ptr)); 113*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 114*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(sub[0], tmp_ptr, ptr, n)); 115*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[0])); 116*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 117*0e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) PetscCheck(tmp_ptr[i] == (PetscScalar)0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceArrayCopt() was not properly serialized, ptr[%" PetscInt_FMT "] %g != 0", i, (double)PetscAbsScalar(tmp_ptr[i])); 118*0e6b6b59SJacob Faibussowitsch } 119*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 120*0e6b6b59SJacob Faibussowitsch } 121*0e6b6b59SJacob Faibussowitsch 122*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextJoin(dctx, nsub, PETSC_DEVICE_CONTEXT_JOIN_DESTROY, &sub)); 123*0e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 124*0e6b6b59SJacob Faibussowitsch } 125*0e6b6b59SJacob Faibussowitsch 126*0e6b6b59SJacob Faibussowitsch int main(int argc, char *argv[]) { 127*0e6b6b59SJacob Faibussowitsch PetscDeviceContext dctx; 128*0e6b6b59SJacob Faibussowitsch PetscRandom rand; 129*0e6b6b59SJacob Faibussowitsch 130*0e6b6b59SJacob Faibussowitsch PetscFunctionBeginUser; 131*0e6b6b59SJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 132*0e6b6b59SJacob Faibussowitsch 133*0e6b6b59SJacob Faibussowitsch // A vile hack. The -info output is used to test correctness in this test which prints -- 134*0e6b6b59SJacob Faibussowitsch // among other things -- the PetscObjectId of the PetscDevicContext and the allocated memory. 135*0e6b6b59SJacob Faibussowitsch // 136*0e6b6b59SJacob Faibussowitsch // Due to device and host creating slightly different number of objects on startup there will 137*0e6b6b59SJacob Faibussowitsch // be a mismatch in the ID's. So for the tests involving the host we sit here creating 138*0e6b6b59SJacob Faibussowitsch // PetscContainers (and incrementing the global PetscObjectId counter) until it reaches some 139*0e6b6b59SJacob Faibussowitsch // arbitrarily high number to ensure that our first PetscDeviceContext has the same ID across 140*0e6b6b59SJacob Faibussowitsch // systems. 141*0e6b6b59SJacob Faibussowitsch if (PETSC_DEVICE_DEFAULT() == PETSC_DEVICE_HOST) { 142*0e6b6b59SJacob Faibussowitsch PetscObjectId id, prev_id = 0; 143*0e6b6b59SJacob Faibussowitsch 144*0e6b6b59SJacob Faibussowitsch do { 145*0e6b6b59SJacob Faibussowitsch PetscContainer c; 146*0e6b6b59SJacob Faibussowitsch 147*0e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, &c)); 148*0e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)c, &id)); 149*0e6b6b59SJacob Faibussowitsch // sanity check, in case PetscContainer ever stops being a PetscObject 150*0e6b6b59SJacob Faibussowitsch PetscCheck(id > prev_id, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscObjectIds are not increasing for successively created PetscContainers! current: %" PetscInt64_FMT ", previous: %" PetscInt64_FMT, id, prev_id); 151*0e6b6b59SJacob Faibussowitsch prev_id = id; 152*0e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&c)); 153*0e6b6b59SJacob Faibussowitsch } while (id < 10); 154*0e6b6b59SJacob Faibussowitsch } 155*0e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 156*0e6b6b59SJacob Faibussowitsch 157*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand)); 158*0e6b6b59SJacob Faibussowitsch // this seed just so happens to keep the allocation size increasing 159*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetSeed(rand, 123)); 160*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSeed(rand)); 161*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rand)); 162*0e6b6b59SJacob Faibussowitsch 163*0e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_HOST)); 164*0e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_DEVICE)); 165*0e6b6b59SJacob Faibussowitsch PetscCall(TestAsyncCoherence(dctx, rand)); 166*0e6b6b59SJacob Faibussowitsch 167*0e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 168*0e6b6b59SJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "EXIT_SUCCESS\n")); 169*0e6b6b59SJacob Faibussowitsch PetscCall(PetscFinalize()); 170*0e6b6b59SJacob Faibussowitsch return 0; 171*0e6b6b59SJacob Faibussowitsch } 172*0e6b6b59SJacob Faibussowitsch 173*0e6b6b59SJacob Faibussowitsch /*TEST 174*0e6b6b59SJacob Faibussowitsch 175*0e6b6b59SJacob Faibussowitsch build: 176*0e6b6b59SJacob Faibussowitsch requires: defined(PETSC_HAVE_CXX) 177*0e6b6b59SJacob Faibussowitsch 178*0e6b6b59SJacob Faibussowitsch testset: 179*0e6b6b59SJacob Faibussowitsch requires: defined(PETSC_USE_INFO), defined(PETSC_USE_DEBUG) 180*0e6b6b59SJacob Faibussowitsch args: -info :device 181*0e6b6b59SJacob Faibussowitsch suffix: with_info 182*0e6b6b59SJacob Faibussowitsch test: 183*0e6b6b59SJacob Faibussowitsch requires: !device 184*0e6b6b59SJacob Faibussowitsch suffix: host_no_device 185*0e6b6b59SJacob Faibussowitsch test: 186*0e6b6b59SJacob Faibussowitsch requires: device 187*0e6b6b59SJacob Faibussowitsch args: -default_device_type host 188*0e6b6b59SJacob Faibussowitsch filter: sed -e 's/host/IMPL/g' -e 's/cuda/IMPL/g' -e 's/hip/IMPL/g' -e 's/sycl/IMPL/g' 189*0e6b6b59SJacob Faibussowitsch suffix: host_with_device 190*0e6b6b59SJacob Faibussowitsch test: 191*0e6b6b59SJacob Faibussowitsch requires: cuda 192*0e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 193*0e6b6b59SJacob Faibussowitsch suffix: cuda 194*0e6b6b59SJacob Faibussowitsch test: 195*0e6b6b59SJacob Faibussowitsch requires: hip 196*0e6b6b59SJacob Faibussowitsch args: -default_device_type hip 197*0e6b6b59SJacob Faibussowitsch suffix: hip 198*0e6b6b59SJacob Faibussowitsch test: 199*0e6b6b59SJacob Faibussowitsch requires: sycl 200*0e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 201*0e6b6b59SJacob Faibussowitsch suffix: sycl 202*0e6b6b59SJacob Faibussowitsch 203*0e6b6b59SJacob Faibussowitsch testset: 204*0e6b6b59SJacob Faibussowitsch output_file: ./output/ExitSuccess.out 205*0e6b6b59SJacob Faibussowitsch requires: !defined(PETSC_USE_DEBUG) 206*0e6b6b59SJacob Faibussowitsch filter: grep -v "\[DEBUG OUTPUT\]" 207*0e6b6b59SJacob Faibussowitsch suffix: no_info 208*0e6b6b59SJacob Faibussowitsch test: 209*0e6b6b59SJacob Faibussowitsch requires: !device 210*0e6b6b59SJacob Faibussowitsch suffix: host_no_device 211*0e6b6b59SJacob Faibussowitsch test: 212*0e6b6b59SJacob Faibussowitsch requires: device 213*0e6b6b59SJacob Faibussowitsch args: -default_device_type host 214*0e6b6b59SJacob Faibussowitsch suffix: host_with_device 215*0e6b6b59SJacob Faibussowitsch test: 216*0e6b6b59SJacob Faibussowitsch requires: cuda 217*0e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 218*0e6b6b59SJacob Faibussowitsch suffix: cuda 219*0e6b6b59SJacob Faibussowitsch test: 220*0e6b6b59SJacob Faibussowitsch requires: hip 221*0e6b6b59SJacob Faibussowitsch args: -default_device_type hip 222*0e6b6b59SJacob Faibussowitsch suffix: hip 223*0e6b6b59SJacob Faibussowitsch test: 224*0e6b6b59SJacob Faibussowitsch requires: sycl 225*0e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 226*0e6b6b59SJacob Faibussowitsch suffix: sycl 227*0e6b6b59SJacob Faibussowitsch TEST*/ 228