1 // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #define _POSIX_C_SOURCE 200112 9 #include <ceed-impl.h> 10 #include <ceed.h> 11 #include <ceed/backend.h> 12 #include <limits.h> 13 #include <stdarg.h> 14 #include <stdbool.h> 15 #include <stddef.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 /// @cond DOXYGEN_SKIP 21 static CeedRequest ceed_request_immediate; 22 static CeedRequest ceed_request_ordered; 23 24 static struct { 25 char prefix[CEED_MAX_RESOURCE_LEN]; 26 int (*init)(const char *resource, Ceed f); 27 unsigned int priority; 28 } backends[32]; 29 static size_t num_backends; 30 31 #define CEED_FTABLE_ENTRY(class, method) \ 32 { #class #method, offsetof(struct class##_private, method) } 33 /// @endcond 34 35 /// @file 36 /// Implementation of core components of Ceed library 37 38 /// @addtogroup CeedUser 39 /// @{ 40 41 /** 42 @brief Request immediate completion 43 44 This predefined constant is passed as the @ref CeedRequest argument to interfaces when the caller wishes for the operation to be performed immediately. 45 The code 46 47 @code 48 CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE); 49 @endcode 50 51 is semantically equivalent to 52 53 @code 54 CeedRequest request; 55 CeedOperatorApply(op, ..., &request); 56 CeedRequestWait(&request); 57 @endcode 58 59 @sa CEED_REQUEST_ORDERED 60 **/ 61 CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate; 62 63 /** 64 @brief Request ordered completion 65 66 This predefined constant is passed as the @ref CeedRequest argument to interfaces when the caller wishes for the operation to be completed in the order that it is submitted to the device. 67 It is typically used in a construct such as: 68 69 @code 70 CeedRequest request; 71 CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED); 72 CeedOperatorApply(op2, ..., &request); 73 // other optional work 74 CeedRequestWait(&request); 75 @endcode 76 77 which allows the sequence to complete asynchronously but does not start `op2` until `op1` has completed. 78 79 @todo The current implementation is overly strict, offering equivalent semantics to @ref CEED_REQUEST_IMMEDIATE. 80 81 @sa CEED_REQUEST_IMMEDIATE 82 */ 83 CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered; 84 85 /** 86 @brief Wait for a @ref CeedRequest to complete. 87 88 Calling @ref CeedRequestWait() on a `NULL` request is a no-op. 89 90 @param[in,out] req Address of @ref CeedRequest to wait for; zeroed on completion. 91 92 @return An error code: 0 - success, otherwise - failure 93 94 @ref User 95 **/ 96 int CeedRequestWait(CeedRequest *req) { 97 if (!*req) return CEED_ERROR_SUCCESS; 98 return CeedError(NULL, CEED_ERROR_UNSUPPORTED, "CeedRequestWait not implemented"); 99 } 100 101 /// @} 102 103 /// ---------------------------------------------------------------------------- 104 /// Ceed Library Internal Functions 105 /// ---------------------------------------------------------------------------- 106 /// @addtogroup CeedDeveloper 107 /// @{ 108 109 /** 110 @brief Register a Ceed backend internally. 111 112 Note: Backends should call @ref CeedRegister() instead. 113 114 @param[in] prefix Prefix of resources for this backend to respond to. 115 For example, the reference backend responds to "/cpu/self". 116 @param[in] init Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource 117 @param[in] priority Integer priority. 118 Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match. 119 120 @return An error code: 0 - success, otherwise - failure 121 122 @ref Developer 123 **/ 124 int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) { 125 int ierr = 0; 126 127 CeedPragmaCritical(CeedRegisterImpl) { 128 if (num_backends < sizeof(backends) / sizeof(backends[0])) { 129 strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN); 130 backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN - 1] = 0; 131 backends[num_backends].init = init; 132 backends[num_backends].priority = priority; 133 num_backends++; 134 } else { 135 ierr = 1; 136 } 137 } 138 CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many backends"); 139 return CEED_ERROR_SUCCESS; 140 } 141 142 /// @} 143 144 /// ---------------------------------------------------------------------------- 145 /// Ceed Backend API 146 /// ---------------------------------------------------------------------------- 147 /// @addtogroup CeedBackend 148 /// @{ 149 150 /** 151 @brief Return value of `CEED_DEBUG` environment variable 152 153 @param[in] ceed `Ceed` context 154 155 @return Boolean value: true - debugging mode enabled 156 false - debugging mode disabled 157 158 @ref Backend 159 **/ 160 // LCOV_EXCL_START 161 bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; } 162 // LCOV_EXCL_STOP 163 164 /** 165 @brief Return value of `CEED_DEBUG` environment variable 166 167 @return Boolean value: true - debugging mode enabled 168 false - debugging mode disabled 169 170 @ref Backend 171 **/ 172 // LCOV_EXCL_START 173 bool CeedDebugFlagEnv(void) { return getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); } 174 // LCOV_EXCL_STOP 175 176 /** 177 @brief Print debugging information in color 178 179 @param[in] color Color to print 180 @param[in] format Printing format 181 182 @ref Backend 183 **/ 184 // LCOV_EXCL_START 185 void CeedDebugImpl256(const unsigned char color, const char *format, ...) { 186 va_list args; 187 va_start(args, format); 188 fflush(stdout); 189 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color); 190 vfprintf(stdout, format, args); 191 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m"); 192 fprintf(stdout, "\n"); 193 fflush(stdout); 194 va_end(args); 195 } 196 // LCOV_EXCL_STOP 197 198 /** 199 @brief Allocate an array on the host; use @ref CeedMalloc(). 200 201 Memory usage can be tracked by the library. 202 This ensures sufficient alignment for vectorization and should be used for large allocations. 203 204 @param[in] n Number of units to allocate 205 @param[in] unit Size of each unit 206 @param[out] p Address of pointer to hold the result 207 208 @return An error code: 0 - success, otherwise - failure 209 210 @ref Backend 211 212 @sa CeedFree() 213 **/ 214 int CeedMallocArray(size_t n, size_t unit, void *p) { 215 int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit); 216 CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit); 217 return CEED_ERROR_SUCCESS; 218 } 219 220 /** 221 @brief Allocate a cleared (zeroed) array on the host; use @ref CeedCalloc(). 222 223 Memory usage can be tracked by the library. 224 225 @param[in] n Number of units to allocate 226 @param[in] unit Size of each unit 227 @param[out] p Address of pointer to hold the result 228 229 @return An error code: 0 - success, otherwise - failure 230 231 @ref Backend 232 233 @sa CeedFree() 234 **/ 235 int CeedCallocArray(size_t n, size_t unit, void *p) { 236 *(void **)p = calloc(n, unit); 237 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit); 238 return CEED_ERROR_SUCCESS; 239 } 240 241 /** 242 @brief Reallocate an array on the host; use @ref CeedRealloc(). 243 244 Memory usage can be tracked by the library. 245 246 @param[in] n Number of units to allocate 247 @param[in] unit Size of each unit 248 @param[out] p Address of pointer to hold the result 249 250 @return An error code: 0 - success, otherwise - failure 251 252 @ref Backend 253 254 @sa CeedFree() 255 **/ 256 int CeedReallocArray(size_t n, size_t unit, void *p) { 257 *(void **)p = realloc(*(void **)p, n * unit); 258 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit); 259 return CEED_ERROR_SUCCESS; 260 } 261 262 /** 263 @brief Allocate a cleared string buffer on the host. 264 265 Memory usage can be tracked by the library. 266 267 @param[in] source Pointer to string to be copied 268 @param[out] copy Pointer to variable to hold newly allocated string copy 269 270 @return An error code: 0 - success, otherwise - failure 271 272 @ref Backend 273 274 @sa CeedFree() 275 **/ 276 int CeedStringAllocCopy(const char *source, char **copy) { 277 size_t len = strlen(source); 278 CeedCall(CeedCalloc(len + 1, copy)); 279 memcpy(*copy, source, len); 280 return CEED_ERROR_SUCCESS; 281 } 282 283 /** Free memory allocated using @ref CeedMalloc() or @ref CeedCalloc() 284 285 @param[in,out] p Address of pointer to memory. 286 This argument is of type `void*` to avoid needing a cast, but is the address of the pointer (which is zeroed) rather than the pointer. 287 288 @return An error code: 0 - success, otherwise - failure 289 290 @ref Backend 291 **/ 292 int CeedFree(void *p) { 293 free(*(void **)p); 294 *(void **)p = NULL; 295 return CEED_ERROR_SUCCESS; 296 } 297 298 /** Internal helper to manage handoff of user `source_array` to backend with proper @ref CeedCopyMode behavior. 299 300 @param[in] source_array Source data provided by user 301 @param[in] copy_mode Copy mode for the data 302 @param[in] num_values Number of values to handle 303 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 304 @param[out] target_array_borrowed Pointer to location to hold borrowed data 305 @param[out] target_array Pointer to location for data 306 307 @return An error code: 0 - success, otherwise - failure 308 309 @ref Backend 310 **/ 311 static inline int CeedSetHostGenericArray(const void *source_array, CeedCopyMode copy_mode, size_t size_unit, CeedSize num_values, 312 void *target_array_owned, void *target_array_borrowed, void *target_array) { 313 switch (copy_mode) { 314 case CEED_COPY_VALUES: 315 if (!*(void **)target_array_owned) CeedCall(CeedCallocArray(num_values, size_unit, target_array_owned)); 316 if (source_array) memcpy(*(void **)target_array_owned, source_array, size_unit * num_values); 317 *(void **)target_array_borrowed = NULL; 318 *(void **)target_array = *(void **)target_array_owned; 319 break; 320 case CEED_OWN_POINTER: 321 CeedCall(CeedFree(target_array_owned)); 322 *(void **)target_array_owned = (void *)source_array; 323 *(void **)target_array_borrowed = NULL; 324 *(void **)target_array = *(void **)target_array_owned; 325 break; 326 case CEED_USE_POINTER: 327 CeedCall(CeedFree(target_array_owned)); 328 *(void **)target_array_owned = NULL; 329 *(void **)target_array_borrowed = (void *)source_array; 330 *(void **)target_array = *(void **)target_array_borrowed; 331 } 332 return CEED_ERROR_SUCCESS; 333 } 334 335 /** Manage handoff of user `bool` `source_array` to backend with proper @ref CeedCopyMode behavior. 336 337 @param[in] source_array Source data provided by user 338 @param[in] copy_mode Copy mode for the data 339 @param[in] num_values Number of values to handle 340 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 341 @param[out] target_array_borrowed Pointer to location to hold borrowed data 342 @param[out] target_array Pointer to location for data 343 344 @return An error code: 0 - success, otherwise - failure 345 346 @ref Backend 347 **/ 348 int CeedSetHostBoolArray(const bool *source_array, CeedCopyMode copy_mode, CeedSize num_values, const bool **target_array_owned, 349 const bool **target_array_borrowed, const bool **target_array) { 350 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(bool), num_values, target_array_owned, target_array_borrowed, target_array)); 351 return CEED_ERROR_SUCCESS; 352 } 353 354 /** Manage handoff of user `CeedInt8` `source_array` to backend with proper @ref CeedCopyMode behavior. 355 356 @param[in] source_array Source data provided by user 357 @param[in] copy_mode Copy mode for the data 358 @param[in] num_values Number of values to handle 359 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 360 @param[out] target_array_borrowed Pointer to location to hold borrowed data 361 @param[out] target_array Pointer to location for data 362 363 @return An error code: 0 - success, otherwise - failure 364 365 @ref Backend 366 **/ 367 int CeedSetHostCeedInt8Array(const CeedInt8 *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt8 **target_array_owned, 368 const CeedInt8 **target_array_borrowed, const CeedInt8 **target_array) { 369 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt8), num_values, target_array_owned, target_array_borrowed, target_array)); 370 return CEED_ERROR_SUCCESS; 371 } 372 373 /** Manage handoff of user `CeedInt` `source_array` to backend with proper @ref CeedCopyMode behavior. 374 375 @param[in] source_array Source data provided by user 376 @param[in] copy_mode Copy mode for the data 377 @param[in] num_values Number of values to handle 378 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 379 @param[out] target_array_borrowed Pointer to location to hold borrowed data 380 @param[out] target_array Pointer to location for data 381 382 @return An error code: 0 - success, otherwise - failure 383 384 @ref Backend 385 **/ 386 int CeedSetHostCeedIntArray(const CeedInt *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt **target_array_owned, 387 const CeedInt **target_array_borrowed, const CeedInt **target_array) { 388 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt), num_values, target_array_owned, target_array_borrowed, target_array)); 389 return CEED_ERROR_SUCCESS; 390 } 391 392 /** Manage handoff of user `CeedScalar` `source_array` to backend with proper @ref CeedCopyMode behavior. 393 394 @param[in] source_array Source data provided by user 395 @param[in] copy_mode Copy mode for the data 396 @param[in] num_values Number of values to handle 397 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 398 @param[out] target_array_borrowed Pointer to location to hold borrowed data 399 @param[out] target_array Pointer to location for data 400 401 @return An error code: 0 - success, otherwise - failure 402 403 @ref Backend 404 **/ 405 int CeedSetHostCeedScalarArray(const CeedScalar *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedScalar **target_array_owned, 406 const CeedScalar **target_array_borrowed, const CeedScalar **target_array) { 407 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedScalar), num_values, target_array_owned, target_array_borrowed, target_array)); 408 return CEED_ERROR_SUCCESS; 409 } 410 411 /** 412 @brief Register a `Ceed` backend 413 414 @param[in] prefix Prefix of resources for this backend to respond to. 415 For example, the reference backend responds to "/cpu/self". 416 @param[in] init Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource 417 @param[in] priority Integer priority. 418 Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match. 419 420 @return An error code: 0 - success, otherwise - failure 421 422 @ref Backend 423 **/ 424 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) { 425 CeedDebugEnv("Backend Register: %s", prefix); 426 CeedRegisterImpl(prefix, init, priority); 427 return CEED_ERROR_SUCCESS; 428 } 429 430 /** 431 @brief Return debugging status flag 432 433 @param[in] ceed `Ceed` context to get debugging flag 434 @param[out] is_debug Variable to store debugging flag 435 436 @return An error code: 0 - success, otherwise - failure 437 438 @ref Backend 439 **/ 440 int CeedIsDebug(Ceed ceed, bool *is_debug) { 441 *is_debug = ceed->is_debug; 442 return CEED_ERROR_SUCCESS; 443 } 444 445 /** 446 @brief Get the root of the requested resource 447 448 @param[in] ceed `Ceed` context to get resource name of 449 @param[in] resource Full user specified resource 450 @param[in] delineator Delineator to break `resource_root` and `resource_spec` 451 @param[out] resource_root Variable to store resource root 452 453 @return An error code: 0 - success, otherwise - failure 454 455 @ref Backend 456 **/ 457 int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) { 458 char *device_spec = strstr(resource, delineator); 459 size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1; 460 461 CeedCall(CeedCalloc(resource_root_len, resource_root)); 462 memcpy(*resource_root, resource, resource_root_len - 1); 463 return CEED_ERROR_SUCCESS; 464 } 465 466 /** 467 @brief Retrieve a parent `Ceed` context 468 469 @param[in] ceed `Ceed` context to retrieve parent of 470 @param[out] parent Address to save the parent to 471 472 @return An error code: 0 - success, otherwise - failure 473 474 @ref Backend 475 **/ 476 int CeedGetParent(Ceed ceed, Ceed *parent) { 477 if (ceed->parent) { 478 CeedCall(CeedGetParent(ceed->parent, parent)); 479 return CEED_ERROR_SUCCESS; 480 } 481 *parent = ceed; 482 return CEED_ERROR_SUCCESS; 483 } 484 485 /** 486 @brief Retrieve a delegate `Ceed` context 487 488 @param[in] ceed `Ceed` context to retrieve delegate of 489 @param[out] delegate Address to save the delegate to 490 491 @return An error code: 0 - success, otherwise - failure 492 493 @ref Backend 494 **/ 495 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 496 *delegate = ceed->delegate; 497 return CEED_ERROR_SUCCESS; 498 } 499 500 /** 501 @brief Set a delegate `Ceed` context 502 503 This function allows a `Ceed` context to set a delegate `Ceed` context. 504 All backend implementations default to the delegate `Ceed` context, unless overridden. 505 506 @param[in] ceed `Ceed` context to set delegate of 507 @param[out] delegate Address to set the delegate to 508 509 @return An error code: 0 - success, otherwise - failure 510 511 @ref Backend 512 **/ 513 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 514 ceed->delegate = delegate; 515 delegate->parent = ceed; 516 return CEED_ERROR_SUCCESS; 517 } 518 519 /** 520 @brief Retrieve a delegate `Ceed` context for a specific object type 521 522 @param[in] ceed `Ceed` context to retrieve delegate of 523 @param[out] delegate Address to save the delegate to 524 @param[in] obj_name Name of the object type to retrieve delegate for 525 526 @return An error code: 0 - success, otherwise - failure 527 528 @ref Backend 529 **/ 530 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) { 531 // Check for object delegate 532 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) { 533 if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) { 534 *delegate = ceed->obj_delegates->delegate; 535 return CEED_ERROR_SUCCESS; 536 } 537 } 538 539 // Use default delegate if no object delegate 540 CeedCall(CeedGetDelegate(ceed, delegate)); 541 return CEED_ERROR_SUCCESS; 542 } 543 544 /** 545 @brief Set a delegate `Ceed` context for a specific object type 546 547 This function allows a `Ceed` context to set a delegate `Ceed` context for a given type of `Ceed` object. 548 All backend implementations default to the delegate `Ceed` context for this object. 549 For example, `CeedSetObjectDelegate(ceed, delegate, "Basis")` uses delegate implementations for all `CeedBasis` backend functions. 550 551 @param[in,out] ceed `Ceed` context to set delegate of 552 @param[in] delegate `Ceed` context to use for delegation 553 @param[in] obj_name Name of the object type to set delegate for 554 555 @return An error code: 0 - success, otherwise - failure 556 557 @ref Backend 558 **/ 559 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) { 560 CeedInt count = ceed->obj_delegate_count; 561 562 // Malloc or Realloc 563 if (count) { 564 CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates)); 565 } else { 566 CeedCall(CeedCalloc(1, &ceed->obj_delegates)); 567 } 568 ceed->obj_delegate_count++; 569 570 // Set object delegate 571 ceed->obj_delegates[count].delegate = delegate; 572 CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name)); 573 574 // Set delegate parent 575 delegate->parent = ceed; 576 return CEED_ERROR_SUCCESS; 577 } 578 579 /** 580 @brief Get the fallback resource for `CeedOperator` 581 582 @param[in] ceed `Ceed` context 583 @param[out] resource Variable to store fallback resource 584 585 @return An error code: 0 - success, otherwise - failure 586 587 @ref Backend 588 **/ 589 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 590 *resource = (const char *)ceed->op_fallback_resource; 591 return CEED_ERROR_SUCCESS; 592 } 593 594 /** 595 @brief Get the fallback `Ceed` for `CeedOperator` 596 597 @param[in] ceed `Ceed` context 598 @param[out] fallback_ceed Variable to store fallback `Ceed` 599 600 @return An error code: 0 - success, otherwise - failure 601 602 @ref Backend 603 **/ 604 int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) { 605 if (ceed->has_valid_op_fallback_resource) { 606 CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- CeedOperator Fallback ----------\n"); 607 CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource); 608 } 609 610 // Create fallback Ceed if uninitalized 611 if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) { 612 CeedDebug(ceed, "Creating fallback Ceed"); 613 614 Ceed fallback_ceed; 615 const char *fallback_resource; 616 617 CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource)); 618 CeedCall(CeedInit(fallback_resource, &fallback_ceed)); 619 fallback_ceed->op_fallback_parent = ceed; 620 fallback_ceed->Error = ceed->Error; 621 ceed->op_fallback_ceed = fallback_ceed; 622 } 623 *fallback_ceed = ceed->op_fallback_ceed; 624 return CEED_ERROR_SUCCESS; 625 } 626 627 /** 628 @brief Set the fallback resource for `CeedOperator`. 629 630 The current resource, if any, is freed by calling this function. 631 This string is freed upon the destruction of the `Ceed` context. 632 633 @param[in,out] ceed `Ceed` context 634 @param[in] resource Fallback resource to set 635 636 @return An error code: 0 - success, otherwise - failure 637 638 @ref Backend 639 **/ 640 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 641 // Free old 642 CeedCall(CeedFree(&ceed->op_fallback_resource)); 643 644 // Set new 645 CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource)); 646 647 // Check validity 648 ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource); 649 return CEED_ERROR_SUCCESS; 650 } 651 652 /** 653 @brief Flag `Ceed` context as deterministic 654 655 @param[in] ceed `Ceed` to flag as deterministic 656 @param[out] is_deterministic Deterministic status to set 657 658 @return An error code: 0 - success, otherwise - failure 659 660 @ref Backend 661 **/ 662 int CeedSetDeterministic(Ceed ceed, bool is_deterministic) { 663 ceed->is_deterministic = is_deterministic; 664 return CEED_ERROR_SUCCESS; 665 } 666 667 /** 668 @brief Set a backend function. 669 670 This function is used for a backend to set the function associated with the Ceed objects. 671 For example, `CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)` sets the backend implementation of @ref CeedVectorCreate() and `CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)` sets the backend implementation of @ref CeedBasisApply(). 672 Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis"). 673 674 @param[in] ceed `Ceed` context for error handling 675 @param[in] type Type of Ceed object to set function for 676 @param[out] object Ceed object to set function for 677 @param[in] func_name Name of function to set 678 @param[in] f Function to set 679 680 @return An error code: 0 - success, otherwise - failure 681 682 @ref Backend 683 **/ 684 int CeedSetBackendFunctionImpl(Ceed ceed, const char *type, void *object, const char *func_name, void (*f)(void)) { 685 char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = ""; 686 687 // Build lookup name 688 if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN); 689 strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN); 690 strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN); 691 692 // Find and use offset 693 for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) { 694 if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) { 695 size_t offset = ceed->f_offsets[i].offset; 696 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 697 698 *fpointer = (int (*)(void))f; 699 return CEED_ERROR_SUCCESS; 700 } 701 } 702 703 // LCOV_EXCL_START 704 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type); 705 // LCOV_EXCL_STOP 706 } 707 708 /** 709 @brief Retrieve backend data for a `Ceed` context 710 711 @param[in] ceed `Ceed` context to retrieve data of 712 @param[out] data Address to save data to 713 714 @return An error code: 0 - success, otherwise - failure 715 716 @ref Backend 717 **/ 718 int CeedGetData(Ceed ceed, void *data) { 719 *(void **)data = ceed->data; 720 return CEED_ERROR_SUCCESS; 721 } 722 723 /** 724 @brief Set backend data for a `Ceed` context 725 726 @param[in,out] ceed `Ceed` context to set data of 727 @param[in] data Address of data to set 728 729 @return An error code: 0 - success, otherwise - failure 730 731 @ref Backend 732 **/ 733 int CeedSetData(Ceed ceed, void *data) { 734 ceed->data = data; 735 return CEED_ERROR_SUCCESS; 736 } 737 738 /** 739 @brief Increment the reference counter for a `Ceed` context 740 741 @param[in,out] ceed `Ceed` context to increment the reference counter 742 743 @return An error code: 0 - success, otherwise - failure 744 745 @ref Backend 746 **/ 747 int CeedReference(Ceed ceed) { 748 ceed->ref_count++; 749 return CEED_ERROR_SUCCESS; 750 } 751 752 /// @} 753 754 /// ---------------------------------------------------------------------------- 755 /// Ceed Public API 756 /// ---------------------------------------------------------------------------- 757 /// @addtogroup CeedUser 758 /// @{ 759 760 /** 761 @brief Get the list of available resource names for `Ceed` contexts 762 763 Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources array. 764 765 @param[out] n Number of available resources 766 @param[out] resources List of available resource names 767 @param[out] priorities Resource name prioritization values, lower is better 768 769 @return An error code: 0 - success, otherwise - failure 770 771 @ref User 772 **/ 773 // LCOV_EXCL_START 774 int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) { 775 *n = 0; 776 *resources = malloc(num_backends * sizeof(**resources)); 777 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 778 if (priorities) { 779 *priorities = malloc(num_backends * sizeof(**priorities)); 780 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 781 } 782 for (size_t i = 0; i < num_backends; i++) { 783 // Only report compiled backends 784 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) { 785 *resources[i] = backends[i].prefix; 786 if (priorities) *priorities[i] = backends[i].priority; 787 *n += 1; 788 } 789 } 790 CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed"); 791 *resources = realloc(*resources, *n * sizeof(**resources)); 792 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 793 if (priorities) { 794 *priorities = realloc(*priorities, *n * sizeof(**priorities)); 795 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 796 } 797 return CEED_ERROR_SUCCESS; 798 } 799 // LCOV_EXCL_STOP 800 801 /** 802 @brief Initialize a `Ceed` context to use the specified resource. 803 804 Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") will result in @ref CeedInt() printing the current libCEED version number and a list of current available backend resources to `stderr`. 805 806 @param[in] resource Resource to use, e.g., "/cpu/self" 807 @param[out] ceed The library context 808 809 @return An error code: 0 - success, otherwise - failure 810 811 @ref User 812 813 @sa CeedRegister() CeedDestroy() 814 **/ 815 int CeedInit(const char *resource, Ceed *ceed) { 816 size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority; 817 818 // Find matching backend 819 CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided"); 820 CeedCall(CeedRegisterAll()); 821 822 // Check for help request 823 const char *help_prefix = "help"; 824 size_t match_help = 0; 825 while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++; 826 if (match_help == 4) { 827 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH, 828 CEED_VERSION_RELEASE ? "" : "+development"); 829 fprintf(stderr, "Available backend resources:\n"); 830 for (size_t i = 0; i < num_backends; i++) { 831 // Only report compiled backends 832 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, " %s\n", backends[i].prefix); 833 } 834 fflush(stderr); 835 match_help = 5; // Delineating character expected 836 } else { 837 match_help = 0; 838 } 839 840 // Find best match, computed as number of matching characters from requested resource stem 841 size_t stem_length = 0; 842 while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++; 843 for (size_t i = 0; i < num_backends; i++) { 844 size_t n = 0; 845 const char *prefix = backends[i].prefix; 846 while (prefix[n] && prefix[n] == resource[n + match_help]) n++; 847 priority = backends[i].priority; 848 if (n > match_len || (n == match_len && match_priority > priority)) { 849 match_len = n; 850 match_priority = priority; 851 match_index = i; 852 } 853 } 854 // Using Levenshtein distance to find closest match 855 if (match_len <= 1 || match_len != stem_length) { 856 // LCOV_EXCL_START 857 size_t lev_dis = UINT_MAX; 858 size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY; 859 for (size_t i = 0; i < num_backends; i++) { 860 const char *prefix = backends[i].prefix; 861 size_t prefix_length = strlen(backends[i].prefix); 862 size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length; 863 size_t column[min_len + 1]; 864 for (size_t j = 0; j <= min_len; j++) column[j] = j; 865 for (size_t j = 1; j <= min_len; j++) { 866 column[0] = j; 867 for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) { 868 size_t old_diag = column[k]; 869 size_t min_1 = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1; 870 size_t min_2 = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1); 871 column[k] = (min_1 < min_2) ? min_1 : min_2; 872 last_diag = old_diag; 873 } 874 } 875 size_t n = column[min_len]; 876 priority = backends[i].priority; 877 if (n < lev_dis || (n == lev_dis && lev_priority > priority)) { 878 lev_dis = n; 879 lev_priority = priority; 880 lev_index = i; 881 } 882 } 883 const char *prefix_lev = backends[lev_index].prefix; 884 size_t lev_length = 0; 885 while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++; 886 size_t m = (lev_length < stem_length) ? lev_length : stem_length; 887 if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource); 888 else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix); 889 // LCOV_EXCL_STOP 890 } 891 892 // Setup Ceed 893 CeedCall(CeedCalloc(1, ceed)); 894 CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots)); 895 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 896 if (!ceed_error_handler) ceed_error_handler = "abort"; 897 if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit; 898 else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore; 899 else (*ceed)->Error = CeedErrorAbort; 900 memcpy((*ceed)->err_msg, "No error message stored", 24); 901 (*ceed)->ref_count = 1; 902 (*ceed)->data = NULL; 903 904 // Set lookup table 905 FOffset f_offsets[] = { 906 CEED_FTABLE_ENTRY(Ceed, Error), 907 CEED_FTABLE_ENTRY(Ceed, SetStream), 908 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 909 CEED_FTABLE_ENTRY(Ceed, Destroy), 910 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 911 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 912 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints), 913 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 914 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 915 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 916 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 917 CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl), 918 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 919 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 920 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 921 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 922 CEED_FTABLE_ENTRY(Ceed, OperatorCreateAtPoints), 923 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 924 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 925 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 926 CEED_FTABLE_ENTRY(CeedVector, SetArray), 927 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 928 CEED_FTABLE_ENTRY(CeedVector, SetValue), 929 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 930 CEED_FTABLE_ENTRY(CeedVector, GetArray), 931 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 932 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 933 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 934 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 935 CEED_FTABLE_ENTRY(CeedVector, Norm), 936 CEED_FTABLE_ENTRY(CeedVector, Scale), 937 CEED_FTABLE_ENTRY(CeedVector, AXPY), 938 CEED_FTABLE_ENTRY(CeedVector, AXPBY), 939 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 940 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 941 CEED_FTABLE_ENTRY(CeedVector, Destroy), 942 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 943 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned), 944 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented), 945 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement), 946 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 947 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 948 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations), 949 CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations), 950 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 951 CEED_FTABLE_ENTRY(CeedBasis, Apply), 952 CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints), 953 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 954 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 955 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 956 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 957 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 958 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 959 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 960 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 961 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 962 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 963 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 964 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 965 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 966 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 967 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 968 CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy), 969 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 970 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 971 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 972 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 973 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 974 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 975 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 976 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 977 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 978 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle), 979 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 980 CEED_FTABLE_ENTRY(CeedOperator, Apply), 981 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 982 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 983 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 984 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 985 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 986 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 987 }; 988 989 CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets)); 990 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 991 992 // Set fallback for advanced CeedOperator functions 993 const char fallback_resource[] = ""; 994 CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource)); 995 996 // Record env variables CEED_DEBUG or DBG 997 (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); 998 999 // Copy resource prefix, if backend setup successful 1000 CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource)); 1001 1002 // Set default JiT source root 1003 // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent 1004 CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault)); 1005 1006 // Backend specific setup 1007 CeedCall(backends[match_index].init(&resource[match_help], *ceed)); 1008 return CEED_ERROR_SUCCESS; 1009 } 1010 1011 /** 1012 @brief Set the GPU stream for a `Ceed` context 1013 1014 @param[in,out] ceed `Ceed` context to set the stream 1015 @param[in] handle Handle to GPU stream 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref User 1020 **/ 1021 int CeedSetStream(Ceed ceed, void *handle) { 1022 CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-NULL"); 1023 if (ceed->SetStream) { 1024 CeedCall(ceed->SetStream(ceed, handle)); 1025 } else { 1026 Ceed delegate; 1027 CeedCall(CeedGetDelegate(ceed, &delegate)); 1028 1029 if (delegate) CeedCall(CeedSetStream(delegate, handle)); 1030 else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream"); 1031 } 1032 return CEED_ERROR_SUCCESS; 1033 } 1034 1035 /** 1036 @brief Copy the pointer to a `Ceed` context. 1037 1038 Both pointers should be destroyed with @ref CeedDestroy(). 1039 1040 Note: If the value of `*ceed_copy` passed to this function is non-`NULL`, then it is assumed that `*ceed_copy` is a pointer to a `Ceed` context. 1041 This `Ceed` context will be destroyed if `*ceed_copy` is the only reference to this `Ceed` context. 1042 1043 @param[in] ceed `Ceed` context to copy reference to 1044 @param[in,out] ceed_copy Variable to store copied reference 1045 1046 @return An error code: 0 - success, otherwise - failure 1047 1048 @ref User 1049 **/ 1050 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 1051 CeedCall(CeedReference(ceed)); 1052 CeedCall(CeedDestroy(ceed_copy)); 1053 *ceed_copy = ceed; 1054 return CEED_ERROR_SUCCESS; 1055 } 1056 1057 /** 1058 @brief Get the full resource name for a `Ceed` context 1059 1060 @param[in] ceed `Ceed` context to get resource name of 1061 @param[out] resource Variable to store resource name 1062 1063 @return An error code: 0 - success, otherwise - failure 1064 1065 @ref User 1066 **/ 1067 int CeedGetResource(Ceed ceed, const char **resource) { 1068 *resource = (const char *)ceed->resource; 1069 return CEED_ERROR_SUCCESS; 1070 } 1071 1072 /** 1073 @brief Return `Ceed` context preferred memory type 1074 1075 @param[in] ceed `Ceed` context to get preferred memory type of 1076 @param[out] mem_type Address to save preferred memory type to 1077 1078 @return An error code: 0 - success, otherwise - failure 1079 1080 @ref User 1081 **/ 1082 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 1083 if (ceed->GetPreferredMemType) { 1084 CeedCall(ceed->GetPreferredMemType(mem_type)); 1085 } else { 1086 Ceed delegate; 1087 CeedCall(CeedGetDelegate(ceed, &delegate)); 1088 1089 if (delegate) { 1090 CeedCall(CeedGetPreferredMemType(delegate, mem_type)); 1091 } else { 1092 *mem_type = CEED_MEM_HOST; 1093 } 1094 } 1095 return CEED_ERROR_SUCCESS; 1096 } 1097 1098 /** 1099 @brief Get deterministic status of `Ceed` context 1100 1101 @param[in] ceed `Ceed` context 1102 @param[out] is_deterministic Variable to store deterministic status 1103 1104 @return An error code: 0 - success, otherwise - failure 1105 1106 @ref User 1107 **/ 1108 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 1109 *is_deterministic = ceed->is_deterministic; 1110 return CEED_ERROR_SUCCESS; 1111 } 1112 1113 /** 1114 @brief Set additional JiT source root for `Ceed` context 1115 1116 @param[in,out] ceed `Ceed` context 1117 @param[in] jit_source_root Absolute path to additional JiT source directory 1118 1119 @return An error code: 0 - success, otherwise - failure 1120 1121 @ref User 1122 **/ 1123 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1124 Ceed ceed_parent; 1125 1126 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1127 1128 CeedInt index = ceed_parent->num_jit_source_roots; 1129 size_t path_length = strlen(jit_source_root); 1130 1131 CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots)); 1132 CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index])); 1133 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1134 ceed_parent->num_jit_source_roots++; 1135 return CEED_ERROR_SUCCESS; 1136 } 1137 1138 /** 1139 @brief View a `Ceed` 1140 1141 @param[in] ceed `Ceed` to view 1142 @param[in] stream Filestream to write to 1143 1144 @return An error code: 0 - success, otherwise - failure 1145 1146 @ref User 1147 **/ 1148 int CeedView(Ceed ceed, FILE *stream) { 1149 CeedMemType mem_type; 1150 1151 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 1152 1153 fprintf(stream, 1154 "Ceed\n" 1155 " Ceed Resource: %s\n" 1156 " Preferred MemType: %s\n", 1157 ceed->resource, CeedMemTypes[mem_type]); 1158 return CEED_ERROR_SUCCESS; 1159 } 1160 1161 /** 1162 @brief Destroy a `Ceed` 1163 1164 @param[in,out] ceed Address of `Ceed` context to destroy 1165 1166 @return An error code: 0 - success, otherwise - failure 1167 1168 @ref User 1169 **/ 1170 int CeedDestroy(Ceed *ceed) { 1171 if (!*ceed || --(*ceed)->ref_count > 0) { 1172 *ceed = NULL; 1173 return CEED_ERROR_SUCCESS; 1174 } 1175 if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate)); 1176 1177 if ((*ceed)->obj_delegate_count > 0) { 1178 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1179 CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate))); 1180 CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name)); 1181 } 1182 CeedCall(CeedFree(&(*ceed)->obj_delegates)); 1183 } 1184 1185 if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed)); 1186 1187 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1188 CeedCall(CeedFree(&(*ceed)->jit_source_roots[i])); 1189 } 1190 CeedCall(CeedFree(&(*ceed)->jit_source_roots)); 1191 1192 CeedCall(CeedFree(&(*ceed)->f_offsets)); 1193 CeedCall(CeedFree(&(*ceed)->resource)); 1194 CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed)); 1195 CeedCall(CeedFree(&(*ceed)->op_fallback_resource)); 1196 CeedCall(CeedFree(ceed)); 1197 return CEED_ERROR_SUCCESS; 1198 } 1199 1200 // LCOV_EXCL_START 1201 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1202 if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args); 1203 if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args); 1204 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1205 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1206 return ceed->err_msg; 1207 } 1208 // LCOV_EXCL_STOP 1209 1210 /** 1211 @brief Error handling implementation; use @ref CeedError() instead. 1212 1213 @return An error code: 0 - success, otherwise - failure 1214 1215 @ref Developer 1216 **/ 1217 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) { 1218 va_list args; 1219 int ret_val; 1220 1221 va_start(args, format); 1222 if (ceed) { 1223 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1224 } else { 1225 // LCOV_EXCL_START 1226 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1227 if (!ceed_error_handler) ceed_error_handler = "abort"; 1228 if (!strcmp(ceed_error_handler, "return")) { 1229 ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1230 } else { 1231 // This function will not return 1232 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1233 } 1234 } 1235 va_end(args); 1236 return ret_val; 1237 // LCOV_EXCL_STOP 1238 } 1239 1240 /** 1241 @brief Error handler that returns without printing anything. 1242 1243 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1244 1245 @return An error code: 0 - success, otherwise - failure 1246 1247 @ref Developer 1248 **/ 1249 // LCOV_EXCL_START 1250 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1251 return err_code; 1252 } 1253 // LCOV_EXCL_STOP 1254 1255 /** 1256 @brief Error handler that stores the error message for future use and returns the error. 1257 1258 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1259 1260 @return An error code: 0 - success, otherwise - failure 1261 1262 @ref Developer 1263 **/ 1264 // LCOV_EXCL_START 1265 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1266 if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args); 1267 if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args); 1268 1269 // Build message 1270 int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func); 1271 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1272 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1273 return err_code; 1274 } 1275 // LCOV_EXCL_STOP 1276 1277 /** 1278 @brief Error handler that prints to `stderr` and aborts 1279 1280 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1281 1282 @return An error code: 0 - success, otherwise - failure 1283 1284 @ref Developer 1285 **/ 1286 // LCOV_EXCL_START 1287 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1288 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1289 vfprintf(stderr, format, *args); 1290 fprintf(stderr, "\n"); 1291 abort(); 1292 return err_code; 1293 } 1294 // LCOV_EXCL_STOP 1295 1296 /** 1297 @brief Error handler that prints to `stderr` and exits. 1298 1299 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1300 1301 In contrast to @ref CeedErrorAbort(), this exits without a signal, so `atexit()` handlers (e.g., as used by gcov) are run. 1302 1303 @return An error code: 0 - success, otherwise - failure 1304 1305 @ref Developer 1306 **/ 1307 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1308 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1309 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1310 vfprintf(stderr, format, *args); // NOLINT 1311 fprintf(stderr, "\n"); 1312 exit(err_code); 1313 return err_code; 1314 } 1315 1316 /** 1317 @brief Set error handler 1318 1319 A default error handler is set in @ref CeedInit(). 1320 Use this function to change the error handler to @ref CeedErrorReturn(), @ref CeedErrorAbort(), or a user-defined error handler. 1321 1322 @return An error code: 0 - success, otherwise - failure 1323 1324 @ref Developer 1325 **/ 1326 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1327 ceed->Error = handler; 1328 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1329 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1330 return CEED_ERROR_SUCCESS; 1331 } 1332 1333 /** 1334 @brief Get error message 1335 1336 The error message is only stored when using the error handler @ref CeedErrorStore() 1337 1338 @param[in] ceed `Ceed` context to retrieve error message 1339 @param[out] err_msg Char pointer to hold error message 1340 1341 @return An error code: 0 - success, otherwise - failure 1342 1343 @ref Developer 1344 **/ 1345 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1346 if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg); 1347 if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg); 1348 *err_msg = ceed->err_msg; 1349 return CEED_ERROR_SUCCESS; 1350 } 1351 1352 /** 1353 @brief Restore error message. 1354 1355 The error message is only stored when using the error handler @ref CeedErrorStore(). 1356 1357 @param[in] ceed `Ceed` context to restore error message 1358 @param[out] err_msg Char pointer that holds error message 1359 1360 @return An error code: 0 - success, otherwise - failure 1361 1362 @ref Developer 1363 **/ 1364 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1365 if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg); 1366 if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg); 1367 *err_msg = NULL; 1368 memcpy(ceed->err_msg, "No error message stored", 24); 1369 return CEED_ERROR_SUCCESS; 1370 } 1371 1372 /** 1373 @brief Get libCEED library version information. 1374 1375 libCEED version numbers have the form major.minor.patch. 1376 Non-release versions may contain unstable interfaces. 1377 1378 @param[out] major Major version of the library 1379 @param[out] minor Minor version of the library 1380 @param[out] patch Patch (subminor) version of the library 1381 @param[out] release True for releases; false for development branches 1382 1383 The caller may pass `NULL` for any arguments that are not needed. 1384 1385 @return An error code: 0 - success, otherwise - failure 1386 1387 @ref Developer 1388 1389 @sa CEED_VERSION_GE() 1390 */ 1391 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1392 if (major) *major = CEED_VERSION_MAJOR; 1393 if (minor) *minor = CEED_VERSION_MINOR; 1394 if (patch) *patch = CEED_VERSION_PATCH; 1395 if (release) *release = CEED_VERSION_RELEASE; 1396 return CEED_ERROR_SUCCESS; 1397 } 1398 1399 /** 1400 @brief Get libCEED scalar type, such as F64 or F32 1401 1402 @param[out] scalar_type Type of libCEED scalars 1403 1404 @return An error code: 0 - success, otherwise - failure 1405 1406 @ref Developer 1407 */ 1408 int CeedGetScalarType(CeedScalarType *scalar_type) { 1409 *scalar_type = CEED_SCALAR_TYPE; 1410 return CEED_ERROR_SUCCESS; 1411 } 1412 1413 /// @} 1414