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