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