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