10e6b6b59SJacob Faibussowitsch static const char help[] = "Tests PetscDeviceAllocate().\n\n"; 20e6b6b59SJacob Faibussowitsch 30e6b6b59SJacob Faibussowitsch #include "petscdevicetestcommon.h" 40e6b6b59SJacob Faibussowitsch 50e6b6b59SJacob Faibussowitsch #define DebugPrintf(comm, ...) PetscPrintf((comm), "[DEBUG OUTPUT] " __VA_ARGS__) 60e6b6b59SJacob Faibussowitsch 70e6b6b59SJacob Faibussowitsch static PetscErrorCode IncrementSize(PetscRandom rand, PetscInt *value) { 80e6b6b59SJacob Faibussowitsch PetscReal rval; 90e6b6b59SJacob Faibussowitsch 100e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 110e6b6b59SJacob Faibussowitsch // set the interval such that *value += rval never goes below 0 or above 500 120e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetInterval(rand, -(*value), 500 - (*value))); 130e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomGetValueReal(rand, &rval)); 140e6b6b59SJacob Faibussowitsch *value += (PetscInt)rval; 150e6b6b59SJacob Faibussowitsch PetscCall(DebugPrintf(PetscObjectComm((PetscObject)rand), "n: %" PetscInt_FMT "\n", *value)); 160e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 170e6b6b59SJacob Faibussowitsch } 180e6b6b59SJacob Faibussowitsch 190e6b6b59SJacob Faibussowitsch static PetscErrorCode TestAllocate(PetscDeviceContext dctx, PetscRandom rand, PetscMemType mtype) { 200e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 210e6b6b59SJacob Faibussowitsch PetscInt n = 10; 220e6b6b59SJacob Faibussowitsch 230e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 240e6b6b59SJacob Faibussowitsch if (PetscMemTypeDevice(mtype)) { 250e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 260e6b6b59SJacob Faibussowitsch 270e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 280e6b6b59SJacob Faibussowitsch // host device context cannot handle this 290e6b6b59SJacob Faibussowitsch if (dtype == PETSC_DEVICE_HOST) PetscFunctionReturn(0); 300e6b6b59SJacob Faibussowitsch } 310e6b6b59SJacob Faibussowitsch // test basic allocation, deallocation 320e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 330e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 340e6b6b59SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceMalloc() return NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 35*6797ed33SJacob Faibussowitsch // this ensures the host pointer is at least valid 360e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 370e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) ptr[i] = (PetscScalar)i; 380e6b6b59SJacob Faibussowitsch } 390e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 400e6b6b59SJacob Faibussowitsch 41*6797ed33SJacob Faibussowitsch // test alignment of various types 42*6797ed33SJacob Faibussowitsch { 43*6797ed33SJacob Faibussowitsch char *char_ptr; 44*6797ed33SJacob Faibussowitsch short *short_ptr; 45*6797ed33SJacob Faibussowitsch int *int_ptr; 46*6797ed33SJacob Faibussowitsch double *double_ptr; 47*6797ed33SJacob Faibussowitsch long int *long_int_ptr; 48*6797ed33SJacob Faibussowitsch 49*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &char_ptr)); 50*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &short_ptr)); 51*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &int_ptr)); 52*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &double_ptr)); 53*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &long_int_ptr)); 54*6797ed33SJacob Faibussowitsch 55*6797ed33SJacob Faibussowitsch // if an error occurs here, it means the alignment system is broken! 56*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, char_ptr)); 57*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, short_ptr)); 58*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, int_ptr)); 59*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, double_ptr)); 60*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, long_int_ptr)); 61*6797ed33SJacob Faibussowitsch } 62*6797ed33SJacob Faibussowitsch 630e6b6b59SJacob Faibussowitsch // test that calloc() produces cleared memory 640e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 650e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, mtype, n, &ptr)); 66*6797ed33SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceCalloc() returned NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 670e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 680e6b6b59SJacob Faibussowitsch tmp_ptr = ptr; 690e6b6b59SJacob Faibussowitsch } else { 700e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 710e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 720e6b6b59SJacob Faibussowitsch } 73*6797ed33SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 740e6b6b59SJacob 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])); 750e6b6b59SJacob Faibussowitsch if (tmp_ptr == ptr) { 760e6b6b59SJacob Faibussowitsch tmp_ptr = NULL; 770e6b6b59SJacob Faibussowitsch } else { 780e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 790e6b6b59SJacob Faibussowitsch } 800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 810e6b6b59SJacob Faibussowitsch 820e6b6b59SJacob Faibussowitsch // test that devicearrayzero produces cleared memory 830e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 840e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 850e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(dctx, ptr, n)); 860e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, &tmp_ptr)); 870e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceRegisterMemory(tmp_ptr, PETSC_MEMTYPE_HOST, n * sizeof(*tmp_ptr))); 880e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) tmp_ptr[i] = (PetscScalar)i; 890e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 900e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 910e6b6b59SJacob 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])); 920e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 930e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 940e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 950e6b6b59SJacob Faibussowitsch } 960e6b6b59SJacob Faibussowitsch 970e6b6b59SJacob Faibussowitsch static PetscErrorCode TestAsyncCoherence(PetscDeviceContext dctx, PetscRandom rand) { 980e6b6b59SJacob Faibussowitsch const PetscInt nsub = 2; 990e6b6b59SJacob Faibussowitsch const PetscInt n = 1024; 1000e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 1010e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 1020e6b6b59SJacob Faibussowitsch PetscDeviceContext *sub; 1030e6b6b59SJacob Faibussowitsch 1040e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1050e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 1060e6b6b59SJacob Faibussowitsch // ensure the streams are nonblocking 1070e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextForkWithStreamType(dctx, PETSC_STREAM_GLOBAL_NONBLOCKING, nsub, &sub)); 1080e6b6b59SJacob Faibussowitsch // do a warmup to ensure each context acquires any necessary data structures 1090e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nsub; ++i) { 1100e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_HOST, n, &ptr)); 1110e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 1120e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 1130e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_DEVICE, n, &ptr)); 1140e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 1150e6b6b59SJacob Faibussowitsch } 1160e6b6b59SJacob Faibussowitsch } 1170e6b6b59SJacob Faibussowitsch 1180e6b6b59SJacob Faibussowitsch // allocate on one 1190e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 1200e6b6b59SJacob Faibussowitsch // free on the other 1210e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1220e6b6b59SJacob Faibussowitsch 1230e6b6b59SJacob Faibussowitsch // allocate on one 1240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 1250e6b6b59SJacob Faibussowitsch // zero on the other 1260e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(sub[1], ptr, n)); 1270e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[1])); 1280e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 1290e6b6b59SJacob 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])); 1300e6b6b59SJacob Faibussowitsch } 1310e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1320e6b6b59SJacob Faibussowitsch 1330e6b6b59SJacob Faibussowitsch // test the transfers are serialized 1340e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 1350e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, PETSC_MEMTYPE_DEVICE, n, &ptr)); 1360e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 1370e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(sub[0], tmp_ptr, ptr, n)); 1380e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[0])); 1390e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 1400e6b6b59SJacob 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])); 1410e6b6b59SJacob Faibussowitsch } 1420e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1430e6b6b59SJacob Faibussowitsch } 1440e6b6b59SJacob Faibussowitsch 1450e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextJoin(dctx, nsub, PETSC_DEVICE_CONTEXT_JOIN_DESTROY, &sub)); 1460e6b6b59SJacob Faibussowitsch PetscFunctionReturn(0); 1470e6b6b59SJacob Faibussowitsch } 1480e6b6b59SJacob Faibussowitsch 1490e6b6b59SJacob Faibussowitsch int main(int argc, char *argv[]) { 1500e6b6b59SJacob Faibussowitsch PetscDeviceContext dctx; 1510e6b6b59SJacob Faibussowitsch PetscRandom rand; 1520e6b6b59SJacob Faibussowitsch 1530e6b6b59SJacob Faibussowitsch PetscFunctionBeginUser; 1540e6b6b59SJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 1550e6b6b59SJacob Faibussowitsch 1560e6b6b59SJacob Faibussowitsch // A vile hack. The -info output is used to test correctness in this test which prints -- 1570e6b6b59SJacob Faibussowitsch // among other things -- the PetscObjectId of the PetscDevicContext and the allocated memory. 1580e6b6b59SJacob Faibussowitsch // 1590e6b6b59SJacob Faibussowitsch // Due to device and host creating slightly different number of objects on startup there will 1600e6b6b59SJacob Faibussowitsch // be a mismatch in the ID's. So for the tests involving the host we sit here creating 1610e6b6b59SJacob Faibussowitsch // PetscContainers (and incrementing the global PetscObjectId counter) until it reaches some 1620e6b6b59SJacob Faibussowitsch // arbitrarily high number to ensure that our first PetscDeviceContext has the same ID across 1630e6b6b59SJacob Faibussowitsch // systems. 1640e6b6b59SJacob Faibussowitsch if (PETSC_DEVICE_DEFAULT() == PETSC_DEVICE_HOST) { 1650e6b6b59SJacob Faibussowitsch PetscObjectId id, prev_id = 0; 1660e6b6b59SJacob Faibussowitsch 1670e6b6b59SJacob Faibussowitsch do { 1680e6b6b59SJacob Faibussowitsch PetscContainer c; 1690e6b6b59SJacob Faibussowitsch 1700e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, &c)); 1710e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)c, &id)); 1720e6b6b59SJacob Faibussowitsch // sanity check, in case PetscContainer ever stops being a PetscObject 1730e6b6b59SJacob 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); 1740e6b6b59SJacob Faibussowitsch prev_id = id; 1750e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&c)); 1760e6b6b59SJacob Faibussowitsch } while (id < 10); 1770e6b6b59SJacob Faibussowitsch } 1780e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 1790e6b6b59SJacob Faibussowitsch 1800e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand)); 1810e6b6b59SJacob Faibussowitsch // this seed just so happens to keep the allocation size increasing 1820e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetSeed(rand, 123)); 1830e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSeed(rand)); 1840e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rand)); 1850e6b6b59SJacob Faibussowitsch 1860e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_HOST)); 1870e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_DEVICE)); 1880e6b6b59SJacob Faibussowitsch PetscCall(TestAsyncCoherence(dctx, rand)); 1890e6b6b59SJacob Faibussowitsch 1900e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 1910e6b6b59SJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "EXIT_SUCCESS\n")); 1920e6b6b59SJacob Faibussowitsch PetscCall(PetscFinalize()); 1930e6b6b59SJacob Faibussowitsch return 0; 1940e6b6b59SJacob Faibussowitsch } 1950e6b6b59SJacob Faibussowitsch 1960e6b6b59SJacob Faibussowitsch /*TEST 1970e6b6b59SJacob Faibussowitsch 1980e6b6b59SJacob Faibussowitsch build: 1990e6b6b59SJacob Faibussowitsch requires: defined(PETSC_HAVE_CXX) 2000e6b6b59SJacob Faibussowitsch 2010e6b6b59SJacob Faibussowitsch testset: 2020e6b6b59SJacob Faibussowitsch requires: defined(PETSC_USE_INFO), defined(PETSC_USE_DEBUG) 2030e6b6b59SJacob Faibussowitsch args: -info :device 2040e6b6b59SJacob Faibussowitsch suffix: with_info 2050e6b6b59SJacob Faibussowitsch test: 2060e6b6b59SJacob Faibussowitsch requires: !device 2070e6b6b59SJacob Faibussowitsch suffix: host_no_device 2080e6b6b59SJacob Faibussowitsch test: 2090e6b6b59SJacob Faibussowitsch requires: device 2100e6b6b59SJacob Faibussowitsch args: -default_device_type host 2110e6b6b59SJacob Faibussowitsch filter: sed -e 's/host/IMPL/g' -e 's/cuda/IMPL/g' -e 's/hip/IMPL/g' -e 's/sycl/IMPL/g' 2120e6b6b59SJacob Faibussowitsch suffix: host_with_device 2130e6b6b59SJacob Faibussowitsch test: 2140e6b6b59SJacob Faibussowitsch requires: cuda 2150e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 2160e6b6b59SJacob Faibussowitsch suffix: cuda 2170e6b6b59SJacob Faibussowitsch test: 2180e6b6b59SJacob Faibussowitsch requires: hip 2190e6b6b59SJacob Faibussowitsch args: -default_device_type hip 2200e6b6b59SJacob Faibussowitsch suffix: hip 2210e6b6b59SJacob Faibussowitsch test: 2220e6b6b59SJacob Faibussowitsch requires: sycl 2230e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 2240e6b6b59SJacob Faibussowitsch suffix: sycl 2250e6b6b59SJacob Faibussowitsch 2260e6b6b59SJacob Faibussowitsch testset: 2270e6b6b59SJacob Faibussowitsch output_file: ./output/ExitSuccess.out 2280e6b6b59SJacob Faibussowitsch requires: !defined(PETSC_USE_DEBUG) 2290e6b6b59SJacob Faibussowitsch filter: grep -v "\[DEBUG OUTPUT\]" 2300e6b6b59SJacob Faibussowitsch suffix: no_info 2310e6b6b59SJacob Faibussowitsch test: 2320e6b6b59SJacob Faibussowitsch requires: !device 2330e6b6b59SJacob Faibussowitsch suffix: host_no_device 2340e6b6b59SJacob Faibussowitsch test: 2350e6b6b59SJacob Faibussowitsch requires: device 2360e6b6b59SJacob Faibussowitsch args: -default_device_type host 2370e6b6b59SJacob Faibussowitsch suffix: host_with_device 2380e6b6b59SJacob Faibussowitsch test: 2390e6b6b59SJacob Faibussowitsch requires: cuda 2400e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 2410e6b6b59SJacob Faibussowitsch suffix: cuda 2420e6b6b59SJacob Faibussowitsch test: 2430e6b6b59SJacob Faibussowitsch requires: hip 2440e6b6b59SJacob Faibussowitsch args: -default_device_type hip 2450e6b6b59SJacob Faibussowitsch suffix: hip 2460e6b6b59SJacob Faibussowitsch test: 2470e6b6b59SJacob Faibussowitsch requires: sycl 2480e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 2490e6b6b59SJacob Faibussowitsch suffix: sycl 2500e6b6b59SJacob Faibussowitsch TEST*/ 251