1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <stdint.h> 21 #include <stdio.h> 22 23 /// @file 24 /// Implementation of public CeedQFunctionContext interfaces 25 26 /// ---------------------------------------------------------------------------- 27 /// CeedQFunctionContext Backend API 28 /// ---------------------------------------------------------------------------- 29 /// @addtogroup CeedQFunctionBackend 30 /// @{ 31 32 /** 33 @brief Get the Ceed associated with a CeedQFunctionContext 34 35 @param ctx CeedQFunctionContext 36 @param[out] ceed Variable to store Ceed 37 38 @return An error code: 0 - success, otherwise - failure 39 40 @ref Backend 41 **/ 42 int CeedQFunctionContextGetCeed(CeedQFunctionContext ctx, Ceed *ceed) { 43 *ceed = ctx->ceed; 44 return CEED_ERROR_SUCCESS; 45 } 46 47 /** 48 @brief Check for valid data in a CeedQFunctionContext 49 50 @param ctx CeedQFunctionContext to check validity 51 @param[out] has_valid_data Variable to store validity 52 53 @return An error code: 0 - success, otherwise - failure 54 55 @ref Backend 56 **/ 57 int CeedQFunctionContextHasValidData(CeedQFunctionContext ctx, 58 bool *has_valid_data) { 59 int ierr; 60 61 if (!ctx->HasValidData) 62 // LCOV_EXCL_START 63 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 64 "Backend does not support HasValidData"); 65 // LCOV_EXCL_STOP 66 67 ierr = ctx->HasValidData(ctx, has_valid_data); CeedChk(ierr); 68 69 return CEED_ERROR_SUCCESS; 70 } 71 72 /** 73 @brief Check for borrowed data of a specific CeedMemType in a 74 CeedQFunctionContext 75 76 @param ctx CeedQFunctionContext to check 77 @param mem_type Memory type to check 78 @param[out] has_borrowed_data_of_type Variable to store result 79 80 @return An error code: 0 - success, otherwise - failure 81 82 @ref Backend 83 **/ 84 int CeedQFunctionContextHasBorrowedDataOfType(CeedQFunctionContext ctx, 85 CeedMemType mem_type, bool *has_borrowed_data_of_type) { 86 int ierr; 87 88 if (!ctx->HasBorrowedDataOfType) 89 // LCOV_EXCL_START 90 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 91 "Backend does not support HasBorrowedDataOfType"); 92 // LCOV_EXCL_STOP 93 94 ierr = ctx->HasBorrowedDataOfType(ctx, mem_type, has_borrowed_data_of_type); 95 CeedChk(ierr); 96 97 return CEED_ERROR_SUCCESS; 98 } 99 100 /** 101 @brief Get the state of a CeedQFunctionContext 102 103 @param ctx CeedQFunctionContext to retrieve state 104 @param[out] state Variable to store state 105 106 @return An error code: 0 - success, otherwise - failure 107 108 @ref Backend 109 **/ 110 int CeedQFunctionContextGetState(CeedQFunctionContext ctx, uint64_t *state) { 111 *state = ctx->state; 112 return CEED_ERROR_SUCCESS; 113 } 114 115 /** 116 @brief Get backend data of a CeedQFunctionContext 117 118 @param ctx CeedQFunctionContext 119 @param[out] data Variable to store data 120 121 @return An error code: 0 - success, otherwise - failure 122 123 @ref Backend 124 **/ 125 int CeedQFunctionContextGetBackendData(CeedQFunctionContext ctx, void *data) { 126 *(void **)data = ctx->data; 127 return CEED_ERROR_SUCCESS; 128 } 129 130 /** 131 @brief Set backend data of a CeedQFunctionContext 132 133 @param[out] ctx CeedQFunctionContext 134 @param data Data to set 135 136 @return An error code: 0 - success, otherwise - failure 137 138 @ref Backend 139 **/ 140 int CeedQFunctionContextSetBackendData(CeedQFunctionContext ctx, void *data) { 141 ctx->data = data; 142 return CEED_ERROR_SUCCESS; 143 } 144 145 /** 146 @brief Increment the reference counter for a CeedQFunctionContext 147 148 @param ctx CeedQFunctionContext to increment the reference counter 149 150 @return An error code: 0 - success, otherwise - failure 151 152 @ref Backend 153 **/ 154 int CeedQFunctionContextReference(CeedQFunctionContext ctx) { 155 ctx->ref_count++; 156 return CEED_ERROR_SUCCESS; 157 } 158 159 /// @} 160 161 /// ---------------------------------------------------------------------------- 162 /// CeedQFunctionContext Public API 163 /// ---------------------------------------------------------------------------- 164 /// @addtogroup CeedQFunctionUser 165 /// @{ 166 167 /** 168 @brief Create a CeedQFunctionContext for storing CeedQFunction user context data 169 170 @param ceed A Ceed object where the CeedQFunctionContext will be created 171 @param[out] ctx Address of the variable where the newly created 172 CeedQFunctionContext will be stored 173 174 @return An error code: 0 - success, otherwise - failure 175 176 @ref User 177 **/ 178 int CeedQFunctionContextCreate(Ceed ceed, CeedQFunctionContext *ctx) { 179 int ierr; 180 181 if (!ceed->QFunctionContextCreate) { 182 Ceed delegate; 183 ierr = CeedGetObjectDelegate(ceed, &delegate, "Context"); CeedChk(ierr); 184 185 if (!delegate) 186 // LCOV_EXCL_START 187 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 188 "Backend does not support ContextCreate"); 189 // LCOV_EXCL_STOP 190 191 ierr = CeedQFunctionContextCreate(delegate, ctx); CeedChk(ierr); 192 return CEED_ERROR_SUCCESS; 193 } 194 195 ierr = CeedCalloc(1, ctx); CeedChk(ierr); 196 (*ctx)->ceed = ceed; 197 ierr = CeedReference(ceed); CeedChk(ierr); 198 (*ctx)->ref_count = 1; 199 ierr = ceed->QFunctionContextCreate(*ctx); CeedChk(ierr); 200 return CEED_ERROR_SUCCESS; 201 } 202 203 /** 204 @brief Copy the pointer to a CeedQFunctionContext. Both pointers should 205 be destroyed with `CeedQFunctionContextDestroy()`; 206 Note: If `*ctx_copy` is non-NULL, then it is assumed that 207 `*ctx_copy` is a pointer to a CeedQFunctionContext. This 208 CeedQFunctionContext will be destroyed if `*ctx_copy` is the 209 only reference to this CeedQFunctionContext. 210 211 @param ctx CeedQFunctionContext to copy reference to 212 @param[out] ctx_copy Variable to store copied reference 213 214 @return An error code: 0 - success, otherwise - failure 215 216 @ref User 217 **/ 218 int CeedQFunctionContextReferenceCopy(CeedQFunctionContext ctx, 219 CeedQFunctionContext *ctx_copy) { 220 int ierr; 221 222 ierr = CeedQFunctionContextReference(ctx); CeedChk(ierr); 223 ierr = CeedQFunctionContextDestroy(ctx_copy); CeedChk(ierr); 224 *ctx_copy = ctx; 225 return CEED_ERROR_SUCCESS; 226 } 227 228 /** 229 @brief Set the data used by a CeedQFunctionContext, freeing any previously allocated 230 data if applicable. The backend may copy values to a different 231 memtype, such as during @ref CeedQFunctionApply(). 232 See also @ref CeedQFunctionContextTakeData(). 233 234 @param ctx CeedQFunctionContext 235 @param mem_type Memory type of the data being passed 236 @param copy_mode Copy mode for the data 237 @param size Size of data, in bytes 238 @param data Data to be used 239 240 @return An error code: 0 - success, otherwise - failure 241 242 @ref User 243 **/ 244 int CeedQFunctionContextSetData(CeedQFunctionContext ctx, CeedMemType mem_type, 245 CeedCopyMode copy_mode, 246 size_t size, void *data) { 247 int ierr; 248 249 if (!ctx->SetData) 250 // LCOV_EXCL_START 251 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 252 "Backend does not support ContextSetData"); 253 // LCOV_EXCL_STOP 254 255 if (ctx->state % 2 == 1) 256 // LCOV_EXCL_START 257 return CeedError(ctx->ceed, 1, 258 "Cannot grant CeedQFunctionContext data access, the " 259 "access lock is already in use"); 260 // LCOV_EXCL_STOP 261 262 ctx->ctx_size = size; 263 ierr = ctx->SetData(ctx, mem_type, copy_mode, data); CeedChk(ierr); 264 ctx->state += 2; 265 return CEED_ERROR_SUCCESS; 266 } 267 268 /** 269 @brief Take ownership of the data in a CeedQFunctionContext via the specified memory type. 270 The caller is responsible for managing and freeing the memory. 271 272 @param ctx CeedQFunctionContext to access 273 @param mem_type Memory type on which to access the data. If the backend 274 uses a different memory type, this will perform a copy. 275 @param[out] data Data on memory type mem_type 276 277 @return An error code: 0 - success, otherwise - failure 278 279 @ref User 280 **/ 281 int CeedQFunctionContextTakeData(CeedQFunctionContext ctx, CeedMemType mem_type, 282 void *data) { 283 int ierr; 284 285 bool has_valid_data = true; 286 ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 287 if (!has_valid_data) 288 // LCOV_EXCL_START 289 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 290 "CeedQFunctionContext has no valid data to take, must set data"); 291 // LCOV_EXCL_STOP 292 293 if (!ctx->TakeData) 294 // LCOV_EXCL_START 295 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 296 "Backend does not support TakeData"); 297 // LCOV_EXCL_STOP 298 299 if (ctx->state % 2 == 1) 300 // LCOV_EXCL_START 301 return CeedError(ctx->ceed, 1, 302 "Cannot grant CeedQFunctionContext data access, the " 303 "access lock is already in use"); 304 // LCOV_EXCL_STOP 305 306 bool has_borrowed_data_of_type = true; 307 ierr = CeedQFunctionContextHasBorrowedDataOfType(ctx, mem_type, 308 &has_borrowed_data_of_type); CeedChk(ierr); 309 if (!has_borrowed_data_of_type) 310 // LCOV_EXCL_START 311 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 312 "CeedQFunctionContext has no borowed %s data, " 313 "must set data with CeedQFunctionContextSetData", 314 CeedMemTypes[mem_type]); 315 // LCOV_EXCL_STOP 316 317 void *temp_data = NULL; 318 ierr = ctx->TakeData(ctx, mem_type, &temp_data); CeedChk(ierr); 319 if (data) (*(void **)data) = temp_data; 320 return CEED_ERROR_SUCCESS; 321 } 322 323 /** 324 @brief Get read/write access to a CeedQFunctionContext via the specified memory type. 325 Restore access with @ref CeedQFunctionContextRestoreData(). 326 327 @param ctx CeedQFunctionContext to access 328 @param mem_type Memory type on which to access the data. If the backend 329 uses a different memory type, this will perform a copy. 330 @param[out] data Data on memory type mem_type 331 332 @note The CeedQFunctionContextGetData() and @ref CeedQFunctionContextRestoreData() functions 333 provide access to array pointers in the desired memory space. Pairing 334 get/restore allows the Context to track access. 335 336 @return An error code: 0 - success, otherwise - failure 337 338 @ref User 339 **/ 340 int CeedQFunctionContextGetData(CeedQFunctionContext ctx, CeedMemType mem_type, 341 void *data) { 342 int ierr; 343 344 if (!ctx->GetData) 345 // LCOV_EXCL_START 346 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 347 "Backend does not support GetData"); 348 // LCOV_EXCL_STOP 349 350 if (ctx->state % 2 == 1) 351 // LCOV_EXCL_START 352 return CeedError(ctx->ceed, 1, 353 "Cannot grant CeedQFunctionContext data access, the " 354 "access lock is already in use"); 355 // LCOV_EXCL_STOP 356 357 bool has_valid_data = true; 358 ierr = CeedQFunctionContextHasValidData(ctx, &has_valid_data); CeedChk(ierr); 359 if (!has_valid_data) 360 // LCOV_EXCL_START 361 return CeedError(ctx->ceed, CEED_ERROR_BACKEND, 362 "CeedQFunctionContext has no valid data to get, must set data"); 363 // LCOV_EXCL_STOP 364 365 ierr = ctx->GetData(ctx, mem_type, data); CeedChk(ierr); 366 ctx->state += 1; 367 return CEED_ERROR_SUCCESS; 368 } 369 370 /** 371 @brief Restore data obtained using @ref CeedQFunctionContextGetData() 372 373 @param ctx CeedQFunctionContext to restore 374 @param data Data to restore 375 376 @return An error code: 0 - success, otherwise - failure 377 378 @ref User 379 **/ 380 int CeedQFunctionContextRestoreData(CeedQFunctionContext ctx, void *data) { 381 int ierr; 382 383 if (!ctx->RestoreData) 384 // LCOV_EXCL_START 385 return CeedError(ctx->ceed, CEED_ERROR_UNSUPPORTED, 386 "Backend does not support RestoreData"); 387 // LCOV_EXCL_STOP 388 389 if (ctx->state % 2 != 1) 390 // LCOV_EXCL_START 391 return CeedError(ctx->ceed, 1, 392 "Cannot restore CeedQFunctionContext array access, " 393 "access was not granted"); 394 // LCOV_EXCL_STOP 395 396 ierr = ctx->RestoreData(ctx); CeedChk(ierr); 397 *(void **)data = NULL; 398 ctx->state += 1; 399 return CEED_ERROR_SUCCESS; 400 } 401 402 /** 403 @brief Get data size for a Context 404 405 @param ctx CeedQFunctionContext 406 @param[out] ctx_size Variable to store size of context data values 407 408 @return An error code: 0 - success, otherwise - failure 409 410 @ref User 411 **/ 412 int CeedQFunctionContextGetContextSize(CeedQFunctionContext ctx, 413 size_t *ctx_size) { 414 *ctx_size = ctx->ctx_size; 415 return CEED_ERROR_SUCCESS; 416 } 417 418 419 /** 420 @brief View a CeedQFunctionContext 421 422 @param[in] ctx CeedQFunctionContext to view 423 @param[in] stream Filestream to write to 424 425 @return An error code: 0 - success, otherwise - failure 426 427 @ref User 428 **/ 429 int CeedQFunctionContextView(CeedQFunctionContext ctx, FILE *stream) { 430 fprintf(stream, "CeedQFunctionContext\n"); 431 fprintf(stream, " Context Data Size: %ld\n", ctx->ctx_size); 432 return CEED_ERROR_SUCCESS; 433 } 434 435 /** 436 @brief Destroy a CeedQFunctionContext 437 438 @param ctx CeedQFunctionContext to destroy 439 440 @return An error code: 0 - success, otherwise - failure 441 442 @ref User 443 **/ 444 int CeedQFunctionContextDestroy(CeedQFunctionContext *ctx) { 445 int ierr; 446 447 if (!*ctx || --(*ctx)->ref_count > 0) 448 return CEED_ERROR_SUCCESS; 449 450 if ((*ctx) && ((*ctx)->state % 2) == 1) 451 // LCOV_EXCL_START 452 return CeedError((*ctx)->ceed, 1, 453 "Cannot destroy CeedQFunctionContext, the access " 454 "lock is in use"); 455 // LCOV_EXCL_STOP 456 457 if ((*ctx)->Destroy) { 458 ierr = (*ctx)->Destroy(*ctx); CeedChk(ierr); 459 } 460 ierr = CeedDestroy(&(*ctx)->ceed); CeedChk(ierr); 461 ierr = CeedFree(ctx); CeedChk(ierr); 462 return CEED_ERROR_SUCCESS; 463 } 464 465 /// @} 466