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/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 CEED_ERROR_SUCCESS; 112 return CeedError(NULL, CEED_ERROR_UNSUPPORTED, 113 "CeedRequestWait not implemented"); 114 } 115 116 /// @} 117 118 /// ---------------------------------------------------------------------------- 119 /// Ceed Library Internal Functions 120 /// ---------------------------------------------------------------------------- 121 /// @addtogroup CeedDeveloper 122 /// @{ 123 124 /// @} 125 126 /// ---------------------------------------------------------------------------- 127 /// Ceed Backend API 128 /// ---------------------------------------------------------------------------- 129 /// @addtogroup CeedBackend 130 /// @{ 131 132 /** 133 @brief Print Ceed debugging information 134 135 @param ceed Ceed context 136 @param format Printing format 137 138 @return None 139 140 @ref Backend 141 **/ 142 // LCOV_EXCL_START 143 void CeedDebugImpl(const Ceed ceed, const char *format,...) { 144 if (!ceed->debug) return; 145 va_list args; 146 va_start(args, format); 147 CeedDebugImpl256(ceed, 0, format, args); 148 va_end(args); 149 } 150 // LCOV_EXCL_STOP 151 152 /** 153 @brief Print Ceed debugging information in color 154 155 @param ceed Ceed context 156 @param color Color to print 157 @param format Printing format 158 159 @return None 160 161 @ref Backend 162 **/ 163 // LCOV_EXCL_START 164 void CeedDebugImpl256(const Ceed ceed, const unsigned char color, 165 const char *format,...) { 166 if (!ceed->debug) return; 167 va_list args; 168 va_start(args, format); 169 fflush(stdout); 170 fprintf(stdout, "\033[38;5;%dm", color); 171 vfprintf(stdout, format, args); 172 fprintf(stdout, "\033[m"); 173 fprintf(stdout, "\n"); 174 fflush(stdout); 175 va_end(args); 176 } 177 // LCOV_EXCL_STOP 178 179 /** 180 @brief Allocate an array on the host; use CeedMalloc() 181 182 Memory usage can be tracked by the library. This ensures sufficient 183 alignment for vectorization and should be used for large allocations. 184 185 @param n Number of units to allocate 186 @param unit Size of each unit 187 @param p Address of pointer to hold the result. 188 189 @return An error code: 0 - success, otherwise - failure 190 191 @sa CeedFree() 192 193 @ref Backend 194 **/ 195 int CeedMallocArray(size_t n, size_t unit, void *p) { 196 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 197 if (ierr) 198 // LCOV_EXCL_START 199 return CeedError(NULL, CEED_ERROR_MAJOR, 200 "posix_memalign failed to allocate %zd " 201 "members of size %zd\n", n, unit); 202 // LCOV_EXCL_STOP 203 return CEED_ERROR_SUCCESS; 204 } 205 206 /** 207 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 208 209 Memory usage can be tracked by the library. 210 211 @param n Number of units to allocate 212 @param unit Size of each unit 213 @param p Address of pointer to hold the result. 214 215 @return An error code: 0 - success, otherwise - failure 216 217 @sa CeedFree() 218 219 @ref Backend 220 **/ 221 int CeedCallocArray(size_t n, size_t unit, void *p) { 222 *(void **)p = calloc(n, unit); 223 if (n && unit && !*(void **)p) 224 // LCOV_EXCL_START 225 return CeedError(NULL, CEED_ERROR_MAJOR, 226 "calloc failed to allocate %zd members of size " 227 "%zd\n", n, unit); 228 // LCOV_EXCL_STOP 229 return CEED_ERROR_SUCCESS; 230 } 231 232 /** 233 @brief Reallocate an array on the host; use CeedRealloc() 234 235 Memory usage can be tracked by the library. 236 237 @param n Number of units to allocate 238 @param unit Size of each unit 239 @param p Address of pointer to hold the result. 240 241 @return An error code: 0 - success, otherwise - failure 242 243 @sa CeedFree() 244 245 @ref Backend 246 **/ 247 int CeedReallocArray(size_t n, size_t unit, void *p) { 248 *(void **)p = realloc(*(void **)p, n*unit); 249 if (n && unit && !*(void **)p) 250 // LCOV_EXCL_START 251 return CeedError(NULL, CEED_ERROR_MAJOR, 252 "realloc failed to allocate %zd members of size " 253 "%zd\n", n, unit); 254 // LCOV_EXCL_STOP 255 return CEED_ERROR_SUCCESS; 256 } 257 258 /** Free memory allocated using CeedMalloc() or CeedCalloc() 259 260 @param p address of pointer to memory. This argument is of type void* to 261 avoid needing a cast, but is the address of the pointer (which is 262 zeroed) rather than the pointer. 263 **/ 264 int CeedFree(void *p) { 265 free(*(void **)p); 266 *(void **)p = NULL; 267 return CEED_ERROR_SUCCESS; 268 } 269 270 /** 271 @brief Register a Ceed backend 272 273 @param prefix Prefix of resources for this backend to respond to. For 274 example, the reference backend responds to "/cpu/self". 275 @param init Initialization function called by CeedInit() when the backend 276 is selected to drive the requested resource. 277 @param priority Integer priority. Lower values are preferred in case the 278 resource requested by CeedInit() has non-unique best prefix 279 match. 280 281 @return An error code: 0 - success, otherwise - failure 282 283 @ref Backend 284 **/ 285 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 286 unsigned int priority) { 287 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 288 // LCOV_EXCL_START 289 return CeedError(NULL, CEED_ERROR_MAJOR, "Too many backends"); 290 // LCOV_EXCL_STOP 291 292 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 293 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 294 backends[num_backends].init = init; 295 backends[num_backends].priority = priority; 296 num_backends++; 297 return CEED_ERROR_SUCCESS; 298 } 299 300 /** 301 @brief Return debugging status flag 302 303 @param ceed Ceed context to get debugging flag 304 @param isDebug Variable to store debugging flag 305 306 @return An error code: 0 - success, otherwise - failure 307 308 @ref Bcakend 309 **/ 310 int CeedIsDebug(Ceed ceed, bool *isDebug) { 311 *isDebug = ceed->debug; 312 return CEED_ERROR_SUCCESS; 313 } 314 315 /** 316 @brief Retrieve a parent Ceed context 317 318 @param ceed Ceed context to retrieve parent of 319 @param[out] parent Address to save the parent to 320 321 @return An error code: 0 - success, otherwise - failure 322 323 @ref Backend 324 **/ 325 int CeedGetParent(Ceed ceed, Ceed *parent) { 326 int ierr; 327 if (ceed->parent) { 328 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 329 return CEED_ERROR_SUCCESS; 330 } 331 *parent = ceed; 332 return CEED_ERROR_SUCCESS; 333 } 334 335 /** 336 @brief Retrieve a delegate Ceed context 337 338 @param ceed Ceed context to retrieve delegate of 339 @param[out] delegate Address to save the delegate to 340 341 @return An error code: 0 - success, otherwise - failure 342 343 @ref Backend 344 **/ 345 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 346 *delegate = ceed->delegate; 347 return CEED_ERROR_SUCCESS; 348 } 349 350 /** 351 @brief Set a delegate Ceed context 352 353 This function allows a Ceed context to set a delegate Ceed context. All 354 backend implementations default to the delegate Ceed context, unless 355 overridden. 356 357 @param ceed Ceed context to set delegate of 358 @param[out] delegate Address to set the delegate to 359 360 @return An error code: 0 - success, otherwise - failure 361 362 @ref Backend 363 **/ 364 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 365 ceed->delegate = delegate; 366 delegate->parent = ceed; 367 return CEED_ERROR_SUCCESS; 368 } 369 370 /** 371 @brief Retrieve a delegate Ceed context for a specific object type 372 373 @param ceed Ceed context to retrieve delegate of 374 @param[out] delegate Address to save the delegate to 375 @param[in] objname Name of the object type to retrieve delegate for 376 377 @return An error code: 0 - success, otherwise - failure 378 379 @ref Backend 380 **/ 381 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 382 CeedInt ierr; 383 384 // Check for object delegate 385 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 386 if (!strcmp(objname, ceed->objdelegates->objname)) { 387 *delegate = ceed->objdelegates->delegate; 388 return CEED_ERROR_SUCCESS; 389 } 390 391 // Use default delegate if no object delegate 392 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 393 return CEED_ERROR_SUCCESS; 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 return CEED_ERROR_SUCCESS; 434 } 435 436 /** 437 @brief Get the fallback resource for CeedOperators 438 439 @param ceed Ceed context 440 @param[out] resource Variable to store fallback resource 441 442 @return An error code: 0 - success, otherwise - failure 443 444 @ref Backend 445 **/ 446 447 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 448 *resource = (const char *)ceed->opfallbackresource; 449 return CEED_ERROR_SUCCESS; 450 } 451 452 /** 453 @brief Set the fallback resource for CeedOperators. The current resource, if 454 any, is freed by calling this function. This string is freed upon the 455 destruction of the Ceed context. 456 457 @param[out] ceed Ceed context 458 @param resource Fallback resource to set 459 460 @return An error code: 0 - success, otherwise - failure 461 462 @ref Backend 463 **/ 464 465 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 466 int ierr; 467 468 // Free old 469 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 470 471 // Set new 472 size_t len = strlen(resource); 473 char *tmp; 474 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 475 memcpy(tmp, resource, len+1); 476 ceed->opfallbackresource = tmp; 477 return CEED_ERROR_SUCCESS; 478 } 479 480 /** 481 @brief Get the parent Ceed context associated with a fallback Ceed context 482 for a CeedOperator 483 484 @param ceed Ceed context 485 @param[out] parent Variable to store parent Ceed context 486 487 @return An error code: 0 - success, otherwise - failure 488 489 @ref Backend 490 **/ 491 492 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 493 *parent = ceed->opfallbackparent; 494 return CEED_ERROR_SUCCESS; 495 } 496 497 /** 498 @brief Flag Ceed context as deterministic 499 500 @param ceed Ceed to flag as deterministic 501 502 @return An error code: 0 - success, otherwise - failure 503 504 @ref Backend 505 **/ 506 507 int CeedSetDeterministic(Ceed ceed, bool isDeterministic) { 508 ceed->isDeterministic = isDeterministic; 509 return CEED_ERROR_SUCCESS; 510 } 511 512 /** 513 @brief Set a backend function 514 515 This function is used for a backend to set the function associated with 516 the Ceed objects. For example, 517 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 518 sets the backend implementation of 'CeedVectorCreate' and 519 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 520 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 521 is not required for the object type ("Basis" vs "CeedBasis"). 522 523 @param ceed Ceed context for error handling 524 @param type Type of Ceed object to set function for 525 @param[out] object Ceed object to set function for 526 @param fname Name of function to set 527 @param f Function to set 528 529 @return An error code: 0 - success, otherwise - failure 530 531 @ref Backend 532 **/ 533 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 534 const char *fname, int (*f)()) { 535 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 536 537 // Build lookup name 538 if (strcmp(type, "Ceed")) 539 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 540 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 541 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 542 543 // Find and use offset 544 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 545 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 546 size_t offset = ceed->foffsets[i].offset; 547 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 548 *fpointer = f; 549 return CEED_ERROR_SUCCESS; 550 } 551 552 // LCOV_EXCL_START 553 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 554 "Requested function '%s' was not found for CEED " 555 "object '%s'", fname, type); 556 // LCOV_EXCL_STOP 557 } 558 559 /** 560 @brief Retrieve backend data for a Ceed context 561 562 @param ceed Ceed context to retrieve data of 563 @param[out] data Address to save data to 564 565 @return An error code: 0 - success, otherwise - failure 566 567 @ref Backend 568 **/ 569 int CeedGetData(Ceed ceed, void *data) { 570 *(void **)data = ceed->data; 571 return CEED_ERROR_SUCCESS; 572 } 573 574 /** 575 @brief Set backend data for a Ceed context 576 577 @param ceed Ceed context to set data of 578 @param data Address of data to set 579 580 @return An error code: 0 - success, otherwise - failure 581 582 @ref Backend 583 **/ 584 int CeedSetData(Ceed ceed, void *data) { 585 ceed->data = data; 586 return CEED_ERROR_SUCCESS; 587 } 588 589 /// @} 590 591 /// ---------------------------------------------------------------------------- 592 /// Ceed Public API 593 /// ---------------------------------------------------------------------------- 594 /// @addtogroup CeedUser 595 /// @{ 596 597 /** 598 @brief Get the list of avaliable resource names for Ceed contexts 599 Note: The caller is responsible for `free()`ing the resources and priorities arrays, 600 but should not `free()` the contents of the resources array. 601 602 @param[out] n Number of avaliable resources 603 @param[out] resources List of avaliable resource names 604 @param[out] priorities Resource name prioritization values, lower is better 605 606 @return An error code: 0 - success, otherwise - failure 607 608 @ref User 609 **/ 610 // LCOV_EXCL_START 611 int CeedRegistryGetList(size_t *n, char ***const resources, 612 CeedInt **priorities) { 613 *n = num_backends; 614 *resources = malloc(num_backends * sizeof(**resources)); 615 if (!resources) 616 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 617 if (priorities) { 618 *priorities = malloc(num_backends * sizeof(**priorities)); 619 if (!priorities) 620 return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure"); 621 } 622 for (size_t i=0; i<num_backends; i++) { 623 *resources[i] = backends[i].prefix; 624 if (priorities) *priorities[i] = backends[i].priority; 625 } 626 return CEED_ERROR_SUCCESS; 627 }; 628 // LCOV_EXCL_STOP 629 630 /** 631 @brief Initialize a \ref Ceed context to use the specified resource. 632 Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") 633 will result in CeedInt printing the current libCEED version number 634 and a list of current avaliable backend resources to stderr. 635 636 @param resource Resource to use, e.g., "/cpu/self" 637 @param ceed The library context 638 @sa CeedRegister() CeedDestroy() 639 640 @return An error code: 0 - success, otherwise - failure 641 642 @ref User 643 **/ 644 int CeedInit(const char *resource, Ceed *ceed) { 645 int ierr; 646 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 647 648 // Find matching backend 649 if (!resource) 650 // LCOV_EXCL_START 651 return CeedError(NULL, CEED_ERROR_MAJOR, "No resource provided"); 652 // LCOV_EXCL_STOP 653 ierr = CeedRegisterAll(); CeedChk(ierr); 654 655 // Check for help request 656 const char *help_prefix = "help"; 657 size_t match_help; 658 for (match_help=0; match_help<4 659 && resource[match_help] == help_prefix[match_help]; match_help++) {} 660 if (match_help == 4) { 661 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, 662 CEED_VERSION_MINOR, CEED_VERSION_PATCH, 663 CEED_VERSION_RELEASE ? "" : "+development"); 664 fprintf(stderr, "Avaliable backend resources:\n"); 665 for (size_t i=0; i<num_backends; i++) { 666 fprintf(stderr, " %s\n", backends[i].prefix); 667 } 668 fflush(stderr); 669 match_help = 5; // Delineating character expected 670 } else { 671 match_help = 0; 672 } 673 674 // Find best match, currently computed as number of matching characters 675 // from requested resource stem but may use Levenshtein in future 676 size_t stem_length; 677 for (stem_length=0; resource[stem_length+match_help] 678 && resource[stem_length+match_help] != ':'; stem_length++) {} 679 for (size_t i=0; i<num_backends; i++) { 680 size_t n; 681 const char *prefix = backends[i].prefix; 682 for (n=0; prefix[n] && prefix[n] == resource[n+match_help]; n++) {} 683 priority = backends[i].priority; 684 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 685 matchlen = n; 686 matchpriority = priority; 687 matchidx = i; 688 } 689 } 690 if (matchlen <= 1) { 691 // LCOV_EXCL_START 692 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", 693 resource); 694 // LCOV_EXCL_STOP 695 } else if (matchlen != stem_length) { 696 // LCOV_EXCL_START 697 return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s " 698 "Closest match: %s", resource, backends[matchidx].prefix); 699 // LCOV_EXCL_STOP 700 } 701 702 // Setup Ceed 703 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 704 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 705 if (!ceed_error_handler) 706 ceed_error_handler = "abort"; 707 if (!strcmp(ceed_error_handler, "exit")) 708 (*ceed)->Error = CeedErrorExit; 709 else if (!strcmp(ceed_error_handler, "store")) 710 (*ceed)->Error = CeedErrorStore; 711 else 712 (*ceed)->Error = CeedErrorAbort; 713 memcpy((*ceed)->errmsg, "No error message stored", 24); 714 (*ceed)->refcount = 1; 715 (*ceed)->data = NULL; 716 717 // Set lookup table 718 foffset foffsets[] = { 719 CEED_FTABLE_ENTRY(Ceed, Error), 720 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 721 CEED_FTABLE_ENTRY(Ceed, Destroy), 722 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 723 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 724 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 725 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 726 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 727 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 728 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 729 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 730 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 731 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 732 CEED_FTABLE_ENTRY(CeedVector, SetArray), 733 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 734 CEED_FTABLE_ENTRY(CeedVector, SetValue), 735 CEED_FTABLE_ENTRY(CeedVector, GetArray), 736 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 737 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 738 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 739 CEED_FTABLE_ENTRY(CeedVector, Norm), 740 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 741 CEED_FTABLE_ENTRY(CeedVector, Destroy), 742 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 743 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 744 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 745 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 746 CEED_FTABLE_ENTRY(CeedBasis, Apply), 747 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 748 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 749 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 750 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 751 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 752 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 753 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 754 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 755 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 756 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 757 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 758 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 759 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 760 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 761 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 762 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 763 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 764 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 765 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 766 CEED_FTABLE_ENTRY(CeedOperator, Apply), 767 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 768 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 769 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 770 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 771 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 772 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 773 }; 774 775 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 776 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 777 778 // Set fallback for advanced CeedOperator functions 779 const char fallbackresource[] = ""; 780 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 781 CeedChk(ierr); 782 783 // Record env variables CEED_DEBUG or DBG 784 (*ceed)->debug = !!getenv("CEED_DEBUG") || !!getenv("DBG"); 785 786 // Backend specific setup 787 ierr = backends[matchidx].init(&resource[match_help], *ceed); CeedChk(ierr); 788 789 // Copy resource prefix, if backend setup successful 790 size_t len = strlen(backends[matchidx].prefix); 791 char *tmp; 792 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 793 memcpy(tmp, backends[matchidx].prefix, len+1); 794 (*ceed)->resource = tmp; 795 return CEED_ERROR_SUCCESS; 796 } 797 798 /** 799 @brief Get the full resource name for a Ceed context 800 801 @param ceed Ceed context to get resource name of 802 @param[out] resource Variable to store resource name 803 804 @return An error code: 0 - success, otherwise - failure 805 806 @ref User 807 **/ 808 809 int CeedGetResource(Ceed ceed, const char **resource) { 810 *resource = (const char *)ceed->resource; 811 return CEED_ERROR_SUCCESS; 812 } 813 814 /** 815 @brief Return Ceed context preferred memory type 816 817 @param ceed Ceed context to get preferred memory type of 818 @param[out] type Address to save preferred memory type to 819 820 @return An error code: 0 - success, otherwise - failure 821 822 @ref User 823 **/ 824 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 825 int ierr; 826 827 if (ceed->GetPreferredMemType) { 828 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 829 } else { 830 Ceed delegate; 831 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 832 833 if (delegate) { 834 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 835 } else { 836 *type = CEED_MEM_HOST; 837 } 838 } 839 return CEED_ERROR_SUCCESS; 840 } 841 842 /** 843 @brief Get deterministic status of Ceed 844 845 @param[in] ceed Ceed 846 @param[out] isDeterministic Variable to store deterministic status 847 848 @return An error code: 0 - success, otherwise - failure 849 850 @ref User 851 **/ 852 int CeedIsDeterministic(Ceed ceed, bool *isDeterministic) { 853 *isDeterministic = ceed->isDeterministic; 854 return CEED_ERROR_SUCCESS; 855 } 856 857 /** 858 @brief View a Ceed 859 860 @param[in] ceed Ceed to view 861 @param[in] stream Filestream to write to 862 863 @return An error code: 0 - success, otherwise - failure 864 865 @ref User 866 **/ 867 int CeedView(Ceed ceed, FILE *stream) { 868 int ierr; 869 CeedMemType memtype; 870 871 ierr = CeedGetPreferredMemType(ceed, &memtype); CeedChk(ierr); 872 873 fprintf(stream, "Ceed\n" 874 " Ceed Resource: %s\n" 875 " Preferred MemType: %s\n", 876 ceed->resource, CeedMemTypes[memtype]); 877 return CEED_ERROR_SUCCESS; 878 } 879 880 /** 881 @brief Destroy a Ceed context 882 883 @param ceed Address of Ceed context to destroy 884 885 @return An error code: 0 - success, otherwise - failure 886 887 @ref User 888 **/ 889 int CeedDestroy(Ceed *ceed) { 890 int ierr; 891 if (!*ceed || --(*ceed)->refcount > 0) return CEED_ERROR_SUCCESS; 892 if ((*ceed)->delegate) { 893 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 894 } 895 896 if ((*ceed)->objdelegatecount > 0) { 897 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 898 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 899 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 900 } 901 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 902 } 903 904 if ((*ceed)->Destroy) { 905 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 906 } 907 908 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 909 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 910 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 911 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 912 ierr = CeedFree(ceed); CeedChk(ierr); 913 return CEED_ERROR_SUCCESS; 914 } 915 916 // LCOV_EXCL_START 917 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 918 if (ceed->parent) 919 return CeedErrorFormat(ceed->parent, format, args); 920 if (ceed->opfallbackparent) 921 return CeedErrorFormat(ceed->opfallbackparent, format, args); 922 vsnprintf(ceed->errmsg, CEED_MAX_RESOURCE_LEN, format, *args); 923 return ceed->errmsg; 924 } 925 // LCOV_EXCL_STOP 926 927 /** 928 @brief Error handling implementation; use \ref CeedError instead. 929 930 @ref Developer 931 **/ 932 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 933 int ecode, const char *format, ...) { 934 va_list args; 935 int retval; 936 va_start(args, format); 937 if (ceed) { 938 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 939 } else { 940 // LCOV_EXCL_START 941 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 942 if (!ceed_error_handler) 943 ceed_error_handler = "abort"; 944 if (!strcmp(ceed_error_handler, "return")) 945 retval = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 946 else 947 // This function will not return 948 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 949 } 950 va_end(args); 951 return retval; 952 // LCOV_EXCL_STOP 953 } 954 955 /** 956 @brief Error handler that returns without printing anything. 957 958 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 959 960 @ref Developer 961 **/ 962 // LCOV_EXCL_START 963 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 964 const char *func, int ecode, const char *format, 965 va_list *args) { 966 return ecode; 967 } 968 // LCOV_EXCL_STOP 969 970 /** 971 @brief Error handler that stores the error message for future use and returns 972 the error. 973 974 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 975 976 @ref Developer 977 **/ 978 // LCOV_EXCL_START 979 int CeedErrorStore(Ceed ceed, const char *filename, int lineno, 980 const char *func, int ecode, const char *format, 981 va_list *args) { 982 if (ceed->parent) 983 return CeedErrorStore(ceed->parent, filename, lineno, func, ecode, format, 984 args); 985 if (ceed->opfallbackparent) 986 return CeedErrorStore(ceed->opfallbackparent, filename, lineno, func, ecode, 987 format, args); 988 989 // Build message 990 CeedInt len; 991 len = snprintf(ceed->errmsg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", 992 filename, lineno, func); 993 vsnprintf(ceed->errmsg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); 994 return ecode; 995 } 996 // LCOV_EXCL_STOP 997 998 /** 999 @brief Error handler that prints to stderr and aborts 1000 1001 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1002 1003 @ref Developer 1004 **/ 1005 // LCOV_EXCL_START 1006 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 1007 const char *func, int ecode, const char *format, 1008 va_list *args) { 1009 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 1010 vfprintf(stderr, format, *args); 1011 fprintf(stderr, "\n"); 1012 abort(); 1013 return ecode; 1014 } 1015 // LCOV_EXCL_STOP 1016 1017 /** 1018 @brief Error handler that prints to stderr and exits 1019 1020 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 1021 1022 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 1023 handlers (e.g., as used by gcov) are run. 1024 1025 @ref Developer 1026 **/ 1027 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 1028 int ecode, const char *format, va_list *args) { 1029 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 1030 vfprintf(stderr, format, *args); 1031 fprintf(stderr, "\n"); 1032 exit(ecode); 1033 return ecode; 1034 } 1035 1036 /** 1037 @brief Set error handler 1038 1039 A default error handler is set in CeedInit(). Use this function to change 1040 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 1041 error handler. 1042 1043 @ref Developer 1044 **/ 1045 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler eh) { 1046 ceed->Error = eh; 1047 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, eh); 1048 for (int i=0; i<ceed->objdelegatecount; i++) 1049 CeedSetErrorHandler(ceed->objdelegates[i].delegate, eh); 1050 return CEED_ERROR_SUCCESS; 1051 } 1052 1053 /** 1054 @brief Get error message 1055 1056 The error message is only stored when using the error handler 1057 CeedErrorStore() 1058 1059 @param[in] ceed Ceed contex to retrieve error message 1060 @param[out] errmsg Char pointer to hold error message 1061 1062 @ref Developer 1063 **/ 1064 int CeedGetErrorMessage(Ceed ceed, const char **errmsg) { 1065 if (ceed->parent) 1066 return CeedGetErrorMessage(ceed->parent, errmsg); 1067 if (ceed->opfallbackparent) 1068 return CeedGetErrorMessage(ceed->opfallbackparent, errmsg); 1069 *errmsg = ceed->errmsg; 1070 return CEED_ERROR_SUCCESS; 1071 } 1072 1073 /** 1074 @brief Restore error message 1075 1076 The error message is only stored when using the error handler 1077 CeedErrorStore() 1078 1079 @param[in] ceed Ceed contex to restore error message 1080 @param[out] errmsg Char pointer that holds error message 1081 1082 @ref Developer 1083 **/ 1084 int CeedResetErrorMessage(Ceed ceed, const char **errmsg) { 1085 if (ceed->parent) 1086 return CeedResetErrorMessage(ceed->parent, errmsg); 1087 if (ceed->opfallbackparent) 1088 return CeedResetErrorMessage(ceed->opfallbackparent, errmsg); 1089 *errmsg = NULL; 1090 memcpy(ceed->errmsg, "No error message stored", 24); 1091 return CEED_ERROR_SUCCESS; 1092 } 1093 1094 /** 1095 @brief Get libCEED library version info 1096 1097 libCEED version numbers have the form major.minor.patch. Non-release versions 1098 may contain unstable interfaces. 1099 1100 @param[out] major Major version of the library 1101 @param[out] minor Minor version of the library 1102 @param[out] patch Patch (subminor) version of the library 1103 @param[out] release True for releases; false for development branches. 1104 1105 The caller may pass NULL for any arguments that are not needed. 1106 1107 @sa CEED_VERSION_GE() 1108 1109 @ref Developer 1110 */ 1111 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1112 if (major) *major = CEED_VERSION_MAJOR; 1113 if (minor) *minor = CEED_VERSION_MINOR; 1114 if (patch) *patch = CEED_VERSION_PATCH; 1115 if (release) *release = CEED_VERSION_RELEASE; 1116 return 0; 1117 } 1118 1119 /// @} 1120