xref: /libCEED/interface/ceed.c (revision dfdf5a531ad639a005f6e2fb19c1b902a7a82be2)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #define _POSIX_C_SOURCE 200112
18d7b241e6Sjeremylt #include <ceed-impl.h>
19d7b241e6Sjeremylt 
20d7b241e6Sjeremylt #include <stdarg.h>
21d7b241e6Sjeremylt #include <stdio.h>
22d7b241e6Sjeremylt #include <stdlib.h>
23d7b241e6Sjeremylt #include <string.h>
24d7b241e6Sjeremylt 
25d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
26d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
27d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
28d7b241e6Sjeremylt 
29d7b241e6Sjeremylt static struct {
30d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
31d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
32d7b241e6Sjeremylt   unsigned int priority;
33d7b241e6Sjeremylt } backends[32];
34d7b241e6Sjeremylt static size_t num_backends;
35d7b241e6Sjeremylt /// @endcond
36d7b241e6Sjeremylt 
37d7b241e6Sjeremylt /// @file
38d7b241e6Sjeremylt /// Implementation of core components of Ceed library
39d7b241e6Sjeremylt ///
40*dfdf5a53Sjeremylt /// @addtogroup Ceed
41d7b241e6Sjeremylt /// @{
42d7b241e6Sjeremylt 
43*dfdf5a53Sjeremylt /**
44*dfdf5a53Sjeremylt   @brief Request immediate completion
45*dfdf5a53Sjeremylt 
46*dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
47*dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
48*dfdf5a53Sjeremylt   immediately.  The code
49*dfdf5a53Sjeremylt 
50*dfdf5a53Sjeremylt   @code
51*dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
52*dfdf5a53Sjeremylt   @endcode
53*dfdf5a53Sjeremylt 
54*dfdf5a53Sjeremylt   is semantically equivalent to
55*dfdf5a53Sjeremylt 
56*dfdf5a53Sjeremylt   @code
57*dfdf5a53Sjeremylt     CeedRequest request;
58*dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
59*dfdf5a53Sjeremylt     CeedRequestWait(&request);
60*dfdf5a53Sjeremylt   @endcode
61*dfdf5a53Sjeremylt 
62*dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
63*dfdf5a53Sjeremylt **/
64d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
65d7b241e6Sjeremylt 
66d7b241e6Sjeremylt /**
67b11c1e72Sjeremylt   @brief Request ordered completion
68d7b241e6Sjeremylt 
69d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
70d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
71d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
72d7b241e6Sjeremylt   such as
73d7b241e6Sjeremylt 
74d7b241e6Sjeremylt   @code
75d7b241e6Sjeremylt     CeedRequest request;
76d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
77d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
78d7b241e6Sjeremylt     // other optional work
79d7b241e6Sjeremylt     CeedWait(&request);
80d7b241e6Sjeremylt   @endcode
81d7b241e6Sjeremylt 
82d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
83d7b241e6Sjeremylt   `op2` until `op1` has completed.
84d7b241e6Sjeremylt 
85d7b241e6Sjeremylt   @fixme The current implementation is overly strict, offering equivalent
86d7b241e6Sjeremylt   semantics to CEED_REQUEST_IMMEDIATE.
87d7b241e6Sjeremylt 
88d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
89d7b241e6Sjeremylt  */
90d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
91d7b241e6Sjeremylt 
92b11c1e72Sjeremylt /**
93b11c1e72Sjeremylt   @brief Error handling implementation; use \ref CeedError instead.
94*dfdf5a53Sjeremylt 
95*dfdf5a53Sjeremylt   @ref Developer
96b11c1e72Sjeremylt **/
97d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
98d7b241e6Sjeremylt                   int ecode, const char *format, ...) {
99d7b241e6Sjeremylt   va_list args;
100d7b241e6Sjeremylt   va_start(args, format);
101d7b241e6Sjeremylt   if (ceed) return ceed->Error(ceed, filename, lineno, func, ecode, format, args);
102d7b241e6Sjeremylt   return CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
103d7b241e6Sjeremylt }
104d7b241e6Sjeremylt 
105b11c1e72Sjeremylt /**
106b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
107b11c1e72Sjeremylt 
108b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
109*dfdf5a53Sjeremylt 
110*dfdf5a53Sjeremylt   @ref Developer
111b11c1e72Sjeremylt **/
112d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
113d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
114d7b241e6Sjeremylt                     va_list args) {
115d7b241e6Sjeremylt   return ecode;
116d7b241e6Sjeremylt }
117d7b241e6Sjeremylt 
118b11c1e72Sjeremylt /**
119b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
120b11c1e72Sjeremylt 
121b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
122*dfdf5a53Sjeremylt 
123*dfdf5a53Sjeremylt   @ref Developer
124b11c1e72Sjeremylt **/
125d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
126d7b241e6Sjeremylt                    const char *func, int ecode,
127d7b241e6Sjeremylt                    const char *format, va_list args) {
128d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
129d7b241e6Sjeremylt   vfprintf(stderr, format, args);
130d7b241e6Sjeremylt   fprintf(stderr, "\n");
131d7b241e6Sjeremylt   abort();
132d7b241e6Sjeremylt   return ecode;
133d7b241e6Sjeremylt }
134d7b241e6Sjeremylt 
135b11c1e72Sjeremylt /**
136*dfdf5a53Sjeremylt   @brief Set error handler
137b11c1e72Sjeremylt 
138b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
139b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
140b11c1e72Sjeremylt   error handler.
141*dfdf5a53Sjeremylt 
142*dfdf5a53Sjeremylt   @ref Developer
143b11c1e72Sjeremylt **/
144d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
145d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
146d7b241e6Sjeremylt                                  int, const char *, va_list)) {
147d7b241e6Sjeremylt   ceed->Error = eh;
148d7b241e6Sjeremylt   return 0;
149d7b241e6Sjeremylt }
150d7b241e6Sjeremylt 
151d7b241e6Sjeremylt /**
152b11c1e72Sjeremylt   @brief Register a Ceed backend
153d7b241e6Sjeremylt 
154d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
155d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
156d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
157d7b241e6Sjeremylt                     is selected to drive the requested resource.
158d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
159d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
160d7b241e6Sjeremylt                     match.
161b11c1e72Sjeremylt 
162b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
163*dfdf5a53Sjeremylt 
164*dfdf5a53Sjeremylt   @ref Advanced
165b11c1e72Sjeremylt **/
166d7b241e6Sjeremylt int CeedRegister(const char *prefix,
167d7b241e6Sjeremylt                  int (*init)(const char *, Ceed), unsigned int priority) {
168d7b241e6Sjeremylt   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
169d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
170d7b241e6Sjeremylt   }
171d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
172d7b241e6Sjeremylt   backends[num_backends].init = init;
173d7b241e6Sjeremylt   backends[num_backends].priority = priority;
174d7b241e6Sjeremylt   num_backends++;
175d7b241e6Sjeremylt   return 0;
176d7b241e6Sjeremylt }
177d7b241e6Sjeremylt 
178b11c1e72Sjeremylt /**
179b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
180b11c1e72Sjeremylt 
181b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
182b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
183b11c1e72Sjeremylt 
184b11c1e72Sjeremylt   @param n Number of units to allocate
185b11c1e72Sjeremylt   @param unit Size of each unit
186b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
187b11c1e72Sjeremylt 
188b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
189b11c1e72Sjeremylt 
190b11c1e72Sjeremylt   @sa CeedFree()
191*dfdf5a53Sjeremylt 
192*dfdf5a53Sjeremylt   @ref Advanced
193b11c1e72Sjeremylt **/
194d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
195d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
196d7b241e6Sjeremylt   if (ierr)
197d7b241e6Sjeremylt     return CeedError(NULL, ierr,
198d7b241e6Sjeremylt                      "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
199d7b241e6Sjeremylt   return 0;
200d7b241e6Sjeremylt }
201d7b241e6Sjeremylt 
202b11c1e72Sjeremylt /**
203b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
204b11c1e72Sjeremylt 
205b11c1e72Sjeremylt   Memory usage can be tracked by the library.
206b11c1e72Sjeremylt 
207b11c1e72Sjeremylt   @param n Number of units to allocate
208b11c1e72Sjeremylt   @param unit Size of each unit
209b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
210b11c1e72Sjeremylt 
211b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
212b11c1e72Sjeremylt 
213b11c1e72Sjeremylt   @sa CeedFree()
214*dfdf5a53Sjeremylt 
215*dfdf5a53Sjeremylt   @ref Advanced
216b11c1e72Sjeremylt **/
217d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
218d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
219d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
220d7b241e6Sjeremylt     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n",
221d7b241e6Sjeremylt                      n, unit);
222d7b241e6Sjeremylt   return 0;
223d7b241e6Sjeremylt }
224d7b241e6Sjeremylt 
225b11c1e72Sjeremylt /**
226b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
227b11c1e72Sjeremylt 
228b11c1e72Sjeremylt   Memory usage can be tracked by the library.
229b11c1e72Sjeremylt 
230b11c1e72Sjeremylt   @param n Number of units to allocate
231b11c1e72Sjeremylt   @param unit Size of each unit
232b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
233b11c1e72Sjeremylt 
234b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
235b11c1e72Sjeremylt 
236b11c1e72Sjeremylt   @sa CeedFree()
237*dfdf5a53Sjeremylt 
238*dfdf5a53Sjeremylt   @ref Advanced
239b11c1e72Sjeremylt **/
240d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
241d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
242d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
243d7b241e6Sjeremylt     return CeedError(NULL, 1,
244d7b241e6Sjeremylt                      "realloc failed to allocate %zd members of size %zd\n",
245d7b241e6Sjeremylt                      n, unit);
246d7b241e6Sjeremylt   return 0;
247d7b241e6Sjeremylt }
248d7b241e6Sjeremylt 
249d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
250d7b241e6Sjeremylt ///
251d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
252d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
253d7b241e6Sjeremylt /// rather than the pointer.
254d7b241e6Sjeremylt int CeedFree(void *p) {
255d7b241e6Sjeremylt   free(*(void **)p);
256d7b241e6Sjeremylt   *(void **)p = NULL;
257d7b241e6Sjeremylt   return 0;
258d7b241e6Sjeremylt }
259d7b241e6Sjeremylt 
260d7b241e6Sjeremylt /**
261b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
262d7b241e6Sjeremylt 
263d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
264d7b241e6Sjeremylt 
265d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
266b11c1e72Sjeremylt 
267b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
268*dfdf5a53Sjeremylt 
269*dfdf5a53Sjeremylt   @ref Advanced
270b11c1e72Sjeremylt **/
271d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
272d7b241e6Sjeremylt   if (!*req) return 0;
273d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
274d7b241e6Sjeremylt }
275d7b241e6Sjeremylt 
276b11c1e72Sjeremylt /**
277b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
278b11c1e72Sjeremylt 
279b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
280b11c1e72Sjeremylt   @param ceed The library context
281b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
282b11c1e72Sjeremylt 
283b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
284*dfdf5a53Sjeremylt 
285*dfdf5a53Sjeremylt   @ref Basic
286b11c1e72Sjeremylt **/
287d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
288d7b241e6Sjeremylt   int ierr;
289d7b241e6Sjeremylt   size_t matchlen = 0, matchidx;
290d7b241e6Sjeremylt   unsigned int matchpriority = 100, priority;
291d7b241e6Sjeremylt 
292d7b241e6Sjeremylt   if (!resource) return CeedError(NULL, 1, "No resource provided");
293d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
294d7b241e6Sjeremylt     size_t n;
295d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
296d7b241e6Sjeremylt     for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {}
297d7b241e6Sjeremylt     priority = backends[i].priority;
298d7b241e6Sjeremylt     if (n > matchlen || (n == matchlen && matchpriority > priority)) {
299d7b241e6Sjeremylt       matchlen = n;
300d7b241e6Sjeremylt       matchpriority = priority;
301d7b241e6Sjeremylt       matchidx = i;
302d7b241e6Sjeremylt     }
303d7b241e6Sjeremylt   }
304d7b241e6Sjeremylt   if (!matchlen) return CeedError(NULL, 1, "No suitable backend");
305d7b241e6Sjeremylt   ierr = CeedCalloc(1,ceed); CeedChk(ierr);
306d7b241e6Sjeremylt   (*ceed)->Error = CeedErrorAbort;
307d7b241e6Sjeremylt   (*ceed)->refcount = 1;
308d7b241e6Sjeremylt   (*ceed)->data = NULL;
309d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
310d7b241e6Sjeremylt   return 0;
311d7b241e6Sjeremylt }
312d7b241e6Sjeremylt 
313d7b241e6Sjeremylt /**
314b11c1e72Sjeremylt   @brief Destroy a Ceed context
315d7b241e6Sjeremylt 
316d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
317b11c1e72Sjeremylt 
318b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
319*dfdf5a53Sjeremylt 
320*dfdf5a53Sjeremylt   @ref Basic
321b11c1e72Sjeremylt **/
322d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
323d7b241e6Sjeremylt   int ierr;
324d7b241e6Sjeremylt 
325d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
326d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
327d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
328d7b241e6Sjeremylt   }
329d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
330d7b241e6Sjeremylt   return 0;
331d7b241e6Sjeremylt }
332d7b241e6Sjeremylt 
333d7b241e6Sjeremylt /// @}
334