1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #define _POSIX_C_SOURCE 200112 18 #include <ceed.h> 19 #include <ceed-backend.h> 20 #include <ceed-impl.h> 21 #include <limits.h> 22 #include <stdarg.h> 23 #include <stddef.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 /// @cond DOXYGEN_SKIP 29 static CeedRequest ceed_request_immediate; 30 static CeedRequest ceed_request_ordered; 31 32 static struct { 33 char prefix[CEED_MAX_RESOURCE_LEN]; 34 int (*init)(const char *resource, Ceed f); 35 unsigned int priority; 36 } backends[32]; 37 static size_t num_backends; 38 39 #define CEED_FTABLE_ENTRY(class, method) \ 40 {#class #method, offsetof(struct class ##_private, method)} 41 /// @endcond 42 43 /// @file 44 /// Implementation of core components of Ceed library 45 46 /// @addtogroup CeedUser 47 /// @{ 48 49 /** 50 @brief Request immediate completion 51 52 This predefined constant is passed as the \ref CeedRequest argument to 53 interfaces when the caller wishes for the operation to be performed 54 immediately. The code 55 56 @code 57 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 58 @endcode 59 60 is semantically equivalent to 61 62 @code 63 CeedRequest request; 64 CeedOperatorApply(op, ..., &request); 65 CeedRequestWait(&request); 66 @endcode 67 68 @sa CEED_REQUEST_ORDERED 69 **/ 70 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 71 72 /** 73 @brief Request ordered completion 74 75 This predefined constant is passed as the \ref CeedRequest argument to 76 interfaces when the caller wishes for the operation to be completed in the 77 order that it is submitted to the device. It is typically used in a construct 78 such as 79 80 @code 81 CeedRequest request; 82 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 83 CeedOperatorApply(op2, ..., &request); 84 // other optional work 85 CeedWait(&request); 86 @endcode 87 88 which allows the sequence to complete asynchronously but does not start 89 `op2` until `op1` has completed. 90 91 @todo The current implementation is overly strict, offering equivalent 92 semantics to @ref CEED_REQUEST_IMMEDIATE. 93 94 @sa CEED_REQUEST_IMMEDIATE 95 */ 96 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 97 98 /** 99 @brief Wait for a CeedRequest to complete. 100 101 Calling CeedRequestWait on a NULL request is a no-op. 102 103 @param req Address of CeedRequest to wait for; zeroed on completion. 104 105 @return An error code: 0 - success, otherwise - failure 106 107 @ref User 108 **/ 109 int CeedRequestWait(CeedRequest *req) { 110 if (!*req) 111 return 0; 112 return CeedError(NULL, 2, "CeedRequestWait not implemented"); 113 } 114 115 /// @} 116 117 /// ---------------------------------------------------------------------------- 118 /// Ceed Library Internal Functions 119 /// ---------------------------------------------------------------------------- 120 /// @addtogroup CeedDeveloper 121 /// @{ 122 123 /// @} 124 125 /// ---------------------------------------------------------------------------- 126 /// Ceed Backend API 127 /// ---------------------------------------------------------------------------- 128 /// @addtogroup CeedBackend 129 /// @{ 130 131 /** 132 @brief Print Ceed debugging information 133 134 @param ceed Ceed context 135 @param format Printing format 136 137 @return None 138 139 @ref Backend 140 **/ 141 // LCOV_EXCL_START 142 void CeedDebugImpl(const Ceed ceed, const char *format,...) { 143 if (!ceed->debug) return; 144 va_list args; 145 va_start(args, format); 146 CeedDebugImpl256(ceed, 0, format, args); 147 va_end(args); 148 } 149 // LCOV_EXCL_STOP 150 151 /** 152 @brief Print Ceed debugging information in color 153 154 @param ceed Ceed context 155 @param color Color to print 156 @param format Printing format 157 158 @return None 159 160 @ref Backend 161 **/ 162 // LCOV_EXCL_START 163 void CeedDebugImpl256(const Ceed ceed, const unsigned char color, 164 const char *format,...) { 165 if (!ceed->debug) return; 166 va_list args; 167 va_start(args, format); 168 fflush(stdout); 169 fprintf(stdout, "\033[38;5;%dm", color); 170 vfprintf(stdout, format, args); 171 fprintf(stdout, "\033[m"); 172 fprintf(stdout, "\n"); 173 fflush(stdout); 174 va_end(args); 175 } 176 // LCOV_EXCL_STOP 177 178 /** 179 @brief Allocate an array on the host; use CeedMalloc() 180 181 Memory usage can be tracked by the library. This ensures sufficient 182 alignment for vectorization and should be used for large allocations. 183 184 @param n Number of units to allocate 185 @param unit Size of each unit 186 @param p Address of pointer to hold the result. 187 188 @return An error code: 0 - success, otherwise - failure 189 190 @sa CeedFree() 191 192 @ref Backend 193 **/ 194 int CeedMallocArray(size_t n, size_t unit, void *p) { 195 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 196 if (ierr) 197 // LCOV_EXCL_START 198 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 199 "members of size %zd\n", n, unit); 200 // LCOV_EXCL_STOP 201 202 return 0; 203 } 204 205 /** 206 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 207 208 Memory usage can be tracked by the library. 209 210 @param n Number of units to allocate 211 @param unit Size of each unit 212 @param p Address of pointer to hold the result. 213 214 @return An error code: 0 - success, otherwise - failure 215 216 @sa CeedFree() 217 218 @ref Backend 219 **/ 220 int CeedCallocArray(size_t n, size_t unit, void *p) { 221 *(void **)p = calloc(n, unit); 222 if (n && unit && !*(void **)p) 223 // LCOV_EXCL_START 224 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 225 "%zd\n", n, unit); 226 // LCOV_EXCL_STOP 227 228 return 0; 229 } 230 231 /** 232 @brief Reallocate an array on the host; use CeedRealloc() 233 234 Memory usage can be tracked by the library. 235 236 @param n Number of units to allocate 237 @param unit Size of each unit 238 @param p Address of pointer to hold the result. 239 240 @return An error code: 0 - success, otherwise - failure 241 242 @sa CeedFree() 243 244 @ref Backend 245 **/ 246 int CeedReallocArray(size_t n, size_t unit, void *p) { 247 *(void **)p = realloc(*(void **)p, n*unit); 248 if (n && unit && !*(void **)p) 249 // LCOV_EXCL_START 250 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 251 "%zd\n", n, unit); 252 // LCOV_EXCL_STOP 253 254 return 0; 255 } 256 257 /** Free memory allocated using CeedMalloc() or CeedCalloc() 258 259 @param p address of pointer to memory. This argument is of type void* to 260 avoid needing a cast, but is the address of the pointer (which is 261 zeroed) rather than the pointer. 262 **/ 263 int CeedFree(void *p) { 264 free(*(void **)p); 265 *(void **)p = NULL; 266 return 0; 267 } 268 269 /** 270 @brief Register a Ceed backend 271 272 @param prefix Prefix of resources for this backend to respond to. For 273 example, the reference backend responds to "/cpu/self". 274 @param init Initialization function called by CeedInit() when the backend 275 is selected to drive the requested resource. 276 @param priority Integer priority. Lower values are preferred in case the 277 resource requested by CeedInit() has non-unique best prefix 278 match. 279 280 @return An error code: 0 - success, otherwise - failure 281 282 @ref Backend 283 **/ 284 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 285 unsigned int priority) { 286 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 287 // LCOV_EXCL_START 288 return CeedError(NULL, 1, "Too many backends"); 289 // LCOV_EXCL_STOP 290 291 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 292 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 293 backends[num_backends].init = init; 294 backends[num_backends].priority = priority; 295 num_backends++; 296 return 0; 297 } 298 299 /** 300 @brief Return debugging status flag 301 302 @param ceed Ceed context to get debugging flag 303 @param isDebug Variable to store debugging flag 304 305 @return An error code: 0 - success, otherwise - failure 306 307 @ref Bcakend 308 **/ 309 int CeedIsDebug(Ceed ceed, bool *isDebug) { 310 *isDebug = ceed->debug; 311 return 0; 312 } 313 314 /** 315 @brief Retrieve a parent Ceed context 316 317 @param ceed Ceed context to retrieve parent of 318 @param[out] parent Address to save the parent to 319 320 @return An error code: 0 - success, otherwise - failure 321 322 @ref Backend 323 **/ 324 int CeedGetParent(Ceed ceed, Ceed *parent) { 325 int ierr; 326 if (ceed->parent) { 327 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 328 return 0; 329 } 330 *parent = ceed; 331 return 0; 332 } 333 334 /** 335 @brief Retrieve a delegate Ceed context 336 337 @param ceed Ceed context to retrieve delegate of 338 @param[out] delegate Address to save the delegate to 339 340 @return An error code: 0 - success, otherwise - failure 341 342 @ref Backend 343 **/ 344 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 345 *delegate = ceed->delegate; 346 return 0; 347 } 348 349 /** 350 @brief Set a delegate Ceed context 351 352 This function allows a Ceed context to set a delegate Ceed context. All 353 backend implementations default to the delegate Ceed context, unless 354 overridden. 355 356 @param ceed Ceed context to set delegate of 357 @param[out] delegate Address to set the delegate to 358 359 @return An error code: 0 - success, otherwise - failure 360 361 @ref Backend 362 **/ 363 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 364 ceed->delegate = delegate; 365 delegate->parent = ceed; 366 return 0; 367 } 368 369 /** 370 @brief Retrieve a delegate Ceed context for a specific object type 371 372 @param ceed Ceed context to retrieve delegate of 373 @param[out] delegate Address to save the delegate to 374 @param[in] objname Name of the object type to retrieve delegate for 375 376 @return An error code: 0 - success, otherwise - failure 377 378 @ref Backend 379 **/ 380 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 381 CeedInt ierr; 382 383 // Check for object delegate 384 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 385 if (!strcmp(objname, ceed->objdelegates->objname)) { 386 *delegate = ceed->objdelegates->delegate; 387 return 0; 388 } 389 390 // Use default delegate if no object delegate 391 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 392 393 return 0; 394 } 395 396 /** 397 @brief Set a delegate Ceed context for a specific object type 398 399 This function allows a Ceed context to set a delegate Ceed context for a 400 given type of Ceed object. All backend implementations default to the 401 delegate Ceed context for this object. For example, 402 CeedSetObjectDelegate(ceed, refceed, "Basis") 403 uses refceed implementations for all CeedBasis backend functions. 404 405 @param ceed Ceed context to set delegate of 406 @param[out] delegate Address to set the delegate to 407 @param[in] objname Name of the object type to set delegate for 408 409 @return An error code: 0 - success, otherwise - failure 410 411 @ref Backend 412 **/ 413 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 414 CeedInt ierr; 415 CeedInt count = ceed->objdelegatecount; 416 417 // Malloc or Realloc 418 if (count) { 419 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 420 } else { 421 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 422 } 423 ceed->objdelegatecount++; 424 425 // Set object delegate 426 ceed->objdelegates[count].delegate = delegate; 427 size_t slen = strlen(objname) + 1; 428 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 429 memcpy(ceed->objdelegates[count].objname, objname, slen); 430 431 // Set delegate parent 432 delegate->parent = ceed; 433 434 return 0; 435 } 436 437 /** 438 @brief Get the fallback resource for CeedOperators 439 440 @param ceed Ceed context 441 @param[out] resource Variable to store fallback resource 442 443 @return An error code: 0 - success, otherwise - failure 444 445 @ref Backend 446 **/ 447 448 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 449 *resource = (const char *)ceed->opfallbackresource; 450 return 0; 451 } 452 453 /** 454 @brief Set the fallback resource for CeedOperators. The current resource, if 455 any, is freed by calling this function. This string is freed upon the 456 destruction of the Ceed context. 457 458 @param[out] ceed Ceed context 459 @param resource Fallback resource to set 460 461 @return An error code: 0 - success, otherwise - failure 462 463 @ref Backend 464 **/ 465 466 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 467 int ierr; 468 469 // Free old 470 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 471 472 // Set new 473 size_t len = strlen(resource); 474 char *tmp; 475 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 476 memcpy(tmp, resource, len+1); 477 ceed->opfallbackresource = tmp; 478 479 return 0; 480 } 481 482 /** 483 @brief Get the parent Ceed context associated with a fallback Ceed context 484 for a CeedOperator 485 486 @param ceed Ceed context 487 @param[out] parent Variable to store parent Ceed context 488 489 @return An error code: 0 - success, otherwise - failure 490 491 @ref Backend 492 **/ 493 494 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 495 *parent = ceed->opfallbackparent; 496 return 0; 497 } 498 499 /** 500 @brief Flag Ceed context as deterministic 501 502 @param ceed Ceed to flag as deterministic 503 504 @return An error code: 0 - success, otherwise - failure 505 506 @ref Backend 507 **/ 508 509 int CeedSetDeterministic(Ceed ceed, bool isDeterministic) { 510 ceed->isDeterministic = isDeterministic; 511 return 0; 512 } 513 514 /** 515 @brief Set a backend function 516 517 This function is used for a backend to set the function associated with 518 the Ceed objects. For example, 519 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 520 sets the backend implementation of 'CeedVectorCreate' and 521 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 522 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 523 is not required for the object type ("Basis" vs "CeedBasis"). 524 525 @param ceed Ceed context for error handling 526 @param type Type of Ceed object to set function for 527 @param[out] object Ceed object to set function for 528 @param fname Name of function to set 529 @param f Function to set 530 531 @return An error code: 0 - success, otherwise - failure 532 533 @ref Backend 534 **/ 535 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 536 const char *fname, int (*f)()) { 537 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 538 539 // Build lookup name 540 if (strcmp(type, "Ceed")) 541 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 542 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 543 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 544 545 // Find and use offset 546 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 547 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 548 size_t offset = ceed->foffsets[i].offset; 549 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 550 *fpointer = f; 551 return 0; 552 } 553 554 // LCOV_EXCL_START 555 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 556 "object '%s'", fname, type); 557 // LCOV_EXCL_STOP 558 } 559 560 /** 561 @brief Retrieve backend data for a Ceed context 562 563 @param ceed Ceed context to retrieve data of 564 @param[out] data Address to save data to 565 566 @return An error code: 0 - success, otherwise - failure 567 568 @ref Backend 569 **/ 570 int CeedGetData(Ceed ceed, void *data) { 571 *(void **)data = ceed->data; 572 return 0; 573 } 574 575 /** 576 @brief Set backend data for a Ceed context 577 578 @param ceed Ceed context to set data of 579 @param data Address of data to set 580 581 @return An error code: 0 - success, otherwise - failure 582 583 @ref Backend 584 **/ 585 int CeedSetData(Ceed ceed, void *data) { 586 ceed->data = data; 587 return 0; 588 } 589 590 /// @} 591 592 /// ---------------------------------------------------------------------------- 593 /// Ceed Public API 594 /// ---------------------------------------------------------------------------- 595 /// @addtogroup CeedUser 596 /// @{ 597 598 /** 599 @brief Initialize a \ref Ceed context to use the specified resource. 600 601 @param resource Resource to use, e.g., "/cpu/self" 602 @param ceed The library context 603 @sa CeedRegister() CeedDestroy() 604 605 @return An error code: 0 - success, otherwise - failure 606 607 @ref User 608 **/ 609 int CeedInit(const char *resource, Ceed *ceed) { 610 int ierr; 611 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 612 613 // Find matching backend 614 if (!resource) 615 // LCOV_EXCL_START 616 return CeedError(NULL, 1, "No resource provided"); 617 // LCOV_EXCL_STOP 618 ierr = CeedRegisterAll(); CeedChk(ierr); 619 620 for (size_t i=0; i<num_backends; i++) { 621 size_t n; 622 const char *prefix = backends[i].prefix; 623 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 624 priority = backends[i].priority; 625 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 626 matchlen = n; 627 matchpriority = priority; 628 matchidx = i; 629 } 630 } 631 if (matchlen <= 1) 632 // LCOV_EXCL_START 633 return CeedError(NULL, 1, "No suitable backend: %s", resource); 634 // LCOV_EXCL_STOP 635 636 // Setup Ceed 637 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 638 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 639 if (!ceed_error_handler) 640 ceed_error_handler = "abort"; 641 if (!strcmp(ceed_error_handler, "exit")) 642 (*ceed)->Error = CeedErrorExit; 643 else if (!strcmp(ceed_error_handler, "store")) 644 (*ceed)->Error = CeedErrorStore; 645 else 646 (*ceed)->Error = CeedErrorAbort; 647 memcpy((*ceed)->errmsg, "No error message stored", 24); 648 (*ceed)->refcount = 1; 649 (*ceed)->data = NULL; 650 651 // Set lookup table 652 foffset foffsets[] = { 653 CEED_FTABLE_ENTRY(Ceed, Error), 654 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 655 CEED_FTABLE_ENTRY(Ceed, Destroy), 656 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 657 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 658 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 659 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 660 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 661 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 662 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 663 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 664 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 665 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 666 CEED_FTABLE_ENTRY(CeedVector, SetArray), 667 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 668 CEED_FTABLE_ENTRY(CeedVector, SetValue), 669 CEED_FTABLE_ENTRY(CeedVector, GetArray), 670 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 671 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 672 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 673 CEED_FTABLE_ENTRY(CeedVector, Norm), 674 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 675 CEED_FTABLE_ENTRY(CeedVector, Destroy), 676 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 677 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 678 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 679 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 680 CEED_FTABLE_ENTRY(CeedBasis, Apply), 681 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 682 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 683 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 684 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 685 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 686 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 687 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 688 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 689 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 690 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 691 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 692 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 693 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 694 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 695 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 696 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 697 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 698 CEED_FTABLE_ENTRY(CeedOperator, Apply), 699 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 700 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 701 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 702 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 703 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 704 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 705 }; 706 707 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 708 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 709 710 // Set fallback for advanced CeedOperator functions 711 const char fallbackresource[] = "/cpu/self/ref/serial"; 712 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 713 CeedChk(ierr); 714 715 // Record env variables CEED_DEBUG or DBG 716 (*ceed)->debug = !!getenv("CEED_DEBUG") || !!getenv("DBG"); 717 718 // Backend specific setup 719 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 720 721 // Copy resource prefix, if backend setup sucessful 722 size_t len = strlen(backends[matchidx].prefix); 723 char *tmp; 724 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 725 memcpy(tmp, backends[matchidx].prefix, len+1); 726 (*ceed)->resource = tmp; 727 728 return 0; 729 } 730 731 /** 732 @brief Get the full resource name for a Ceed context 733 734 @param ceed Ceed context to get resource name of 735 @param[out] resource Variable to store resource name 736 737 @return An error code: 0 - success, otherwise - failure 738 739 @ref User 740 **/ 741 742 int CeedGetResource(Ceed ceed, const char **resource) { 743 *resource = (const char *)ceed->resource; 744 return 0; 745 } 746 747 /** 748 @brief Return Ceed context preferred memory type 749 750 @param ceed Ceed context to get preferred memory type of 751 @param[out] type Address to save preferred memory type to 752 753 @return An error code: 0 - success, otherwise - failure 754 755 @ref User 756 **/ 757 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 758 int ierr; 759 760 if (ceed->GetPreferredMemType) { 761 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 762 } else { 763 Ceed delegate; 764 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 765 766 if (delegate) { 767 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 768 } else { 769 *type = CEED_MEM_HOST; 770 } 771 } 772 773 return 0; 774 } 775 776 /** 777 @brief Get deterministic status of Ceed 778 779 @param[in] ceed Ceed 780 @param[out] isDeterministic Variable to store deterministic status 781 782 @return An error code: 0 - success, otherwise - failure 783 784 @ref User 785 **/ 786 int CeedIsDeterministic(Ceed ceed, bool *isDeterministic) { 787 *isDeterministic = ceed->isDeterministic; 788 return 0; 789 } 790 791 /** 792 @brief View a Ceed 793 794 @param[in] ceed Ceed to view 795 @param[in] stream Filestream to write to 796 797 @return An error code: 0 - success, otherwise - failure 798 799 @ref User 800 **/ 801 int CeedView(Ceed ceed, FILE *stream) { 802 int ierr; 803 CeedMemType memtype; 804 805 ierr = CeedGetPreferredMemType(ceed, &memtype); CeedChk(ierr); 806 807 fprintf(stream, "Ceed\n" 808 " Ceed Resource: %s\n" 809 " Preferred MemType: %s\n", 810 ceed->resource, CeedMemTypes[memtype]); 811 812 return 0; 813 } 814 815 /** 816 @brief Destroy a Ceed context 817 818 @param ceed Address of Ceed context to destroy 819 820 @return An error code: 0 - success, otherwise - failure 821 822 @ref User 823 **/ 824 int CeedDestroy(Ceed *ceed) { 825 int ierr; 826 if (!*ceed || --(*ceed)->refcount > 0) return 0; 827 if ((*ceed)->delegate) { 828 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 829 } 830 831 if ((*ceed)->objdelegatecount > 0) { 832 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 833 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 834 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 835 } 836 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 837 } 838 839 if ((*ceed)->Destroy) { 840 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 841 } 842 843 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 844 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 845 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 846 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 847 ierr = CeedFree(ceed); CeedChk(ierr); 848 return 0; 849 } 850 851 // LCOV_EXCL_START 852 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 853 vsnprintf(ceed->errmsg, CEED_MAX_RESOURCE_LEN, format, *args); 854 return ceed->errmsg; 855 } 856 // LCOV_EXCL_STOP 857 858 /** 859 @brief Error handling implementation; use \ref CeedError instead. 860 861 @ref Developer 862 **/ 863 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 864 int ecode, const char *format, ...) { 865 va_list args; 866 int retval; 867 va_start(args, format); 868 if (ceed) { 869 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 870 } else { 871 // LCOV_EXCL_START 872 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 873 if (!ceed_error_handler) 874 ceed_error_handler = "abort"; 875 if (!strcmp(ceed_error_handler, "return")) 876 retval = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 877 else 878 // This function will not return 879 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 880 } 881 va_end(args); 882 return retval; 883 // LCOV_EXCL_STOP 884 } 885 886 /** 887 @brief Error handler that returns without printing anything. 888 889 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 890 891 @ref Developer 892 **/ 893 // LCOV_EXCL_START 894 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 895 const char *func, int ecode, const char *format, 896 va_list *args) { 897 return ecode; 898 } 899 // LCOV_EXCL_STOP 900 901 /** 902 @brief Error handler that stores the error message for future use and returns 903 the error. 904 905 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 906 907 @ref Developer 908 **/ 909 // LCOV_EXCL_START 910 int CeedErrorStore(Ceed ceed, const char *filename, int lineno, 911 const char *func, int ecode, const char *format, 912 va_list *args) { 913 if (ceed->parent) 914 return CeedErrorStore(ceed->parent, filename, lineno, func, ecode, format, 915 args); 916 if (ceed->opfallbackparent) 917 return CeedErrorStore(ceed->opfallbackparent, filename, lineno, func, ecode, 918 format, args); 919 920 // Build message 921 CeedInt len; 922 len = snprintf(ceed->errmsg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", 923 filename, lineno, func); 924 vsnprintf(ceed->errmsg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); 925 return ecode; 926 } 927 // LCOV_EXCL_STOP 928 929 /** 930 @brief Error handler that prints to stderr and aborts 931 932 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 933 934 @ref Developer 935 **/ 936 // LCOV_EXCL_START 937 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 938 const char *func, int ecode, const char *format, 939 va_list *args) { 940 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 941 vfprintf(stderr, format, *args); 942 fprintf(stderr, "\n"); 943 abort(); 944 return ecode; 945 } 946 // LCOV_EXCL_STOP 947 948 /** 949 @brief Error handler that prints to stderr and exits 950 951 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 952 953 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 954 handlers (e.g., as used by gcov) are run. 955 956 @ref Developer 957 **/ 958 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 959 int ecode, const char *format, va_list *args) { 960 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 961 vfprintf(stderr, format, *args); 962 fprintf(stderr, "\n"); 963 exit(ecode); 964 return ecode; 965 } 966 967 /** 968 @brief Set error handler 969 970 A default error handler is set in CeedInit(). Use this function to change 971 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 972 error handler. 973 974 @ref Developer 975 **/ 976 int CeedSetErrorHandler(Ceed ceed, 977 int (*eh)(Ceed, const char *, int, const char *, 978 int, const char *, va_list *)) { 979 ceed->Error = eh; 980 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, eh); 981 for (int i=0; i<ceed->objdelegatecount; i++) 982 CeedSetErrorHandler(ceed->objdelegates[i].delegate, eh); 983 return 0; 984 } 985 986 /** 987 @brief Get error message 988 989 The error message is only stored when using the error handler 990 CeedErrorStore() 991 992 @param[in] ceed Ceed contex to retrieve error message 993 @param[out] errmsg Char pointer to hold error message 994 995 @ref Developer 996 **/ 997 int CeedGetErrorMessage(Ceed ceed, const char **errmsg) { 998 *errmsg = ceed->errmsg; 999 return 0; 1000 } 1001 1002 /** 1003 @brief Restore error message 1004 1005 The error message is only stored when using the error handler 1006 CeedErrorStore() 1007 1008 @param[in] ceed Ceed contex to restore error message 1009 @param[out] errmsg Char pointer that holds error message 1010 1011 @ref Developer 1012 **/ 1013 int CeedResetErrorMessage(Ceed ceed, const char **errmsg) { 1014 *errmsg = NULL; 1015 memcpy(ceed->errmsg, "No error message stored", 24); 1016 return 0; 1017 } 1018 1019 /// @} 1020