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 @brief Error handler that returns without printing anything. 124 125 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 126 127 @ref Developer 128 **/ 129 // LCOV_EXCL_START 130 int CeedErrorReturn(Ceed ceed, const char *filename, int lineno, 131 const char *func, int ecode, const char *format, 132 va_list args) { 133 return ecode; 134 } 135 // LCOV_EXCL_STOP 136 137 /** 138 @brief Error handler that prints to stderr and aborts 139 140 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 141 142 @ref Developer 143 **/ 144 // LCOV_EXCL_START 145 int CeedErrorAbort(Ceed ceed, const char *filename, int lineno, 146 const char *func, int ecode, const char *format, 147 va_list args) { 148 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 149 vfprintf(stderr, format, args); 150 fprintf(stderr, "\n"); 151 abort(); 152 return ecode; 153 } 154 // LCOV_EXCL_STOP 155 156 /** 157 @brief Error handler that prints to stderr and exits 158 159 Pass this to CeedSetErrorHandler() to obtain this error handling behavior. 160 161 In contrast to CeedErrorAbort(), this exits without a signal, so atexit() 162 handlers (e.g., as used by gcov) are run. 163 164 @ref Developer 165 **/ 166 int CeedErrorExit(Ceed ceed, const char *filename, int lineno, const char *func, 167 int ecode, const char *format, va_list args) { 168 fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func); 169 vfprintf(stderr, format, args); 170 fprintf(stderr, "\n"); 171 exit(ecode); 172 return ecode; 173 } 174 175 /** 176 @brief Set error handler 177 178 A default error handler is set in CeedInit(). Use this function to change 179 the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined 180 error handler. 181 182 @ref Developer 183 **/ 184 int CeedSetErrorHandler(Ceed ceed, 185 int (*eh)(Ceed, const char *, int, const char *, 186 int, const char *, va_list)) { 187 ceed->Error = eh; 188 return 0; 189 } 190 191 /// @} 192 193 /// ---------------------------------------------------------------------------- 194 /// Ceed Backend API 195 /// ---------------------------------------------------------------------------- 196 /// @addtogroup CeedBackend 197 /// @{ 198 199 /** 200 @brief Allocate an array on the host; use CeedMalloc() 201 202 Memory usage can be tracked by the library. This ensures sufficient 203 alignment for vectorization and should be used for large allocations. 204 205 @param n Number of units to allocate 206 @param unit Size of each unit 207 @param p Address of pointer to hold the result. 208 209 @return An error code: 0 - success, otherwise - failure 210 211 @sa CeedFree() 212 213 @ref Backend 214 **/ 215 int CeedMallocArray(size_t n, size_t unit, void *p) { 216 int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit); 217 if (ierr) 218 // LCOV_EXCL_START 219 return CeedError(NULL, ierr, "posix_memalign failed to allocate %zd " 220 "members of size %zd\n", n, unit); 221 // LCOV_EXCL_STOP 222 223 return 0; 224 } 225 226 /** 227 @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc() 228 229 Memory usage can be tracked by the library. 230 231 @param n Number of units to allocate 232 @param unit Size of each unit 233 @param p Address of pointer to hold the result. 234 235 @return An error code: 0 - success, otherwise - failure 236 237 @sa CeedFree() 238 239 @ref Backend 240 **/ 241 int CeedCallocArray(size_t n, size_t unit, void *p) { 242 *(void **)p = calloc(n, unit); 243 if (n && unit && !*(void **)p) 244 // LCOV_EXCL_START 245 return CeedError(NULL, 1, "calloc failed to allocate %zd members of size " 246 "%zd\n", n, unit); 247 // LCOV_EXCL_STOP 248 249 return 0; 250 } 251 252 /** 253 @brief Reallocate an array on the host; use CeedRealloc() 254 255 Memory usage can be tracked by the library. 256 257 @param n Number of units to allocate 258 @param unit Size of each unit 259 @param p Address of pointer to hold the result. 260 261 @return An error code: 0 - success, otherwise - failure 262 263 @sa CeedFree() 264 265 @ref Backend 266 **/ 267 int CeedReallocArray(size_t n, size_t unit, void *p) { 268 *(void **)p = realloc(*(void **)p, n*unit); 269 if (n && unit && !*(void **)p) 270 // LCOV_EXCL_START 271 return CeedError(NULL, 1, "realloc failed to allocate %zd members of size " 272 "%zd\n", n, unit); 273 // LCOV_EXCL_STOP 274 275 return 0; 276 } 277 278 /** Free memory allocated using CeedMalloc() or CeedCalloc() 279 280 @param p address of pointer to memory. This argument is of type void* to 281 avoid needing a cast, but is the address of the pointer (which is 282 zeroed) rather than the pointer. 283 **/ 284 int CeedFree(void *p) { 285 free(*(void **)p); 286 *(void **)p = NULL; 287 return 0; 288 } 289 290 /** 291 @brief Register a Ceed backend 292 293 @param prefix Prefix of resources for this backend to respond to. For 294 example, the reference backend responds to "/cpu/self". 295 @param init Initialization function called by CeedInit() when the backend 296 is selected to drive the requested resource. 297 @param priority Integer priority. Lower values are preferred in case the 298 resource requested by CeedInit() has non-unique best prefix 299 match. 300 301 @return An error code: 0 - success, otherwise - failure 302 303 @ref Backend 304 **/ 305 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), 306 unsigned int priority) { 307 if (num_backends >= sizeof(backends) / sizeof(backends[0])) 308 // LCOV_EXCL_START 309 return CeedError(NULL, 1, "Too many backends"); 310 // LCOV_EXCL_STOP 311 312 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 313 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0; 314 backends[num_backends].init = init; 315 backends[num_backends].priority = priority; 316 num_backends++; 317 return 0; 318 } 319 320 /** 321 @brief Retrieve a parent Ceed context 322 323 @param ceed Ceed context to retrieve parent of 324 @param[out] parent Address to save the parent to 325 326 @return An error code: 0 - success, otherwise - failure 327 328 @ref Backend 329 **/ 330 int CeedGetParent(Ceed ceed, Ceed *parent) { 331 int ierr; 332 if (ceed->parent) { 333 ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr); 334 return 0; 335 } 336 *parent = ceed; 337 return 0; 338 } 339 340 /** 341 @brief Retrieve a delegate Ceed context 342 343 @param ceed Ceed context to retrieve delegate of 344 @param[out] delegate Address to save the delegate to 345 346 @return An error code: 0 - success, otherwise - failure 347 348 @ref Backend 349 **/ 350 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 351 *delegate = ceed->delegate; 352 return 0; 353 } 354 355 /** 356 @brief Set a delegate Ceed context 357 358 This function allows a Ceed context to set a delegate Ceed context. All 359 backend implementations default to the delegate Ceed context, unless 360 overridden. 361 362 @param ceed Ceed context to set delegate of 363 @param[out] delegate Address to set the delegate to 364 365 @return An error code: 0 - success, otherwise - failure 366 367 @ref Backend 368 **/ 369 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 370 ceed->delegate = delegate; 371 delegate->parent = ceed; 372 return 0; 373 } 374 375 /** 376 @brief Retrieve a delegate Ceed context for a specific object type 377 378 @param ceed Ceed context to retrieve delegate of 379 @param[out] delegate Address to save the delegate to 380 @param[in] objname Name of the object type to retrieve delegate for 381 382 @return An error code: 0 - success, otherwise - failure 383 384 @ref Backend 385 **/ 386 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *objname) { 387 CeedInt ierr; 388 389 // Check for object delegate 390 for (CeedInt i=0; i<ceed->objdelegatecount; i++) 391 if (!strcmp(objname, ceed->objdelegates->objname)) { 392 *delegate = ceed->objdelegates->delegate; 393 return 0; 394 } 395 396 // Use default delegate if no object delegate 397 ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr); 398 399 return 0; 400 } 401 402 /** 403 @brief Set a delegate Ceed context for a specific object type 404 405 This function allows a Ceed context to set a delegate Ceed context for a 406 given type of Ceed object. All backend implementations default to the 407 delegate Ceed context for this object. For example, 408 CeedSetObjectDelegate(ceed, refceed, "Basis") 409 uses refceed implementations for all CeedBasis backend functions. 410 411 @param ceed Ceed context to set delegate of 412 @param[out] delegate Address to set the delegate to 413 @param[in] objname Name of the object type to set delegate for 414 415 @return An error code: 0 - success, otherwise - failure 416 417 @ref Backend 418 **/ 419 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *objname) { 420 CeedInt ierr; 421 CeedInt count = ceed->objdelegatecount; 422 423 // Malloc or Realloc 424 if (count) { 425 ierr = CeedRealloc(count+1, &ceed->objdelegates); CeedChk(ierr); 426 } else { 427 ierr = CeedCalloc(1, &ceed->objdelegates); CeedChk(ierr); 428 } 429 ceed->objdelegatecount++; 430 431 // Set object delegate 432 ceed->objdelegates[count].delegate = delegate; 433 size_t slen = strlen(objname) + 1; 434 ierr = CeedMalloc(slen, &ceed->objdelegates[count].objname); CeedChk(ierr); 435 memcpy(ceed->objdelegates[count].objname, objname, slen); 436 437 // Set delegate parent 438 delegate->parent = ceed; 439 440 return 0; 441 } 442 443 /** 444 @brief Get the fallback resource for CeedOperators 445 446 @param ceed Ceed context 447 @param[out] resource Variable to store fallback resource 448 449 @return An error code: 0 - success, otherwise - failure 450 451 @ref Backend 452 **/ 453 454 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 455 *resource = (const char *)ceed->opfallbackresource; 456 return 0; 457 } 458 459 /** 460 @brief Set the fallback resource for CeedOperators. The current resource, if 461 any, is freed by calling this function. This string is freed upon the 462 destruction of the Ceed context. 463 464 @param[out] ceed Ceed context 465 @param resource Fallback resource to set 466 467 @return An error code: 0 - success, otherwise - failure 468 469 @ref Backend 470 **/ 471 472 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 473 int ierr; 474 475 // Free old 476 ierr = CeedFree(&ceed->opfallbackresource); CeedChk(ierr); 477 478 // Set new 479 size_t len = strlen(resource); 480 char *tmp; 481 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 482 memcpy(tmp, resource, len+1); 483 ceed->opfallbackresource = tmp; 484 485 return 0; 486 } 487 488 /** 489 @brief Get the parent Ceed context associated with a fallback Ceed context 490 for a CeedOperator 491 492 @param ceed Ceed context 493 @param[out] parent Variable to store parent Ceed context 494 495 @return An error code: 0 - success, otherwise - failure 496 497 @ref Backend 498 **/ 499 500 int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) { 501 *parent = ceed->opfallbackparent; 502 return 0; 503 } 504 505 /** 506 @brief Set a backend function 507 508 This function is used for a backend to set the function associated with 509 the Ceed objects. For example, 510 CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) 511 sets the backend implementation of 'CeedVectorCreate' and 512 CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) 513 sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed' 514 is not required for the object type ("Basis" vs "CeedBasis"). 515 516 @param ceed Ceed context for error handling 517 @param type Type of Ceed object to set function for 518 @param[out] object Ceed object to set function for 519 @param fname Name of function to set 520 @param f Function to set 521 522 @return An error code: 0 - success, otherwise - failure 523 524 @ref Backend 525 **/ 526 int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, 527 const char *fname, int (*f)()) { 528 char lookupname[CEED_MAX_RESOURCE_LEN+1] = ""; 529 530 // Build lookup name 531 if (strcmp(type, "Ceed")) 532 strncat (lookupname, "Ceed", CEED_MAX_RESOURCE_LEN); 533 strncat(lookupname, type, CEED_MAX_RESOURCE_LEN); 534 strncat(lookupname, fname, CEED_MAX_RESOURCE_LEN); 535 536 // Find and use offset 537 for (CeedInt i = 0; ceed->foffsets[i].fname; i++) 538 if (!strcmp(ceed->foffsets[i].fname, lookupname)) { 539 size_t offset = ceed->foffsets[i].offset; 540 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 541 *fpointer = f; 542 return 0; 543 } 544 545 // LCOV_EXCL_START 546 return CeedError(ceed, 1, "Requested function '%s' was not found for CEED " 547 "object '%s'", fname, type); 548 // LCOV_EXCL_STOP 549 } 550 551 /** 552 @brief Retrieve backend data for a Ceed context 553 554 @param ceed Ceed context to retrieve data of 555 @param[out] data Address to save data to 556 557 @return An error code: 0 - success, otherwise - failure 558 559 @ref Backend 560 **/ 561 int CeedGetData(Ceed ceed, void **data) { 562 *data = ceed->data; 563 return 0; 564 } 565 566 /** 567 @brief Set backend data for a Ceed context 568 569 @param ceed Ceed context to set data of 570 @param data Address of data to set 571 572 @return An error code: 0 - success, otherwise - failure 573 574 @ref Backend 575 **/ 576 int CeedSetData(Ceed ceed, void **data) { 577 ceed->data = *data; 578 return 0; 579 } 580 581 /// @} 582 583 /// ---------------------------------------------------------------------------- 584 /// Ceed Public API 585 /// ---------------------------------------------------------------------------- 586 /// @addtogroup CeedUser 587 /// @{ 588 589 /** 590 @brief Initialize a \ref Ceed context to use the specified resource. 591 592 @param resource Resource to use, e.g., "/cpu/self" 593 @param ceed The library context 594 @sa CeedRegister() CeedDestroy() 595 596 @return An error code: 0 - success, otherwise - failure 597 598 @ref User 599 **/ 600 int CeedInit(const char *resource, Ceed *ceed) { 601 int ierr; 602 size_t matchlen = 0, matchidx = UINT_MAX, matchpriority = UINT_MAX, priority; 603 604 // Find matching backend 605 if (!resource) 606 // LCOV_EXCL_START 607 return CeedError(NULL, 1, "No resource provided"); 608 // LCOV_EXCL_STOP 609 610 for (size_t i=0; i<num_backends; i++) { 611 size_t n; 612 const char *prefix = backends[i].prefix; 613 for (n = 0; prefix[n] && prefix[n] == resource[n]; n++) {} 614 priority = backends[i].priority; 615 if (n > matchlen || (n == matchlen && matchpriority > priority)) { 616 matchlen = n; 617 matchpriority = priority; 618 matchidx = i; 619 } 620 } 621 if (!matchlen) 622 // LCOV_EXCL_START 623 return CeedError(NULL, 1, "No suitable backend: %s", resource); 624 // LCOV_EXCL_STOP 625 626 // Setup Ceed 627 ierr = CeedCalloc(1, ceed); CeedChk(ierr); 628 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 629 if (!ceed_error_handler) 630 ceed_error_handler = "abort"; 631 if (!strcmp(ceed_error_handler, "exit")) 632 (*ceed)->Error = CeedErrorExit; 633 else 634 (*ceed)->Error = CeedErrorAbort; 635 (*ceed)->refcount = 1; 636 (*ceed)->data = NULL; 637 638 // Set lookup table 639 foffset foffsets[] = { 640 CEED_FTABLE_ENTRY(Ceed, Error), 641 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 642 CEED_FTABLE_ENTRY(Ceed, Destroy), 643 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 644 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 645 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 646 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 647 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 648 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 649 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 650 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 651 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 652 CEED_FTABLE_ENTRY(CeedVector, SetArray), 653 CEED_FTABLE_ENTRY(CeedVector, SetValue), 654 CEED_FTABLE_ENTRY(CeedVector, GetArray), 655 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 656 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 657 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 658 CEED_FTABLE_ENTRY(CeedVector, Norm), 659 CEED_FTABLE_ENTRY(CeedVector, Destroy), 660 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 661 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 662 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 663 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 664 CEED_FTABLE_ENTRY(CeedBasis, Apply), 665 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 666 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 667 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 668 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 669 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 670 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearQFunction), 671 CEED_FTABLE_ENTRY(CeedOperator, AssembleLinearDiagonal), 672 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 673 CEED_FTABLE_ENTRY(CeedOperator, Apply), 674 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 675 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 676 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 677 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 678 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 679 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 680 }; 681 682 ierr = CeedCalloc(sizeof(foffsets), &(*ceed)->foffsets); CeedChk(ierr); 683 memcpy((*ceed)->foffsets, foffsets, sizeof(foffsets)); 684 685 // Set fallback for advanced CeedOperator functions 686 const char fallbackresource[] = "/cpu/self/ref/serial"; 687 ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource); 688 CeedChk(ierr); 689 690 // Backend specific setup 691 ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr); 692 693 // Copy resource prefix, if backend setup sucessful 694 size_t len = strlen(backends[matchidx].prefix); 695 char *tmp; 696 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 697 memcpy(tmp, backends[matchidx].prefix, len+1); 698 (*ceed)->resource = tmp; 699 700 return 0; 701 } 702 703 /** 704 @brief Get the full resource name for a Ceed context 705 706 @param ceed Ceed context to get resource name of 707 @param[out] resource Variable to store resource name 708 709 @return An error code: 0 - success, otherwise - failure 710 711 @ref User 712 **/ 713 714 int CeedGetResource(Ceed ceed, const char **resource) { 715 *resource = (const char *)ceed->resource; 716 return 0; 717 } 718 719 /** 720 @brief Return Ceed context preferred memory type 721 722 @param ceed Ceed context to get preferred memory type of 723 @param[out] type Address to save preferred memory type to 724 725 @return An error code: 0 - success, otherwise - failure 726 727 @ref User 728 **/ 729 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *type) { 730 int ierr; 731 732 if (ceed->GetPreferredMemType) { 733 ierr = ceed->GetPreferredMemType(type); CeedChk(ierr); 734 } else { 735 Ceed delegate; 736 ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr); 737 738 if (delegate) { 739 ierr = CeedGetPreferredMemType(delegate, type); CeedChk(ierr); 740 } else { 741 *type = CEED_MEM_HOST; 742 } 743 } 744 745 return 0; 746 } 747 748 /** 749 @brief View a Ceed 750 751 @param[in] ceed Ceed to view 752 @param[in] stream Filestream to write to 753 754 @return An error code: 0 - success, otherwise - failure 755 756 @ref User 757 **/ 758 int CeedView(Ceed ceed, FILE *stream) { 759 int ierr; 760 CeedMemType memtype; 761 762 ierr = CeedGetPreferredMemType(ceed, &memtype); CeedChk(ierr); 763 764 fprintf(stream, "Ceed\n" 765 " Ceed Resource: %s\n" 766 " Preferred MemType: %s\n", 767 ceed->resource, CeedMemTypes[memtype]); 768 769 return 0; 770 } 771 772 /** 773 @brief Destroy a Ceed context 774 775 @param ceed Address of Ceed context to destroy 776 777 @return An error code: 0 - success, otherwise - failure 778 779 @ref User 780 **/ 781 int CeedDestroy(Ceed *ceed) { 782 int ierr; 783 if (!*ceed || --(*ceed)->refcount > 0) 784 return 0; 785 786 if ((*ceed)->delegate) { 787 ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr); 788 } 789 790 if ((*ceed)->objdelegatecount > 0) { 791 for (int i=0; i<(*ceed)->objdelegatecount; i++) { 792 ierr = CeedDestroy(&((*ceed)->objdelegates[i].delegate)); CeedChk(ierr); 793 ierr = CeedFree(&(*ceed)->objdelegates[i].objname); CeedChk(ierr); 794 } 795 ierr = CeedFree(&(*ceed)->objdelegates); CeedChk(ierr); 796 } 797 798 if ((*ceed)->Destroy) { 799 ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr); 800 } 801 802 ierr = CeedFree(&(*ceed)->foffsets); CeedChk(ierr); 803 ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr); 804 ierr = CeedDestroy(&(*ceed)->opfallbackceed); CeedChk(ierr); 805 ierr = CeedFree(&(*ceed)->opfallbackresource); CeedChk(ierr); 806 ierr = CeedFree(ceed); CeedChk(ierr); 807 return 0; 808 } 809 810 /** 811 @brief Error handling implementation; use \ref CeedError instead. 812 813 @ref Developer 814 **/ 815 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, 816 int ecode, const char *format, ...) { 817 va_list args; 818 int retval; 819 va_start(args, format); 820 if (ceed) { 821 retval = ceed->Error(ceed, filename, lineno, func, ecode, format, args); 822 } else { 823 // This function doesn't actually return 824 // LCOV_EXCL_START 825 retval = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args); 826 } 827 va_end(args); 828 return retval; 829 // LCOV_EXCL_STOP 830 } 831 832 /// @} 833