xref: /petsc/src/sys/objects/device/tests/ex7.c (revision 0e6b6b5985dd9b1172860d21fb88bd3966bf7c54)
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