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 7d71ae5a4SJacob Faibussowitsch static PetscErrorCode IncrementSize(PetscRandom rand, PetscInt *value) 8d71ae5a4SJacob Faibussowitsch { 90e6b6b59SJacob Faibussowitsch PetscReal rval; 100e6b6b59SJacob Faibussowitsch 110e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 120e6b6b59SJacob Faibussowitsch // set the interval such that *value += rval never goes below 0 or above 500 130e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetInterval(rand, -(*value), 500 - (*value))); 140e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomGetValueReal(rand, &rval)); 150e6b6b59SJacob Faibussowitsch *value += (PetscInt)rval; 160e6b6b59SJacob Faibussowitsch PetscCall(DebugPrintf(PetscObjectComm((PetscObject)rand), "n: %" PetscInt_FMT "\n", *value)); 173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 180e6b6b59SJacob Faibussowitsch } 190e6b6b59SJacob Faibussowitsch 20d71ae5a4SJacob Faibussowitsch static PetscErrorCode TestAllocate(PetscDeviceContext dctx, PetscRandom rand, PetscMemType mtype) 21d71ae5a4SJacob Faibussowitsch { 220e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 230e6b6b59SJacob Faibussowitsch PetscInt n = 10; 240e6b6b59SJacob Faibussowitsch 250e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 260e6b6b59SJacob Faibussowitsch if (PetscMemTypeDevice(mtype)) { 270e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 280e6b6b59SJacob Faibussowitsch 290e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 300e6b6b59SJacob Faibussowitsch // host device context cannot handle this 313ba16761SJacob Faibussowitsch if (dtype == PETSC_DEVICE_HOST) PetscFunctionReturn(PETSC_SUCCESS); 320e6b6b59SJacob Faibussowitsch } 330e6b6b59SJacob Faibussowitsch // test basic allocation, deallocation 340e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 350e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 360e6b6b59SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceMalloc() return NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 376797ed33SJacob Faibussowitsch // this ensures the host pointer is at least valid 380e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 390e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) ptr[i] = (PetscScalar)i; 400e6b6b59SJacob Faibussowitsch } 410e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 420e6b6b59SJacob Faibussowitsch 436797ed33SJacob Faibussowitsch // test alignment of various types 446797ed33SJacob Faibussowitsch { 456797ed33SJacob Faibussowitsch char *char_ptr; 466797ed33SJacob Faibussowitsch short *short_ptr; 476797ed33SJacob Faibussowitsch int *int_ptr; 486797ed33SJacob Faibussowitsch double *double_ptr; 496797ed33SJacob Faibussowitsch long int *long_int_ptr; 506797ed33SJacob Faibussowitsch 516797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &char_ptr)); 526797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &short_ptr)); 536797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &int_ptr)); 546797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &double_ptr)); 556797ed33SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, 1, &long_int_ptr)); 566797ed33SJacob Faibussowitsch 576797ed33SJacob Faibussowitsch // if an error occurs here, it means the alignment system is broken! 586797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, char_ptr)); 596797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, short_ptr)); 606797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, int_ptr)); 616797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, double_ptr)); 626797ed33SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, long_int_ptr)); 636797ed33SJacob Faibussowitsch } 646797ed33SJacob Faibussowitsch 650e6b6b59SJacob Faibussowitsch // test that calloc() produces cleared memory 660e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 670e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, mtype, n, &ptr)); 686797ed33SJacob Faibussowitsch PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_POINTER, "PetscDeviceCalloc() returned NULL pointer for %s allocation size %" PetscInt_FMT, PetscMemTypeToString(mtype), n); 690e6b6b59SJacob Faibussowitsch if (PetscMemTypeHost(mtype)) { 700e6b6b59SJacob Faibussowitsch tmp_ptr = ptr; 710e6b6b59SJacob Faibussowitsch } else { 720e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 730e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 740e6b6b59SJacob Faibussowitsch } 756797ed33SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 760e6b6b59SJacob 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])); 770e6b6b59SJacob Faibussowitsch if (tmp_ptr == ptr) { 780e6b6b59SJacob Faibussowitsch tmp_ptr = NULL; 790e6b6b59SJacob Faibussowitsch } else { 800e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 810e6b6b59SJacob Faibussowitsch } 820e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 830e6b6b59SJacob Faibussowitsch 840e6b6b59SJacob Faibussowitsch // test that devicearrayzero produces cleared memory 850e6b6b59SJacob Faibussowitsch PetscCall(IncrementSize(rand, &n)); 860e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, mtype, n, &ptr)); 870e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(dctx, ptr, n)); 880e6b6b59SJacob Faibussowitsch PetscCall(PetscMalloc1(n, &tmp_ptr)); 890e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceRegisterMemory(tmp_ptr, PETSC_MEMTYPE_HOST, n * sizeof(*tmp_ptr))); 900e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) tmp_ptr[i] = (PetscScalar)i; 910e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(dctx, tmp_ptr, ptr, n)); 920e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(dctx)); 9315229ffcSPierre Jolivet for (PetscInt i = 0; i < n; ++i) PetscCheck(tmp_ptr[i] == (PetscScalar)0.0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDeviceArrayZero() did not clear memory, ptr[%" PetscInt_FMT "] %g != 0", i, (double)PetscAbsScalar(tmp_ptr[i])); 940e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, tmp_ptr)); 950e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(dctx, ptr)); 963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 970e6b6b59SJacob Faibussowitsch } 980e6b6b59SJacob Faibussowitsch 99d71ae5a4SJacob Faibussowitsch static PetscErrorCode TestAsyncCoherence(PetscDeviceContext dctx, PetscRandom rand) 100d71ae5a4SJacob Faibussowitsch { 1010e6b6b59SJacob Faibussowitsch const PetscInt nsub = 2; 1020e6b6b59SJacob Faibussowitsch const PetscInt n = 1024; 1030e6b6b59SJacob Faibussowitsch PetscScalar *ptr, *tmp_ptr; 1040e6b6b59SJacob Faibussowitsch PetscDeviceType dtype; 1050e6b6b59SJacob Faibussowitsch PetscDeviceContext *sub; 1060e6b6b59SJacob Faibussowitsch 1070e6b6b59SJacob Faibussowitsch PetscFunctionBegin; 1080e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetDeviceType(dctx, &dtype)); 1090e6b6b59SJacob Faibussowitsch // ensure the streams are nonblocking 110*d9acb416SHong Zhang PetscCall(PetscDeviceContextForkWithStreamType(dctx, PETSC_STREAM_NONBLOCKING, nsub, &sub)); 1110e6b6b59SJacob Faibussowitsch // do a warmup to ensure each context acquires any necessary data structures 1120e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < nsub; ++i) { 1130e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_HOST, n, &ptr)); 1140e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 1150e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 1160e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[i], PETSC_MEMTYPE_DEVICE, n, &ptr)); 1170e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[i], ptr)); 1180e6b6b59SJacob Faibussowitsch } 1190e6b6b59SJacob Faibussowitsch } 1200e6b6b59SJacob Faibussowitsch 1210e6b6b59SJacob Faibussowitsch // allocate on one 1220e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 1230e6b6b59SJacob Faibussowitsch // free on the other 1240e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1250e6b6b59SJacob Faibussowitsch 1260e6b6b59SJacob Faibussowitsch // allocate on one 1270e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(sub[0], PETSC_MEMTYPE_HOST, n, &ptr)); 1280e6b6b59SJacob Faibussowitsch // zero on the other 1290e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayZero(sub[1], ptr, n)); 1300e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[1])); 1310e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 1320e6b6b59SJacob 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])); 1330e6b6b59SJacob Faibussowitsch } 1340e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1350e6b6b59SJacob Faibussowitsch 1360e6b6b59SJacob Faibussowitsch // test the transfers are serialized 1370e6b6b59SJacob Faibussowitsch if (dtype != PETSC_DEVICE_HOST) { 1380e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceCalloc(dctx, PETSC_MEMTYPE_DEVICE, n, &ptr)); 1390e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceMalloc(dctx, PETSC_MEMTYPE_HOST, n, &tmp_ptr)); 1400e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceArrayCopy(sub[0], tmp_ptr, ptr, n)); 1410e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextSynchronize(sub[0])); 1420e6b6b59SJacob Faibussowitsch for (PetscInt i = 0; i < n; ++i) { 1430e6b6b59SJacob 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])); 1440e6b6b59SJacob Faibussowitsch } 1450e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceFree(sub[1], ptr)); 1460e6b6b59SJacob Faibussowitsch } 1470e6b6b59SJacob Faibussowitsch 1480e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextJoin(dctx, nsub, PETSC_DEVICE_CONTEXT_JOIN_DESTROY, &sub)); 1493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1500e6b6b59SJacob Faibussowitsch } 1510e6b6b59SJacob Faibussowitsch 152d71ae5a4SJacob Faibussowitsch int main(int argc, char *argv[]) 153d71ae5a4SJacob Faibussowitsch { 1540e6b6b59SJacob Faibussowitsch PetscDeviceContext dctx; 1550e6b6b59SJacob Faibussowitsch PetscRandom rand; 1560e6b6b59SJacob Faibussowitsch 1570e6b6b59SJacob Faibussowitsch PetscFunctionBeginUser; 1580e6b6b59SJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 1590e6b6b59SJacob Faibussowitsch 1600e6b6b59SJacob Faibussowitsch // A vile hack. The -info output is used to test correctness in this test which prints -- 1610e6b6b59SJacob Faibussowitsch // among other things -- the PetscObjectId of the PetscDevicContext and the allocated memory. 1620e6b6b59SJacob Faibussowitsch // 1630e6b6b59SJacob Faibussowitsch // Due to device and host creating slightly different number of objects on startup there will 1640e6b6b59SJacob Faibussowitsch // be a mismatch in the ID's. So for the tests involving the host we sit here creating 1650e6b6b59SJacob Faibussowitsch // PetscContainers (and incrementing the global PetscObjectId counter) until it reaches some 1660e6b6b59SJacob Faibussowitsch // arbitrarily high number to ensure that our first PetscDeviceContext has the same ID across 1670e6b6b59SJacob Faibussowitsch // systems. 168146a86ebSJacob Faibussowitsch { 169146a86ebSJacob Faibussowitsch PetscObjectId prev_id = 0; 1700e6b6b59SJacob Faibussowitsch 1710e6b6b59SJacob Faibussowitsch do { 1720e6b6b59SJacob Faibussowitsch PetscContainer c; 173146a86ebSJacob Faibussowitsch PetscObjectId id; 1740e6b6b59SJacob Faibussowitsch 1750e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, &c)); 1760e6b6b59SJacob Faibussowitsch PetscCall(PetscObjectGetId((PetscObject)c, &id)); 1770e6b6b59SJacob Faibussowitsch // sanity check, in case PetscContainer ever stops being a PetscObject 1780e6b6b59SJacob 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); 1790e6b6b59SJacob Faibussowitsch prev_id = id; 1800e6b6b59SJacob Faibussowitsch PetscCall(PetscContainerDestroy(&c)); 181146a86ebSJacob Faibussowitsch } while (prev_id < 50); 1820e6b6b59SJacob Faibussowitsch } 1830e6b6b59SJacob Faibussowitsch PetscCall(PetscDeviceContextGetCurrentContext(&dctx)); 1840e6b6b59SJacob Faibussowitsch 1850e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand)); 1860e6b6b59SJacob Faibussowitsch // this seed just so happens to keep the allocation size increasing 1870e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetSeed(rand, 123)); 1880e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSeed(rand)); 1890e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rand)); 1900e6b6b59SJacob Faibussowitsch 1910e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_HOST)); 1920e6b6b59SJacob Faibussowitsch PetscCall(TestAllocate(dctx, rand, PETSC_MEMTYPE_DEVICE)); 1930e6b6b59SJacob Faibussowitsch PetscCall(TestAsyncCoherence(dctx, rand)); 1940e6b6b59SJacob Faibussowitsch 1950e6b6b59SJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 1960e6b6b59SJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "EXIT_SUCCESS\n")); 1970e6b6b59SJacob Faibussowitsch PetscCall(PetscFinalize()); 1980e6b6b59SJacob Faibussowitsch return 0; 1990e6b6b59SJacob Faibussowitsch } 2000e6b6b59SJacob Faibussowitsch 2010e6b6b59SJacob Faibussowitsch /*TEST 2020e6b6b59SJacob Faibussowitsch 2030e6b6b59SJacob Faibussowitsch testset: 2044c073473SPierre Jolivet requires: defined(PETSC_USE_INFO) defined(PETSC_USE_DEBUG) cxx 2050e6b6b59SJacob Faibussowitsch args: -info :device 2060e6b6b59SJacob Faibussowitsch suffix: with_info 2070e6b6b59SJacob Faibussowitsch test: 2080e6b6b59SJacob Faibussowitsch requires: !device 2090e6b6b59SJacob Faibussowitsch suffix: host_no_device 2100e6b6b59SJacob Faibussowitsch test: 2110e6b6b59SJacob Faibussowitsch requires: device 2120e6b6b59SJacob Faibussowitsch args: -default_device_type host 2130e6b6b59SJacob Faibussowitsch filter: sed -e 's/host/IMPL/g' -e 's/cuda/IMPL/g' -e 's/hip/IMPL/g' -e 's/sycl/IMPL/g' 2140e6b6b59SJacob Faibussowitsch suffix: host_with_device 2150e6b6b59SJacob Faibussowitsch test: 2160e6b6b59SJacob Faibussowitsch requires: cuda 2170e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 2180e6b6b59SJacob Faibussowitsch suffix: cuda 2190e6b6b59SJacob Faibussowitsch test: 2200e6b6b59SJacob Faibussowitsch requires: hip 2210e6b6b59SJacob Faibussowitsch args: -default_device_type hip 2220e6b6b59SJacob Faibussowitsch suffix: hip 2230e6b6b59SJacob Faibussowitsch test: 2240e6b6b59SJacob Faibussowitsch requires: sycl 2250e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 2260e6b6b59SJacob Faibussowitsch suffix: sycl 2270e6b6b59SJacob Faibussowitsch 2280e6b6b59SJacob Faibussowitsch testset: 2290e6b6b59SJacob Faibussowitsch output_file: ./output/ExitSuccess.out 2300e6b6b59SJacob Faibussowitsch requires: !defined(PETSC_USE_DEBUG) 2310e6b6b59SJacob Faibussowitsch filter: grep -v "\[DEBUG OUTPUT\]" 2320e6b6b59SJacob Faibussowitsch suffix: no_info 2330e6b6b59SJacob Faibussowitsch test: 2340e6b6b59SJacob Faibussowitsch requires: !device 2350e6b6b59SJacob Faibussowitsch suffix: host_no_device 2360e6b6b59SJacob Faibussowitsch test: 2370e6b6b59SJacob Faibussowitsch requires: device 2380e6b6b59SJacob Faibussowitsch args: -default_device_type host 2390e6b6b59SJacob Faibussowitsch suffix: host_with_device 2400e6b6b59SJacob Faibussowitsch test: 2410e6b6b59SJacob Faibussowitsch requires: cuda 2420e6b6b59SJacob Faibussowitsch args: -default_device_type cuda 2430e6b6b59SJacob Faibussowitsch suffix: cuda 2440e6b6b59SJacob Faibussowitsch test: 2450e6b6b59SJacob Faibussowitsch requires: hip 2460e6b6b59SJacob Faibussowitsch args: -default_device_type hip 2470e6b6b59SJacob Faibussowitsch suffix: hip 2480e6b6b59SJacob Faibussowitsch test: 2490e6b6b59SJacob Faibussowitsch requires: sycl 2500e6b6b59SJacob Faibussowitsch args: -default_device_type sycl 2510e6b6b59SJacob Faibussowitsch suffix: sycl 252667ab0feSJacob Faibussowitsch 253667ab0feSJacob Faibussowitsch test: 254667ab0feSJacob Faibussowitsch requires: !cxx 255667ab0feSJacob Faibussowitsch output_file: ./output/ExitSuccess.out 256667ab0feSJacob Faibussowitsch filter: grep -v "\[DEBUG OUTPUT\]" 257667ab0feSJacob Faibussowitsch suffix: no_cxx 258667ab0feSJacob Faibussowitsch 2590e6b6b59SJacob Faibussowitsch TEST*/ 260