1 // Copyright (c) 2017-2025, 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 @brief Create a work vector space for a `ceed` 143 144 @param[in,out] ceed `Ceed` to create work vector space for 145 146 @return An error code: 0 - success, otherwise - failure 147 148 @ref Developer 149 **/ 150 static int CeedWorkVectorsCreate(Ceed ceed) { 151 CeedCall(CeedCalloc(1, &ceed->work_vectors)); 152 return CEED_ERROR_SUCCESS; 153 } 154 155 /** 156 @brief Destroy a work vector space for a `ceed` 157 158 @param[in,out] ceed `Ceed` to destroy work vector space for 159 160 @return An error code: 0 - success, otherwise - failure 161 162 @ref Developer 163 **/ 164 static int CeedWorkVectorsDestroy(Ceed ceed) { 165 if (!ceed->work_vectors) return CEED_ERROR_SUCCESS; 166 for (CeedSize i = 0; i < ceed->work_vectors->num_vecs; i++) { 167 CeedCheck(!ceed->work_vectors->is_in_use[i], ceed, CEED_ERROR_ACCESS, "Work vector %" CeedSize_FMT " checked out but not returned"); 168 ceed->ref_count += 2; // Note: increase ref_count to prevent Ceed destructor from triggering again 169 CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i])); 170 ceed->ref_count -= 1; // Note: restore ref_count 171 } 172 CeedCall(CeedFree(&ceed->work_vectors->is_in_use)); 173 CeedCall(CeedFree(&ceed->work_vectors->vecs)); 174 CeedCall(CeedFree(&ceed->work_vectors)); 175 return CEED_ERROR_SUCCESS; 176 } 177 178 /// @} 179 180 /// ---------------------------------------------------------------------------- 181 /// Ceed Backend API 182 /// ---------------------------------------------------------------------------- 183 /// @addtogroup CeedBackend 184 /// @{ 185 186 /** 187 @brief Return value of `CEED_DEBUG` environment variable 188 189 @param[in] ceed `Ceed` context 190 191 @return Boolean value: true - debugging mode enabled 192 false - debugging mode disabled 193 194 @ref Backend 195 **/ 196 // LCOV_EXCL_START 197 bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; } 198 // LCOV_EXCL_STOP 199 200 /** 201 @brief Return value of `CEED_DEBUG` environment variable 202 203 @return Boolean value: true - debugging mode enabled 204 false - debugging mode disabled 205 206 @ref Backend 207 **/ 208 // LCOV_EXCL_START 209 bool CeedDebugFlagEnv(void) { return getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); } 210 // LCOV_EXCL_STOP 211 212 /** 213 @brief Print debugging information in color 214 215 @param[in] color Color to print 216 @param[in] format Printing format 217 218 @ref Backend 219 **/ 220 // LCOV_EXCL_START 221 void CeedDebugImpl256(const unsigned char color, const char *format, ...) { 222 va_list args; 223 va_start(args, format); 224 fflush(stdout); 225 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color); 226 vfprintf(stdout, format, args); 227 if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m"); 228 fprintf(stdout, "\n"); 229 fflush(stdout); 230 va_end(args); 231 } 232 // LCOV_EXCL_STOP 233 234 /** 235 @brief Allocate an array on the host; use @ref CeedMalloc(). 236 237 Memory usage can be tracked by the library. 238 This ensures sufficient alignment for vectorization and should be used for large allocations. 239 240 @param[in] n Number of units to allocate 241 @param[in] unit Size of each unit 242 @param[out] p Address of pointer to hold the result 243 244 @return An error code: 0 - success, otherwise - failure 245 246 @ref Backend 247 248 @sa CeedFree() 249 **/ 250 int CeedMallocArray(size_t n, size_t unit, void *p) { 251 int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit); 252 CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit); 253 return CEED_ERROR_SUCCESS; 254 } 255 256 /** 257 @brief Allocate a cleared (zeroed) array on the host; use @ref CeedCalloc(). 258 259 Memory usage can be tracked by the library. 260 261 @param[in] n Number of units to allocate 262 @param[in] unit Size of each unit 263 @param[out] p Address of pointer to hold the result 264 265 @return An error code: 0 - success, otherwise - failure 266 267 @ref Backend 268 269 @sa CeedFree() 270 **/ 271 int CeedCallocArray(size_t n, size_t unit, void *p) { 272 *(void **)p = calloc(n, unit); 273 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit); 274 return CEED_ERROR_SUCCESS; 275 } 276 277 /** 278 @brief Reallocate an array on the host; use @ref CeedRealloc(). 279 280 Memory usage can be tracked by the library. 281 282 @param[in] n Number of units to allocate 283 @param[in] unit Size of each unit 284 @param[out] p Address of pointer to hold the result 285 286 @return An error code: 0 - success, otherwise - failure 287 288 @ref Backend 289 290 @sa CeedFree() 291 **/ 292 int CeedReallocArray(size_t n, size_t unit, void *p) { 293 *(void **)p = realloc(*(void **)p, n * unit); 294 CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit); 295 return CEED_ERROR_SUCCESS; 296 } 297 298 /** 299 @brief Allocate a cleared string buffer on the host. 300 301 Memory usage can be tracked by the library. 302 303 @param[in] source Pointer to string to be copied 304 @param[out] copy Pointer to variable to hold newly allocated string copy 305 306 @return An error code: 0 - success, otherwise - failure 307 308 @ref Backend 309 310 @sa CeedFree() 311 **/ 312 int CeedStringAllocCopy(const char *source, char **copy) { 313 size_t len = strlen(source); 314 CeedCall(CeedCalloc(len + 1, copy)); 315 memcpy(*copy, source, len); 316 return CEED_ERROR_SUCCESS; 317 } 318 319 /** Free memory allocated using @ref CeedMalloc() or @ref CeedCalloc() 320 321 @param[in,out] p Address of pointer to memory. 322 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. 323 324 @return An error code: 0 - success, otherwise - failure 325 326 @ref Backend 327 **/ 328 int CeedFree(void *p) { 329 free(*(void **)p); 330 *(void **)p = NULL; 331 return CEED_ERROR_SUCCESS; 332 } 333 334 /** Internal helper to manage handoff of user `source_array` to backend with proper @ref CeedCopyMode behavior. 335 336 @param[in] source_array Source data provided by user 337 @param[in] copy_mode Copy mode for the data 338 @param[in] num_values Number of values to handle 339 @param[in] size_unit Size of array element in bytes 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 static inline int CeedSetHostGenericArray(const void *source_array, CeedCopyMode copy_mode, size_t size_unit, CeedSize num_values, 349 void *target_array_owned, void *target_array_borrowed, void *target_array) { 350 switch (copy_mode) { 351 case CEED_COPY_VALUES: 352 if (!*(void **)target_array) { 353 if (*(void **)target_array_borrowed) { 354 *(void **)target_array = *(void **)target_array_borrowed; 355 } else { 356 if (!*(void **)target_array_owned) CeedCall(CeedCallocArray(num_values, size_unit, target_array_owned)); 357 *(void **)target_array = *(void **)target_array_owned; 358 } 359 } 360 if (source_array) memcpy(*(void **)target_array, source_array, size_unit * num_values); 361 break; 362 case CEED_OWN_POINTER: 363 CeedCall(CeedFree(target_array_owned)); 364 *(void **)target_array_owned = (void *)source_array; 365 *(void **)target_array_borrowed = NULL; 366 *(void **)target_array = *(void **)target_array_owned; 367 break; 368 case CEED_USE_POINTER: 369 CeedCall(CeedFree(target_array_owned)); 370 *(void **)target_array_owned = NULL; 371 *(void **)target_array_borrowed = (void *)source_array; 372 *(void **)target_array = *(void **)target_array_borrowed; 373 } 374 return CEED_ERROR_SUCCESS; 375 } 376 377 /** Manage handoff of user `bool` `source_array` to backend with proper @ref CeedCopyMode behavior. 378 379 @param[in] source_array Source data provided by user 380 @param[in] copy_mode Copy mode for the data 381 @param[in] num_values Number of values to handle 382 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 383 @param[out] target_array_borrowed Pointer to location to hold borrowed data 384 @param[out] target_array Pointer to location for data 385 386 @return An error code: 0 - success, otherwise - failure 387 388 @ref Backend 389 **/ 390 int CeedSetHostBoolArray(const bool *source_array, CeedCopyMode copy_mode, CeedSize num_values, const bool **target_array_owned, 391 const bool **target_array_borrowed, const bool **target_array) { 392 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(bool), num_values, target_array_owned, target_array_borrowed, target_array)); 393 return CEED_ERROR_SUCCESS; 394 } 395 396 /** Manage handoff of user `CeedInt8` `source_array` to backend with proper @ref CeedCopyMode behavior. 397 398 @param[in] source_array Source data provided by user 399 @param[in] copy_mode Copy mode for the data 400 @param[in] num_values Number of values to handle 401 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 402 @param[out] target_array_borrowed Pointer to location to hold borrowed data 403 @param[out] target_array Pointer to location for data 404 405 @return An error code: 0 - success, otherwise - failure 406 407 @ref Backend 408 **/ 409 int CeedSetHostCeedInt8Array(const CeedInt8 *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt8 **target_array_owned, 410 const CeedInt8 **target_array_borrowed, const CeedInt8 **target_array) { 411 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt8), num_values, target_array_owned, target_array_borrowed, target_array)); 412 return CEED_ERROR_SUCCESS; 413 } 414 415 /** Manage handoff of user `CeedInt` `source_array` to backend with proper @ref CeedCopyMode behavior. 416 417 @param[in] source_array Source data provided by user 418 @param[in] copy_mode Copy mode for the data 419 @param[in] num_values Number of values to handle 420 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 421 @param[out] target_array_borrowed Pointer to location to hold borrowed data 422 @param[out] target_array Pointer to location for data 423 424 @return An error code: 0 - success, otherwise - failure 425 426 @ref Backend 427 **/ 428 int CeedSetHostCeedIntArray(const CeedInt *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt **target_array_owned, 429 const CeedInt **target_array_borrowed, const CeedInt **target_array) { 430 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt), num_values, target_array_owned, target_array_borrowed, target_array)); 431 return CEED_ERROR_SUCCESS; 432 } 433 434 /** Manage handoff of user `CeedScalar` `source_array` to backend with proper @ref CeedCopyMode behavior. 435 436 @param[in] source_array Source data provided by user 437 @param[in] copy_mode Copy mode for the data 438 @param[in] num_values Number of values to handle 439 @param[in,out] target_array_owned Pointer to location to allocated or hold owned data, may be freed if already allocated 440 @param[out] target_array_borrowed Pointer to location to hold borrowed data 441 @param[out] target_array Pointer to location for data 442 443 @return An error code: 0 - success, otherwise - failure 444 445 @ref Backend 446 **/ 447 int CeedSetHostCeedScalarArray(const CeedScalar *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedScalar **target_array_owned, 448 const CeedScalar **target_array_borrowed, const CeedScalar **target_array) { 449 CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedScalar), num_values, target_array_owned, target_array_borrowed, target_array)); 450 return CEED_ERROR_SUCCESS; 451 } 452 453 /** 454 @brief Register a `Ceed` backend 455 456 @param[in] prefix Prefix of resources for this backend to respond to. 457 For example, the reference backend responds to "/cpu/self". 458 @param[in] init Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource 459 @param[in] priority Integer priority. 460 Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match. 461 462 @return An error code: 0 - success, otherwise - failure 463 464 @ref Backend 465 **/ 466 int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) { 467 CeedDebugEnv("Backend Register: %s", prefix); 468 CeedRegisterImpl(prefix, init, priority); 469 return CEED_ERROR_SUCCESS; 470 } 471 472 /** 473 @brief Return debugging status flag 474 475 @param[in] ceed `Ceed` context to get debugging flag 476 @param[out] is_debug Variable to store debugging flag 477 478 @return An error code: 0 - success, otherwise - failure 479 480 @ref Backend 481 **/ 482 int CeedIsDebug(Ceed ceed, bool *is_debug) { 483 *is_debug = ceed->is_debug; 484 return CEED_ERROR_SUCCESS; 485 } 486 487 /** 488 @brief Get the root of the requested resource. 489 490 Note: Caller is responsible for calling @ref CeedFree() on the `resource_root`. 491 492 @param[in] ceed `Ceed` context to get resource name of 493 @param[in] resource Full user specified resource 494 @param[in] delineator Delineator to break `resource_root` and `resource_spec` 495 @param[out] resource_root Variable to store resource root 496 497 @return An error code: 0 - success, otherwise - failure 498 499 @ref Backend 500 **/ 501 int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) { 502 char *device_spec = strstr(resource, delineator); 503 size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1; 504 505 CeedCall(CeedCalloc(resource_root_len, resource_root)); 506 memcpy(*resource_root, resource, resource_root_len - 1); 507 return CEED_ERROR_SUCCESS; 508 } 509 510 /** 511 @brief Retrieve a parent `Ceed` context 512 513 @param[in] ceed `Ceed` context to retrieve parent of 514 @param[out] parent Address to save the parent to 515 516 @return An error code: 0 - success, otherwise - failure 517 518 @ref Backend 519 **/ 520 int CeedGetParent(Ceed ceed, Ceed *parent) { 521 if (ceed->parent) { 522 CeedCall(CeedGetParent(ceed->parent, parent)); 523 return CEED_ERROR_SUCCESS; 524 } 525 *parent = NULL; 526 CeedCall(CeedReferenceCopy(ceed, parent)); 527 return CEED_ERROR_SUCCESS; 528 } 529 530 /** 531 @brief Retrieve a delegate `Ceed` context 532 533 @param[in] ceed `Ceed` context to retrieve delegate of 534 @param[out] delegate Address to save the delegate to 535 536 @return An error code: 0 - success, otherwise - failure 537 538 @ref Backend 539 **/ 540 int CeedGetDelegate(Ceed ceed, Ceed *delegate) { 541 *delegate = NULL; 542 if (ceed->delegate) CeedCall(CeedReferenceCopy(ceed->delegate, delegate)); 543 return CEED_ERROR_SUCCESS; 544 } 545 546 /** 547 @brief Set a delegate `Ceed` context 548 549 This function allows a `Ceed` context to set a delegate `Ceed` context. 550 All backend implementations default to the delegate `Ceed` context, unless overridden. 551 552 @param[in] ceed `Ceed` context to set delegate of 553 @param[out] delegate Address to set the delegate to 554 555 @return An error code: 0 - success, otherwise - failure 556 557 @ref Backend 558 **/ 559 int CeedSetDelegate(Ceed ceed, Ceed delegate) { 560 CeedCall(CeedReferenceCopy(delegate, &ceed->delegate)); 561 delegate->parent = ceed; 562 return CEED_ERROR_SUCCESS; 563 } 564 565 /** 566 @brief Retrieve a delegate `Ceed` context for a specific object type 567 568 @param[in] ceed `Ceed` context to retrieve delegate of 569 @param[out] delegate Address to save the delegate to 570 @param[in] obj_name Name of the object type to retrieve delegate for 571 572 @return An error code: 0 - success, otherwise - failure 573 574 @ref Backend 575 **/ 576 int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) { 577 // Check for object delegate 578 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) { 579 if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) { 580 *delegate = NULL; 581 CeedCall(CeedReferenceCopy(ceed->obj_delegates->delegate, delegate)); 582 return CEED_ERROR_SUCCESS; 583 } 584 } 585 586 // Use default delegate if no object delegate 587 CeedCall(CeedGetDelegate(ceed, delegate)); 588 return CEED_ERROR_SUCCESS; 589 } 590 591 /** 592 @brief Set a delegate `Ceed` context for a specific object type 593 594 This function allows a `Ceed` context to set a delegate `Ceed` context for a given type of `Ceed` object. 595 All backend implementations default to the delegate `Ceed` context for this object. 596 For example, `CeedSetObjectDelegate(ceed, delegate, "Basis")` uses delegate implementations for all `CeedBasis` backend functions. 597 598 @param[in,out] ceed `Ceed` context to set delegate of 599 @param[in] delegate `Ceed` context to use for delegation 600 @param[in] obj_name Name of the object type to set delegate for 601 602 @return An error code: 0 - success, otherwise - failure 603 604 @ref Backend 605 **/ 606 int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) { 607 CeedInt count = ceed->obj_delegate_count; 608 609 // Malloc or Realloc 610 if (count) { 611 CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates)); 612 } else { 613 CeedCall(CeedCalloc(1, &ceed->obj_delegates)); 614 } 615 ceed->obj_delegate_count++; 616 617 // Set object delegate 618 CeedCall(CeedReferenceCopy(delegate, &ceed->obj_delegates[count].delegate)); 619 CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name)); 620 621 // Set delegate parent 622 delegate->parent = ceed; 623 return CEED_ERROR_SUCCESS; 624 } 625 626 /** 627 @brief Get the fallback resource for `CeedOperator` 628 629 @param[in] ceed `Ceed` context 630 @param[out] resource Variable to store fallback resource 631 632 @return An error code: 0 - success, otherwise - failure 633 634 @ref Backend 635 **/ 636 int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) { 637 *resource = (const char *)ceed->op_fallback_resource; 638 return CEED_ERROR_SUCCESS; 639 } 640 641 /** 642 @brief Get the fallback `Ceed` for `CeedOperator` 643 644 @param[in] ceed `Ceed` context 645 @param[out] fallback_ceed Variable to store fallback `Ceed` 646 647 @return An error code: 0 - success, otherwise - failure 648 649 @ref Backend 650 **/ 651 int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) { 652 if (ceed->has_valid_op_fallback_resource) { 653 CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- Ceed Fallback ----------\n"); 654 CeedDebug(ceed, "Falling back from Ceed with backend %s at address %p to Ceed with backend %s", ceed->resource, ceed, ceed->op_fallback_resource); 655 } 656 657 // Create fallback Ceed if uninitialized 658 if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) { 659 CeedDebug(ceed, "Creating fallback Ceed"); 660 661 Ceed fallback_ceed; 662 const char *fallback_resource; 663 664 CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource)); 665 CeedCall(CeedInit(fallback_resource, &fallback_ceed)); 666 fallback_ceed->parent = ceed; 667 fallback_ceed->Error = ceed->Error; 668 ceed->op_fallback_ceed = fallback_ceed; 669 } 670 *fallback_ceed = NULL; 671 CeedDebug(ceed, "Fallback Ceed with backend %s at address %p\n", ceed->op_fallback_resource, ceed->op_fallback_ceed); 672 if (ceed->op_fallback_ceed) CeedCall(CeedReferenceCopy(ceed->op_fallback_ceed, fallback_ceed)); 673 return CEED_ERROR_SUCCESS; 674 } 675 676 /** 677 @brief Set the fallback resource for `CeedOperator`. 678 679 The current resource, if any, is freed by calling this function. 680 This string is freed upon the destruction of the `Ceed` context. 681 682 @param[in,out] ceed `Ceed` context 683 @param[in] resource Fallback resource to set 684 685 @return An error code: 0 - success, otherwise - failure 686 687 @ref Backend 688 **/ 689 int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) { 690 // Free old 691 CeedCall(CeedFree(&ceed->op_fallback_resource)); 692 693 // Set new 694 CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource)); 695 696 // Check validity 697 ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource); 698 return CEED_ERROR_SUCCESS; 699 } 700 701 /** 702 @brief Flag `Ceed` context as deterministic 703 704 @param[in] ceed `Ceed` to flag as deterministic 705 @param[out] is_deterministic Deterministic status to set 706 707 @return An error code: 0 - success, otherwise - failure 708 709 @ref Backend 710 **/ 711 int CeedSetDeterministic(Ceed ceed, bool is_deterministic) { 712 ceed->is_deterministic = is_deterministic; 713 return CEED_ERROR_SUCCESS; 714 } 715 716 /** 717 @brief Set a backend function. 718 719 This function is used for a backend to set the function associated with the Ceed objects. 720 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(). 721 Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis"). 722 723 @param[in] ceed `Ceed` context for error handling 724 @param[in] type Type of Ceed object to set function for 725 @param[out] object Ceed object to set function for 726 @param[in] func_name Name of function to set 727 @param[in] f Function to set 728 729 @return An error code: 0 - success, otherwise - failure 730 731 @ref Backend 732 **/ 733 int CeedSetBackendFunctionImpl(Ceed ceed, const char *type, void *object, const char *func_name, void (*f)(void)) { 734 char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = ""; 735 736 // Build lookup name 737 if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN); 738 strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN); 739 strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN); 740 741 // Find and use offset 742 for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) { 743 if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) { 744 size_t offset = ceed->f_offsets[i].offset; 745 int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD* 746 747 *fpointer = (int (*)(void))f; 748 return CEED_ERROR_SUCCESS; 749 } 750 } 751 752 // LCOV_EXCL_START 753 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type); 754 // LCOV_EXCL_STOP 755 } 756 757 /** 758 @brief Retrieve backend data for a `Ceed` context 759 760 @param[in] ceed `Ceed` context to retrieve data of 761 @param[out] data Address to save data to 762 763 @return An error code: 0 - success, otherwise - failure 764 765 @ref Backend 766 **/ 767 int CeedGetData(Ceed ceed, void *data) { 768 *(void **)data = ceed->data; 769 return CEED_ERROR_SUCCESS; 770 } 771 772 /** 773 @brief Set backend data for a `Ceed` context 774 775 @param[in,out] ceed `Ceed` context to set data of 776 @param[in] data Address of data to set 777 778 @return An error code: 0 - success, otherwise - failure 779 780 @ref Backend 781 **/ 782 int CeedSetData(Ceed ceed, void *data) { 783 ceed->data = data; 784 return CEED_ERROR_SUCCESS; 785 } 786 787 /** 788 @brief Increment the reference counter for a `Ceed` context 789 790 @param[in,out] ceed `Ceed` context to increment the reference counter 791 792 @return An error code: 0 - success, otherwise - failure 793 794 @ref Backend 795 **/ 796 int CeedReference(Ceed ceed) { 797 ceed->ref_count++; 798 return CEED_ERROR_SUCCESS; 799 } 800 801 /** 802 @brief Computes the current memory usage of the work vectors in a `Ceed` context and prints to debug.abort 803 804 @param[in] ceed `Ceed` context 805 @param[out] usage_mb Address of the variable where the MB of work vector usage will be stored 806 807 @return An error code: 0 - success, otherwise - failure 808 809 @ref Developer 810 **/ 811 int CeedGetWorkVectorMemoryUsage(Ceed ceed, CeedScalar *usage_mb) { 812 if (!ceed->VectorCreate) { 813 Ceed delegate; 814 815 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 816 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 817 CeedCall(CeedGetWorkVectorMemoryUsage(delegate, usage_mb)); 818 CeedCall(CeedDestroy(&delegate)); 819 return CEED_ERROR_SUCCESS; 820 } 821 *usage_mb = 0.0; 822 if (ceed->work_vectors) { 823 for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) { 824 CeedSize vec_len; 825 CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len)); 826 *usage_mb += vec_len; 827 } 828 *usage_mb *= sizeof(CeedScalar) * 1e-6; 829 CeedDebug(ceed, "Resource {%s}: Work vectors memory usage: %" CeedInt_FMT " vectors, %g MB\n", ceed->resource, ceed->work_vectors->num_vecs, 830 *usage_mb); 831 } 832 return CEED_ERROR_SUCCESS; 833 } 834 835 /** 836 @brief Clear inactive work vectors in a `Ceed` context below a minimum length. 837 838 @param[in,out] ceed `Ceed` context 839 @param[in] min_len Minimum length of work vector to keep 840 841 @return An error code: 0 - success, otherwise - failure 842 843 @ref Backend 844 **/ 845 int CeedClearWorkVectors(Ceed ceed, CeedSize min_len) { 846 if (!ceed->VectorCreate) { 847 Ceed delegate; 848 849 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 850 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 851 CeedCall(CeedClearWorkVectors(delegate, min_len)); 852 CeedCall(CeedDestroy(&delegate)); 853 return CEED_ERROR_SUCCESS; 854 } 855 if (!ceed->work_vectors) return CEED_ERROR_SUCCESS; 856 for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) { 857 if (ceed->work_vectors->is_in_use[i]) continue; 858 CeedSize vec_len; 859 CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len)); 860 if (vec_len < min_len) { 861 ceed->ref_count += 2; // Note: increase ref_count to prevent Ceed destructor from triggering 862 CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i])); 863 ceed->ref_count -= 1; // Note: restore ref_count 864 ceed->work_vectors->num_vecs--; 865 if (ceed->work_vectors->num_vecs > 0) { 866 ceed->work_vectors->vecs[i] = ceed->work_vectors->vecs[ceed->work_vectors->num_vecs]; 867 ceed->work_vectors->is_in_use[i] = ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs]; 868 ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs] = false; 869 i--; 870 } 871 } 872 } 873 return CEED_ERROR_SUCCESS; 874 } 875 876 /** 877 @brief Get a `CeedVector` for scratch work from a `Ceed` context. 878 879 Note: This vector must be restored with @ref CeedRestoreWorkVector(). 880 881 @param[in] ceed `Ceed` context 882 @param[in] len Minimum length of work vector 883 @param[out] vec Address of the variable where `CeedVector` will be stored 884 885 @return An error code: 0 - success, otherwise - failure 886 887 @ref Backend 888 **/ 889 int CeedGetWorkVector(Ceed ceed, CeedSize len, CeedVector *vec) { 890 CeedInt i = 0; 891 CeedScalar usage_mb; 892 893 if (!ceed->VectorCreate) { 894 Ceed delegate; 895 896 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 897 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 898 CeedCall(CeedGetWorkVector(delegate, len, vec)); 899 CeedCall(CeedDestroy(&delegate)); 900 return CEED_ERROR_SUCCESS; 901 } 902 903 if (!ceed->work_vectors) CeedCall(CeedWorkVectorsCreate(ceed)); 904 905 // Search for big enough work vector 906 for (i = 0; i < ceed->work_vectors->num_vecs; i++) { 907 if (!ceed->work_vectors->is_in_use[i]) { 908 CeedSize work_len; 909 910 CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &work_len)); 911 if (work_len >= len) break; 912 } 913 } 914 // Long enough vector was not found 915 if (i == ceed->work_vectors->num_vecs) { 916 if (ceed->work_vectors->max_vecs == 0) { 917 ceed->work_vectors->max_vecs = 1; 918 CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs)); 919 CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use)); 920 } else if (ceed->work_vectors->max_vecs == i) { 921 ceed->work_vectors->max_vecs *= 2; 922 CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs)); 923 CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use)); 924 } 925 ceed->work_vectors->num_vecs++; 926 CeedCallBackend(CeedVectorCreate(ceed, len, &ceed->work_vectors->vecs[i])); 927 ceed->ref_count--; // Note: ref_count manipulation to prevent a ref-loop 928 if (ceed->is_debug) CeedGetWorkVectorMemoryUsage(ceed, &usage_mb); 929 } 930 // Return pointer to work vector 931 ceed->work_vectors->is_in_use[i] = true; 932 *vec = NULL; 933 CeedCall(CeedVectorReferenceCopy(ceed->work_vectors->vecs[i], vec)); 934 ceed->ref_count++; // Note: bump ref_count to account for external access 935 return CEED_ERROR_SUCCESS; 936 } 937 938 /** 939 @brief Restore a `CeedVector` for scratch work from a `Ceed` context from @ref CeedGetWorkVector() 940 941 @param[in] ceed `Ceed` context 942 @param[out] vec `CeedVector` to restore 943 944 @return An error code: 0 - success, otherwise - failure 945 946 @ref Backend 947 **/ 948 int CeedRestoreWorkVector(Ceed ceed, CeedVector *vec) { 949 if (!ceed->VectorCreate) { 950 Ceed delegate; 951 952 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 953 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 954 CeedCall(CeedRestoreWorkVector(delegate, vec)); 955 CeedCall(CeedDestroy(&delegate)); 956 return CEED_ERROR_SUCCESS; 957 } 958 959 for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) { 960 if (*vec == ceed->work_vectors->vecs[i]) { 961 CeedCheck(ceed->work_vectors->is_in_use[i], ceed, CEED_ERROR_ACCESS, "Work vector %" CeedSize_FMT " was not checked out but is being returned"); 962 CeedCall(CeedVectorDestroy(vec)); 963 ceed->work_vectors->is_in_use[i] = false; 964 ceed->ref_count--; // Note: reduce ref_count again to prevent a ref-loop 965 return CEED_ERROR_SUCCESS; 966 } 967 } 968 // LCOV_EXCL_START 969 return CeedError(ceed, CEED_ERROR_MAJOR, "vec was not checked out via CeedGetWorkVector()"); 970 // LCOV_EXCL_STOP 971 } 972 973 /** 974 @brief Retrieve list of additional JiT source roots from `Ceed` context. 975 976 Note: The caller is responsible for restoring `jit_source_roots` with @ref CeedRestoreJitSourceRoots(). 977 978 @param[in] ceed `Ceed` context 979 @param[out] num_source_roots Number of JiT source directories 980 @param[out] jit_source_roots Absolute paths to additional JiT source directories 981 982 @return An error code: 0 - success, otherwise - failure 983 984 @ref Backend 985 **/ 986 int CeedGetJitSourceRoots(Ceed ceed, CeedInt *num_source_roots, const char ***jit_source_roots) { 987 Ceed ceed_parent; 988 989 CeedCall(CeedGetParent(ceed, &ceed_parent)); 990 *num_source_roots = ceed_parent->num_jit_source_roots; 991 *jit_source_roots = (const char **)ceed_parent->jit_source_roots; 992 ceed_parent->num_jit_source_roots_readers++; 993 CeedCall(CeedDestroy(&ceed_parent)); 994 return CEED_ERROR_SUCCESS; 995 } 996 997 /** 998 @brief Restore list of additional JiT source roots from with @ref CeedGetJitSourceRoots() 999 1000 @param[in] ceed `Ceed` context 1001 @param[out] jit_source_roots Absolute paths to additional JiT source directories 1002 1003 @return An error code: 0 - success, otherwise - failure 1004 1005 @ref Backend 1006 **/ 1007 int CeedRestoreJitSourceRoots(Ceed ceed, const char ***jit_source_roots) { 1008 Ceed ceed_parent; 1009 1010 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1011 *jit_source_roots = NULL; 1012 ceed_parent->num_jit_source_roots_readers--; 1013 CeedCall(CeedDestroy(&ceed_parent)); 1014 return CEED_ERROR_SUCCESS; 1015 } 1016 1017 /** 1018 @brief Retrieve list of additional JiT defines from `Ceed` context. 1019 1020 Note: The caller is responsible for restoring `jit_defines` with @ref CeedRestoreJitDefines(). 1021 1022 @param[in] ceed `Ceed` context 1023 @param[out] num_jit_defines Number of JiT defines 1024 @param[out] jit_defines Strings such as `foo=bar`, used as `-Dfoo=bar` in JiT 1025 1026 @return An error code: 0 - success, otherwise - failure 1027 1028 @ref Backend 1029 **/ 1030 int CeedGetJitDefines(Ceed ceed, CeedInt *num_jit_defines, const char ***jit_defines) { 1031 Ceed ceed_parent; 1032 1033 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1034 *num_jit_defines = ceed_parent->num_jit_defines; 1035 *jit_defines = (const char **)ceed_parent->jit_defines; 1036 ceed_parent->num_jit_defines_readers++; 1037 CeedCall(CeedDestroy(&ceed_parent)); 1038 return CEED_ERROR_SUCCESS; 1039 } 1040 1041 /** 1042 @brief Restore list of additional JiT defines from with @ref CeedGetJitDefines() 1043 1044 @param[in] ceed `Ceed` context 1045 @param[out] jit_defines String such as `foo=bar`, used as `-Dfoo=bar` in JiT 1046 1047 @return An error code: 0 - success, otherwise - failure 1048 1049 @ref Backend 1050 **/ 1051 int CeedRestoreJitDefines(Ceed ceed, const char ***jit_defines) { 1052 Ceed ceed_parent; 1053 1054 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1055 *jit_defines = NULL; 1056 ceed_parent->num_jit_defines_readers--; 1057 CeedCall(CeedDestroy(&ceed_parent)); 1058 return CEED_ERROR_SUCCESS; 1059 } 1060 1061 /// @} 1062 1063 /// ---------------------------------------------------------------------------- 1064 /// Ceed Public API 1065 /// ---------------------------------------------------------------------------- 1066 /// @addtogroup CeedUser 1067 /// @{ 1068 1069 /** 1070 @brief Get the list of available resource names for `Ceed` contexts 1071 1072 Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources array. 1073 1074 @param[out] n Number of available resources 1075 @param[out] resources List of available resource names 1076 @param[out] priorities Resource name prioritization values, lower is better 1077 1078 @return An error code: 0 - success, otherwise - failure 1079 1080 @ref User 1081 **/ 1082 // LCOV_EXCL_START 1083 int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) { 1084 *n = 0; 1085 *resources = malloc(num_backends * sizeof(**resources)); 1086 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 1087 if (priorities) { 1088 *priorities = malloc(num_backends * sizeof(**priorities)); 1089 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure"); 1090 } 1091 for (size_t i = 0; i < num_backends; i++) { 1092 // Only report compiled backends 1093 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) { 1094 *resources[i] = backends[i].prefix; 1095 if (priorities) *priorities[i] = backends[i].priority; 1096 *n += 1; 1097 } 1098 } 1099 CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed"); 1100 *resources = realloc(*resources, *n * sizeof(**resources)); 1101 CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 1102 if (priorities) { 1103 *priorities = realloc(*priorities, *n * sizeof(**priorities)); 1104 CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure"); 1105 } 1106 return CEED_ERROR_SUCCESS; 1107 } 1108 // LCOV_EXCL_STOP 1109 1110 /** 1111 @brief Initialize a `Ceed` context to use the specified resource. 1112 1113 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`. 1114 1115 @param[in] resource Resource to use, e.g., "/cpu/self" 1116 @param[out] ceed The library context 1117 1118 @return An error code: 0 - success, otherwise - failure 1119 1120 @ref User 1121 1122 @sa CeedRegister() CeedDestroy() 1123 **/ 1124 int CeedInit(const char *resource, Ceed *ceed) { 1125 size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority; 1126 1127 // Find matching backend 1128 CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided"); 1129 CeedCall(CeedRegisterAll()); 1130 1131 // Check for help request 1132 const char *help_prefix = "help"; 1133 size_t match_help = 0; 1134 while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++; 1135 if (match_help == 4) { 1136 fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH, 1137 CEED_VERSION_RELEASE ? "" : "+development"); 1138 fprintf(stderr, "Available backend resources:\n"); 1139 for (size_t i = 0; i < num_backends; i++) { 1140 // Only report compiled backends 1141 if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, " %s\n", backends[i].prefix); 1142 } 1143 fflush(stderr); 1144 match_help = 5; // Delineating character expected 1145 } else { 1146 match_help = 0; 1147 } 1148 1149 // Find best match, computed as number of matching characters from requested resource stem 1150 size_t stem_length = 0; 1151 while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++; 1152 for (size_t i = 0; i < num_backends; i++) { 1153 size_t n = 0; 1154 const char *prefix = backends[i].prefix; 1155 while (prefix[n] && prefix[n] == resource[n + match_help]) n++; 1156 priority = backends[i].priority; 1157 if (n > match_len || (n == match_len && match_priority > priority)) { 1158 match_len = n; 1159 match_priority = priority; 1160 match_index = i; 1161 } 1162 } 1163 // Using Levenshtein distance to find closest match 1164 if (match_len <= 1 || match_len != stem_length) { 1165 // LCOV_EXCL_START 1166 size_t lev_dis = UINT_MAX; 1167 size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY; 1168 for (size_t i = 0; i < num_backends; i++) { 1169 const char *prefix = backends[i].prefix; 1170 size_t prefix_length = strlen(backends[i].prefix); 1171 size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length; 1172 size_t column[min_len + 1]; 1173 for (size_t j = 0; j <= min_len; j++) column[j] = j; 1174 for (size_t j = 1; j <= min_len; j++) { 1175 column[0] = j; 1176 for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) { 1177 size_t old_diag = column[k]; 1178 size_t min_1 = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1; 1179 size_t min_2 = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1); 1180 column[k] = (min_1 < min_2) ? min_1 : min_2; 1181 last_diag = old_diag; 1182 } 1183 } 1184 size_t n = column[min_len]; 1185 priority = backends[i].priority; 1186 if (n < lev_dis || (n == lev_dis && lev_priority > priority)) { 1187 lev_dis = n; 1188 lev_priority = priority; 1189 lev_index = i; 1190 } 1191 } 1192 const char *prefix_lev = backends[lev_index].prefix; 1193 size_t lev_length = 0; 1194 while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++; 1195 size_t m = (lev_length < stem_length) ? lev_length : stem_length; 1196 if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource); 1197 else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix); 1198 // LCOV_EXCL_STOP 1199 } 1200 1201 // Setup Ceed 1202 CeedCall(CeedCalloc(1, ceed)); 1203 CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots)); 1204 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1205 if (!ceed_error_handler) ceed_error_handler = "abort"; 1206 if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit; 1207 else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore; 1208 else (*ceed)->Error = CeedErrorAbort; 1209 memcpy((*ceed)->err_msg, "No error message stored", 24); 1210 (*ceed)->ref_count = 1; 1211 (*ceed)->data = NULL; 1212 1213 // Set lookup table 1214 FOffset f_offsets[] = { 1215 CEED_FTABLE_ENTRY(Ceed, Error), 1216 CEED_FTABLE_ENTRY(Ceed, SetStream), 1217 CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType), 1218 CEED_FTABLE_ENTRY(Ceed, Destroy), 1219 CEED_FTABLE_ENTRY(Ceed, VectorCreate), 1220 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate), 1221 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints), 1222 CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked), 1223 CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1), 1224 CEED_FTABLE_ENTRY(Ceed, BasisCreateH1), 1225 CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv), 1226 CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl), 1227 CEED_FTABLE_ENTRY(Ceed, TensorContractCreate), 1228 CEED_FTABLE_ENTRY(Ceed, QFunctionCreate), 1229 CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate), 1230 CEED_FTABLE_ENTRY(Ceed, OperatorCreate), 1231 CEED_FTABLE_ENTRY(Ceed, OperatorCreateAtPoints), 1232 CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate), 1233 CEED_FTABLE_ENTRY(CeedVector, HasValidArray), 1234 CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType), 1235 CEED_FTABLE_ENTRY(CeedVector, CopyStrided), 1236 CEED_FTABLE_ENTRY(CeedVector, SetArray), 1237 CEED_FTABLE_ENTRY(CeedVector, TakeArray), 1238 CEED_FTABLE_ENTRY(CeedVector, SetValue), 1239 CEED_FTABLE_ENTRY(CeedVector, SetValueStrided), 1240 CEED_FTABLE_ENTRY(CeedVector, SyncArray), 1241 CEED_FTABLE_ENTRY(CeedVector, GetArray), 1242 CEED_FTABLE_ENTRY(CeedVector, GetArrayRead), 1243 CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite), 1244 CEED_FTABLE_ENTRY(CeedVector, RestoreArray), 1245 CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead), 1246 CEED_FTABLE_ENTRY(CeedVector, Norm), 1247 CEED_FTABLE_ENTRY(CeedVector, Scale), 1248 CEED_FTABLE_ENTRY(CeedVector, AXPY), 1249 CEED_FTABLE_ENTRY(CeedVector, AXPBY), 1250 CEED_FTABLE_ENTRY(CeedVector, PointwiseMult), 1251 CEED_FTABLE_ENTRY(CeedVector, Reciprocal), 1252 CEED_FTABLE_ENTRY(CeedVector, Destroy), 1253 CEED_FTABLE_ENTRY(CeedElemRestriction, Apply), 1254 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned), 1255 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented), 1256 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement), 1257 CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock), 1258 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets), 1259 CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations), 1260 CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations), 1261 CEED_FTABLE_ENTRY(CeedElemRestriction, GetAtPointsElementOffset), 1262 CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy), 1263 CEED_FTABLE_ENTRY(CeedBasis, Apply), 1264 CEED_FTABLE_ENTRY(CeedBasis, ApplyAdd), 1265 CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints), 1266 CEED_FTABLE_ENTRY(CeedBasis, ApplyAddAtPoints), 1267 CEED_FTABLE_ENTRY(CeedBasis, Destroy), 1268 CEED_FTABLE_ENTRY(CeedTensorContract, Apply), 1269 CEED_FTABLE_ENTRY(CeedTensorContract, Destroy), 1270 CEED_FTABLE_ENTRY(CeedQFunction, Apply), 1271 CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction), 1272 CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction), 1273 CEED_FTABLE_ENTRY(CeedQFunction, Destroy), 1274 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData), 1275 CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType), 1276 CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData), 1277 CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData), 1278 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData), 1279 CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead), 1280 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData), 1281 CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead), 1282 CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy), 1283 CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy), 1284 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction), 1285 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate), 1286 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal), 1287 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal), 1288 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal), 1289 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal), 1290 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic), 1291 CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble), 1292 CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle), 1293 CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse), 1294 CEED_FTABLE_ENTRY(CeedOperator, Apply), 1295 CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite), 1296 CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd), 1297 CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite), 1298 CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian), 1299 CEED_FTABLE_ENTRY(CeedOperator, Destroy), 1300 {NULL, 0} // End of lookup table - used in SetBackendFunction loop 1301 }; 1302 1303 CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets)); 1304 memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets)); 1305 1306 // Set fallback for advanced CeedOperator functions 1307 const char fallback_resource[] = ""; 1308 CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource)); 1309 1310 // Record env variables CEED_DEBUG or DBG 1311 (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); 1312 1313 // Copy resource prefix, if backend setup successful 1314 CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource)); 1315 1316 // Set default JiT source root 1317 // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent 1318 CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault)); 1319 1320 // Backend specific setup 1321 CeedCall(backends[match_index].init(&resource[match_help], *ceed)); 1322 return CEED_ERROR_SUCCESS; 1323 } 1324 1325 /** 1326 @brief Set the GPU stream for a `Ceed` context 1327 1328 @param[in,out] ceed `Ceed` context to set the stream 1329 @param[in] handle Handle to GPU stream 1330 1331 @return An error code: 0 - success, otherwise - failure 1332 1333 @ref User 1334 **/ 1335 int CeedSetStream(Ceed ceed, void *handle) { 1336 CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-NULL"); 1337 if (ceed->SetStream) { 1338 CeedCall(ceed->SetStream(ceed, handle)); 1339 } else { 1340 Ceed delegate; 1341 CeedCall(CeedGetDelegate(ceed, &delegate)); 1342 1343 if (delegate) CeedCall(CeedSetStream(delegate, handle)); 1344 else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream"); 1345 CeedCall(CeedDestroy(&delegate)); 1346 } 1347 return CEED_ERROR_SUCCESS; 1348 } 1349 1350 /** 1351 @brief Copy the pointer to a `Ceed` context. 1352 1353 Both pointers should be destroyed with @ref CeedDestroy(). 1354 1355 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. 1356 This `Ceed` context will be destroyed if `*ceed_copy` is the only reference to this `Ceed` context. 1357 1358 @param[in] ceed `Ceed` context to copy reference to 1359 @param[in,out] ceed_copy Variable to store copied reference 1360 1361 @return An error code: 0 - success, otherwise - failure 1362 1363 @ref User 1364 **/ 1365 int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) { 1366 CeedCall(CeedReference(ceed)); 1367 CeedCall(CeedDestroy(ceed_copy)); 1368 *ceed_copy = ceed; 1369 return CEED_ERROR_SUCCESS; 1370 } 1371 1372 /** 1373 @brief Get the full resource name for a `Ceed` context 1374 1375 @param[in] ceed `Ceed` context to get resource name of 1376 @param[out] resource Variable to store resource name 1377 1378 @return An error code: 0 - success, otherwise - failure 1379 1380 @ref User 1381 **/ 1382 int CeedGetResource(Ceed ceed, const char **resource) { 1383 *resource = (const char *)ceed->resource; 1384 return CEED_ERROR_SUCCESS; 1385 } 1386 1387 /** 1388 @brief Return `Ceed` context preferred memory type 1389 1390 @param[in] ceed `Ceed` context to get preferred memory type of 1391 @param[out] mem_type Address to save preferred memory type to 1392 1393 @return An error code: 0 - success, otherwise - failure 1394 1395 @ref User 1396 **/ 1397 int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) { 1398 if (ceed->GetPreferredMemType) { 1399 CeedCall(ceed->GetPreferredMemType(mem_type)); 1400 } else { 1401 Ceed delegate; 1402 CeedCall(CeedGetDelegate(ceed, &delegate)); 1403 1404 if (delegate) { 1405 CeedCall(CeedGetPreferredMemType(delegate, mem_type)); 1406 } else { 1407 *mem_type = CEED_MEM_HOST; 1408 } 1409 CeedCall(CeedDestroy(&delegate)); 1410 } 1411 return CEED_ERROR_SUCCESS; 1412 } 1413 1414 /** 1415 @brief Get deterministic status of `Ceed` context 1416 1417 @param[in] ceed `Ceed` context 1418 @param[out] is_deterministic Variable to store deterministic status 1419 1420 @return An error code: 0 - success, otherwise - failure 1421 1422 @ref User 1423 **/ 1424 int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) { 1425 *is_deterministic = ceed->is_deterministic; 1426 return CEED_ERROR_SUCCESS; 1427 } 1428 1429 /** 1430 @brief Set additional JiT source root for `Ceed` context 1431 1432 @param[in,out] ceed `Ceed` context 1433 @param[in] jit_source_root Absolute path to additional JiT source directory 1434 1435 @return An error code: 0 - success, otherwise - failure 1436 1437 @ref User 1438 **/ 1439 int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) { 1440 Ceed ceed_parent; 1441 1442 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1443 CeedCheck(!ceed_parent->num_jit_source_roots_readers, ceed, CEED_ERROR_ACCESS, "Cannot add JiT source root, read access has not been restored"); 1444 1445 CeedInt index = ceed_parent->num_jit_source_roots; 1446 size_t path_length = strlen(jit_source_root); 1447 1448 if (ceed_parent->num_jit_source_roots == ceed_parent->max_jit_source_roots) { 1449 if (ceed_parent->max_jit_source_roots == 0) ceed_parent->max_jit_source_roots = 1; 1450 ceed_parent->max_jit_source_roots *= 2; 1451 CeedCall(CeedRealloc(ceed_parent->max_jit_source_roots, &ceed_parent->jit_source_roots)); 1452 } 1453 CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index])); 1454 memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length); 1455 ceed_parent->num_jit_source_roots++; 1456 CeedCall(CeedDestroy(&ceed_parent)); 1457 return CEED_ERROR_SUCCESS; 1458 } 1459 1460 /** 1461 @brief Set additional JiT compiler define for `Ceed` context 1462 1463 @param[in,out] ceed `Ceed` context 1464 @param[in] jit_define String such as `foo=bar`, used as `-Dfoo=bar` in JiT 1465 1466 @return An error code: 0 - success, otherwise - failure 1467 1468 @ref User 1469 **/ 1470 int CeedAddJitDefine(Ceed ceed, const char *jit_define) { 1471 Ceed ceed_parent; 1472 1473 CeedCall(CeedGetParent(ceed, &ceed_parent)); 1474 CeedCheck(!ceed_parent->num_jit_defines_readers, ceed, CEED_ERROR_ACCESS, "Cannot add JiT define, read access has not been restored"); 1475 1476 CeedInt index = ceed_parent->num_jit_defines; 1477 size_t define_length = strlen(jit_define); 1478 1479 if (ceed_parent->num_jit_defines == ceed_parent->max_jit_defines) { 1480 if (ceed_parent->max_jit_defines == 0) ceed_parent->max_jit_defines = 1; 1481 ceed_parent->max_jit_defines *= 2; 1482 CeedCall(CeedRealloc(ceed_parent->max_jit_defines, &ceed_parent->jit_defines)); 1483 } 1484 CeedCall(CeedCalloc(define_length + 1, &ceed_parent->jit_defines[index])); 1485 memcpy(ceed_parent->jit_defines[index], jit_define, define_length); 1486 ceed_parent->num_jit_defines++; 1487 CeedCall(CeedDestroy(&ceed_parent)); 1488 return CEED_ERROR_SUCCESS; 1489 } 1490 1491 /** 1492 @brief View a `Ceed` 1493 1494 @param[in] ceed `Ceed` to view 1495 @param[in] stream Filestream to write to 1496 1497 @return An error code: 0 - success, otherwise - failure 1498 1499 @ref User 1500 **/ 1501 int CeedView(Ceed ceed, FILE *stream) { 1502 CeedMemType mem_type; 1503 1504 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 1505 1506 fprintf(stream, 1507 "Ceed\n" 1508 " Ceed Resource: %s\n" 1509 " Preferred MemType: %s\n", 1510 ceed->resource, CeedMemTypes[mem_type]); 1511 return CEED_ERROR_SUCCESS; 1512 } 1513 1514 /** 1515 @brief Destroy a `Ceed` 1516 1517 @param[in,out] ceed Address of `Ceed` context to destroy 1518 1519 @return An error code: 0 - success, otherwise - failure 1520 1521 @ref User 1522 **/ 1523 int CeedDestroy(Ceed *ceed) { 1524 if (!*ceed || --(*ceed)->ref_count > 0) { 1525 *ceed = NULL; 1526 return CEED_ERROR_SUCCESS; 1527 } 1528 1529 CeedCheck(!(*ceed)->num_jit_source_roots_readers, *ceed, CEED_ERROR_ACCESS, 1530 "Cannot destroy ceed context, read access for JiT source roots has been granted"); 1531 CeedCheck(!(*ceed)->num_jit_defines_readers, *ceed, CEED_ERROR_ACCESS, "Cannot add JiT source root, read access for JiT defines has been granted"); 1532 1533 if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate)); 1534 1535 if ((*ceed)->obj_delegate_count > 0) { 1536 for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) { 1537 CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate))); 1538 CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name)); 1539 } 1540 CeedCall(CeedFree(&(*ceed)->obj_delegates)); 1541 } 1542 1543 if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed)); 1544 1545 for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) { 1546 CeedCall(CeedFree(&(*ceed)->jit_source_roots[i])); 1547 } 1548 CeedCall(CeedFree(&(*ceed)->jit_source_roots)); 1549 1550 for (CeedInt i = 0; i < (*ceed)->num_jit_defines; i++) { 1551 CeedCall(CeedFree(&(*ceed)->jit_defines[i])); 1552 } 1553 CeedCall(CeedFree(&(*ceed)->jit_defines)); 1554 1555 CeedCall(CeedFree(&(*ceed)->f_offsets)); 1556 CeedCall(CeedFree(&(*ceed)->resource)); 1557 CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed)); 1558 CeedCall(CeedFree(&(*ceed)->op_fallback_resource)); 1559 CeedCall(CeedWorkVectorsDestroy(*ceed)); 1560 CeedCall(CeedFree(ceed)); 1561 return CEED_ERROR_SUCCESS; 1562 } 1563 1564 // LCOV_EXCL_START 1565 const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) { 1566 if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args); 1567 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1568 vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT 1569 return ceed->err_msg; 1570 } 1571 // LCOV_EXCL_STOP 1572 1573 /** 1574 @brief Error handling implementation; use @ref CeedError() instead. 1575 1576 @return An error code: 0 - success, otherwise - failure 1577 1578 @ref Developer 1579 **/ 1580 int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) { 1581 va_list args; 1582 int ret_val; 1583 1584 va_start(args, format); 1585 if (ceed) { 1586 ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args); 1587 } else { 1588 // LCOV_EXCL_START 1589 const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER"); 1590 if (!ceed_error_handler) ceed_error_handler = "abort"; 1591 if (!strcmp(ceed_error_handler, "return")) { 1592 ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args); 1593 } else { 1594 // This function will not return 1595 ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args); 1596 } 1597 } 1598 va_end(args); 1599 return ret_val; 1600 // LCOV_EXCL_STOP 1601 } 1602 1603 /** 1604 @brief Error handler that returns without printing anything. 1605 1606 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1607 1608 @return An error code: 0 - success, otherwise - failure 1609 1610 @ref Developer 1611 **/ 1612 // LCOV_EXCL_START 1613 int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1614 return err_code; 1615 } 1616 // LCOV_EXCL_STOP 1617 1618 /** 1619 @brief Error handler that stores the error message for future use and returns the error. 1620 1621 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1622 1623 @return An error code: 0 - success, otherwise - failure 1624 1625 @ref Developer 1626 **/ 1627 // LCOV_EXCL_START 1628 int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1629 if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args); 1630 1631 // Build message 1632 int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func); 1633 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1634 vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT 1635 return err_code; 1636 } 1637 // LCOV_EXCL_STOP 1638 1639 /** 1640 @brief Error handler that prints to `stderr` and aborts 1641 1642 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1643 1644 @return An error code: 0 - success, otherwise - failure 1645 1646 @ref Developer 1647 **/ 1648 // LCOV_EXCL_START 1649 int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1650 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1651 vfprintf(stderr, format, *args); 1652 fprintf(stderr, "\n"); 1653 abort(); 1654 return err_code; 1655 } 1656 // LCOV_EXCL_STOP 1657 1658 /** 1659 @brief Error handler that prints to `stderr` and exits. 1660 1661 Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior. 1662 1663 In contrast to @ref CeedErrorAbort(), this exits without a signal, so `atexit()` handlers (e.g., as used by gcov) are run. 1664 1665 @return An error code: 0 - success, otherwise - failure 1666 1667 @ref Developer 1668 **/ 1669 int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) { 1670 fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func); 1671 // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized 1672 vfprintf(stderr, format, *args); // NOLINT 1673 fprintf(stderr, "\n"); 1674 exit(err_code); 1675 return err_code; 1676 } 1677 1678 /** 1679 @brief Set error handler 1680 1681 A default error handler is set in @ref CeedInit(). 1682 Use this function to change the error handler to @ref CeedErrorReturn(), @ref CeedErrorAbort(), or a user-defined error handler. 1683 1684 @return An error code: 0 - success, otherwise - failure 1685 1686 @ref Developer 1687 **/ 1688 int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) { 1689 ceed->Error = handler; 1690 if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler); 1691 for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler); 1692 return CEED_ERROR_SUCCESS; 1693 } 1694 1695 /** 1696 @brief Get error message 1697 1698 The error message is only stored when using the error handler @ref CeedErrorStore() 1699 1700 @param[in] ceed `Ceed` context to retrieve error message 1701 @param[out] err_msg Char pointer to hold error message 1702 1703 @return An error code: 0 - success, otherwise - failure 1704 1705 @ref Developer 1706 **/ 1707 int CeedGetErrorMessage(Ceed ceed, const char **err_msg) { 1708 if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg); 1709 *err_msg = ceed->err_msg; 1710 return CEED_ERROR_SUCCESS; 1711 } 1712 1713 /** 1714 @brief Restore error message. 1715 1716 The error message is only stored when using the error handler @ref CeedErrorStore(). 1717 1718 @param[in] ceed `Ceed` context to restore error message 1719 @param[out] err_msg Char pointer that holds error message 1720 1721 @return An error code: 0 - success, otherwise - failure 1722 1723 @ref Developer 1724 **/ 1725 int CeedResetErrorMessage(Ceed ceed, const char **err_msg) { 1726 if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg); 1727 *err_msg = NULL; 1728 memcpy(ceed->err_msg, "No error message stored", 24); 1729 return CEED_ERROR_SUCCESS; 1730 } 1731 1732 /** 1733 @brief Get libCEED library version information. 1734 1735 libCEED version numbers have the form major.minor.patch. 1736 Non-release versions may contain unstable interfaces. 1737 1738 @param[out] major Major version of the library 1739 @param[out] minor Minor version of the library 1740 @param[out] patch Patch (subminor) version of the library 1741 @param[out] release True for releases; false for development branches 1742 1743 The caller may pass `NULL` for any arguments that are not needed. 1744 1745 @return An error code: 0 - success, otherwise - failure 1746 1747 @ref Developer 1748 1749 @sa CEED_VERSION_GE() CeedGetGitVersion() CeedGetBuildConfiguration() 1750 */ 1751 int CeedGetVersion(int *major, int *minor, int *patch, bool *release) { 1752 if (major) *major = CEED_VERSION_MAJOR; 1753 if (minor) *minor = CEED_VERSION_MINOR; 1754 if (patch) *patch = CEED_VERSION_PATCH; 1755 if (release) *release = CEED_VERSION_RELEASE; 1756 return CEED_ERROR_SUCCESS; 1757 } 1758 1759 /** 1760 @brief Get libCEED scalar type, such as F64 or F32 1761 1762 @param[out] scalar_type Type of libCEED scalars 1763 1764 @return An error code: 0 - success, otherwise - failure 1765 1766 @ref Developer 1767 */ 1768 int CeedGetScalarType(CeedScalarType *scalar_type) { 1769 *scalar_type = CEED_SCALAR_TYPE; 1770 return CEED_ERROR_SUCCESS; 1771 } 1772 1773 /// @} 1774