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 #include <ceed.h> 9 #include <ceed/backend.h> 10 #include <math.h> 11 #include <stdbool.h> 12 #include <string.h> 13 #include <hip/hip_runtime.h> 14 15 #include "../hip/ceed-hip-common.h" 16 #include "ceed-hip-ref.h" 17 18 //------------------------------------------------------------------------------ 19 // Check if host/device sync is needed 20 //------------------------------------------------------------------------------ 21 static inline int CeedVectorNeedSync_Hip(const CeedVector vec, CeedMemType mem_type, bool *need_sync) { 22 CeedVector_Hip *impl; 23 bool has_valid_array = false; 24 25 CeedCallBackend(CeedVectorGetData(vec, &impl)); 26 CeedCallBackend(CeedVectorHasValidArray(vec, &has_valid_array)); 27 switch (mem_type) { 28 case CEED_MEM_HOST: 29 *need_sync = has_valid_array && !impl->h_array; 30 break; 31 case CEED_MEM_DEVICE: 32 *need_sync = has_valid_array && !impl->d_array; 33 break; 34 } 35 return CEED_ERROR_SUCCESS; 36 } 37 38 //------------------------------------------------------------------------------ 39 // Sync host to device 40 //------------------------------------------------------------------------------ 41 static inline int CeedVectorSyncH2D_Hip(const CeedVector vec) { 42 CeedSize length; 43 size_t bytes; 44 CeedVector_Hip *impl; 45 46 CeedCallBackend(CeedVectorGetData(vec, &impl)); 47 48 CeedCheck(impl->h_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "No valid host data to sync to device"); 49 50 CeedCallBackend(CeedVectorGetLength(vec, &length)); 51 bytes = length * sizeof(CeedScalar); 52 if (impl->d_array_borrowed) { 53 impl->d_array = impl->d_array_borrowed; 54 } else if (impl->d_array_owned) { 55 impl->d_array = impl->d_array_owned; 56 } else { 57 CeedCallHip(CeedVectorReturnCeed(vec), hipMalloc((void **)&impl->d_array_owned, bytes)); 58 impl->d_array = impl->d_array_owned; 59 } 60 CeedCallHip(CeedVectorReturnCeed(vec), hipMemcpy(impl->d_array, impl->h_array, bytes, hipMemcpyHostToDevice)); 61 return CEED_ERROR_SUCCESS; 62 } 63 64 //------------------------------------------------------------------------------ 65 // Sync device to host 66 //------------------------------------------------------------------------------ 67 static inline int CeedVectorSyncD2H_Hip(const CeedVector vec) { 68 CeedSize length; 69 size_t bytes; 70 CeedVector_Hip *impl; 71 72 CeedCallBackend(CeedVectorGetData(vec, &impl)); 73 74 CeedCheck(impl->d_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "No valid device data to sync to host"); 75 76 if (impl->h_array_borrowed) { 77 impl->h_array = impl->h_array_borrowed; 78 } else if (impl->h_array_owned) { 79 impl->h_array = impl->h_array_owned; 80 } else { 81 CeedSize length; 82 83 CeedCallBackend(CeedVectorGetLength(vec, &length)); 84 CeedCallBackend(CeedCalloc(length, &impl->h_array_owned)); 85 impl->h_array = impl->h_array_owned; 86 } 87 88 CeedCallBackend(CeedVectorGetLength(vec, &length)); 89 bytes = length * sizeof(CeedScalar); 90 CeedCallHip(CeedVectorReturnCeed(vec), hipMemcpy(impl->h_array, impl->d_array, bytes, hipMemcpyDeviceToHost)); 91 return CEED_ERROR_SUCCESS; 92 } 93 94 //------------------------------------------------------------------------------ 95 // Sync arrays 96 //------------------------------------------------------------------------------ 97 static int CeedVectorSyncArray_Hip(const CeedVector vec, CeedMemType mem_type) { 98 bool need_sync = false; 99 CeedVector_Hip *impl; 100 101 // Sync for unified memory 102 CeedCallBackend(CeedVectorGetData(vec, &impl)); 103 if (impl->has_unified_addressing && !impl->h_array_borrowed) { 104 CeedCallHip(CeedVectorReturnCeed(vec), hipDeviceSynchronize()); 105 return CEED_ERROR_SUCCESS; 106 } 107 108 // Check whether device/host sync is needed 109 CeedCallBackend(CeedVectorNeedSync_Hip(vec, mem_type, &need_sync)); 110 if (!need_sync) return CEED_ERROR_SUCCESS; 111 112 switch (mem_type) { 113 case CEED_MEM_HOST: 114 return CeedVectorSyncD2H_Hip(vec); 115 case CEED_MEM_DEVICE: 116 return CeedVectorSyncH2D_Hip(vec); 117 } 118 return CEED_ERROR_UNSUPPORTED; 119 } 120 121 //------------------------------------------------------------------------------ 122 // Set all pointers as invalid 123 //------------------------------------------------------------------------------ 124 static inline int CeedVectorSetAllInvalid_Hip(const CeedVector vec) { 125 CeedVector_Hip *impl; 126 127 CeedCallBackend(CeedVectorGetData(vec, &impl)); 128 impl->h_array = NULL; 129 impl->d_array = NULL; 130 return CEED_ERROR_SUCCESS; 131 } 132 133 //------------------------------------------------------------------------------ 134 // Check if CeedVector has any valid pointer 135 //------------------------------------------------------------------------------ 136 static inline int CeedVectorHasValidArray_Hip(const CeedVector vec, bool *has_valid_array) { 137 CeedVector_Hip *impl; 138 139 CeedCallBackend(CeedVectorGetData(vec, &impl)); 140 *has_valid_array = impl->h_array || impl->d_array; 141 return CEED_ERROR_SUCCESS; 142 } 143 144 //------------------------------------------------------------------------------ 145 // Check if has array of given type 146 //------------------------------------------------------------------------------ 147 static inline int CeedVectorHasArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_array_of_type) { 148 CeedVector_Hip *impl; 149 150 CeedCallBackend(CeedVectorGetData(vec, &impl)); 151 switch (mem_type) { 152 case CEED_MEM_HOST: 153 *has_array_of_type = impl->h_array_borrowed || impl->h_array_owned; 154 break; 155 case CEED_MEM_DEVICE: 156 *has_array_of_type = impl->d_array_borrowed || impl->d_array_owned; 157 break; 158 } 159 return CEED_ERROR_SUCCESS; 160 } 161 162 //------------------------------------------------------------------------------ 163 // Check if has borrowed array of given type 164 //------------------------------------------------------------------------------ 165 static inline int CeedVectorHasBorrowedArrayOfType_Hip(const CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) { 166 CeedVector_Hip *impl; 167 168 CeedCallBackend(CeedVectorGetData(vec, &impl)); 169 170 // Use device memory for unified memory 171 mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type; 172 173 switch (mem_type) { 174 case CEED_MEM_HOST: 175 *has_borrowed_array_of_type = impl->h_array_borrowed; 176 break; 177 case CEED_MEM_DEVICE: 178 *has_borrowed_array_of_type = impl->d_array_borrowed; 179 break; 180 } 181 return CEED_ERROR_SUCCESS; 182 } 183 184 //------------------------------------------------------------------------------ 185 // Set array from host 186 //------------------------------------------------------------------------------ 187 static int CeedVectorSetArrayHost_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) { 188 CeedSize length; 189 CeedVector_Hip *impl; 190 191 CeedCallBackend(CeedVectorGetData(vec, &impl)); 192 CeedCallBackend(CeedVectorGetLength(vec, &length)); 193 194 CeedCallBackend(CeedSetHostCeedScalarArray(array, copy_mode, length, (const CeedScalar **)&impl->h_array_owned, 195 (const CeedScalar **)&impl->h_array_borrowed, (const CeedScalar **)&impl->h_array)); 196 return CEED_ERROR_SUCCESS; 197 } 198 199 //------------------------------------------------------------------------------ 200 // Set array from device 201 //------------------------------------------------------------------------------ 202 static int CeedVectorSetArrayDevice_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) { 203 CeedSize length; 204 Ceed ceed; 205 CeedVector_Hip *impl; 206 207 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 208 CeedCallBackend(CeedVectorGetData(vec, &impl)); 209 CeedCallBackend(CeedVectorGetLength(vec, &length)); 210 211 CeedCallBackend(CeedSetDeviceCeedScalarArray_Hip(ceed, array, copy_mode, length, (const CeedScalar **)&impl->d_array_owned, 212 (const CeedScalar **)&impl->d_array_borrowed, (const CeedScalar **)&impl->d_array)); 213 CeedCallBackend(CeedDestroy(&ceed)); 214 return CEED_ERROR_SUCCESS; 215 } 216 217 //------------------------------------------------------------------------------ 218 // Set array with unified memory 219 //------------------------------------------------------------------------------ 220 static int CeedVectorSetArrayUnifiedHostToDevice_Hip(const CeedVector vec, const CeedCopyMode copy_mode, CeedScalar *array) { 221 CeedSize length; 222 Ceed ceed; 223 CeedVector_Hip *impl; 224 225 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 226 CeedCallBackend(CeedVectorGetData(vec, &impl)); 227 CeedCallBackend(CeedVectorGetLength(vec, &length)); 228 229 switch (copy_mode) { 230 case CEED_COPY_VALUES: 231 case CEED_OWN_POINTER: 232 if (!impl->d_array) { 233 if (impl->d_array_borrowed) { 234 impl->d_array = impl->d_array_borrowed; 235 } else { 236 if (!impl->d_array_owned) CeedCallHip(ceed, hipMalloc((void **)&impl->d_array_owned, sizeof(CeedScalar) * length)); 237 impl->d_array = impl->d_array_owned; 238 } 239 } 240 if (array) CeedCallHip(ceed, hipMemcpy(impl->d_array, array, sizeof(CeedScalar) * length, hipMemcpyHostToDevice)); 241 if (copy_mode == CEED_OWN_POINTER) CeedCallBackend(CeedFree(&array)); 242 break; 243 case CEED_USE_POINTER: 244 CeedCallHip(ceed, hipFree(impl->d_array_owned)); 245 CeedCallBackend(CeedFree(&impl->h_array_owned)); 246 impl->h_array_owned = NULL; 247 impl->h_array_borrowed = array; 248 impl->d_array = impl->h_array_borrowed; 249 } 250 CeedCallBackend(CeedDestroy(&ceed)); 251 return CEED_ERROR_SUCCESS; 252 } 253 254 //------------------------------------------------------------------------------ 255 // Set the array used by a vector, 256 // freeing any previously allocated array if applicable 257 //------------------------------------------------------------------------------ 258 static int CeedVectorSetArray_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedCopyMode copy_mode, CeedScalar *array) { 259 CeedVector_Hip *impl; 260 261 CeedCallBackend(CeedVectorGetData(vec, &impl)); 262 CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec)); 263 switch (mem_type) { 264 case CEED_MEM_HOST: 265 if (impl->has_unified_addressing) { 266 return CeedVectorSetArrayUnifiedHostToDevice_Hip(vec, copy_mode, array); 267 } else { 268 return CeedVectorSetArrayHost_Hip(vec, copy_mode, array); 269 } 270 case CEED_MEM_DEVICE: 271 return CeedVectorSetArrayDevice_Hip(vec, copy_mode, array); 272 } 273 return CEED_ERROR_UNSUPPORTED; 274 } 275 276 //------------------------------------------------------------------------------ 277 // Copy host array to value strided 278 //------------------------------------------------------------------------------ 279 static int CeedHostCopyStrided_Hip(CeedScalar *h_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar *h_copy_array) { 280 for (CeedSize i = start; i < stop; i += step) h_copy_array[i] = h_array[i]; 281 return CEED_ERROR_SUCCESS; 282 } 283 284 //------------------------------------------------------------------------------ 285 // Copy device array to value strided (impl in .hip.cpp file) 286 //------------------------------------------------------------------------------ 287 int CeedDeviceCopyStrided_Hip(CeedScalar *d_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar *d_copy_array); 288 289 //------------------------------------------------------------------------------ 290 // Copy a vector to a value strided 291 //------------------------------------------------------------------------------ 292 static int CeedVectorCopyStrided_Hip(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedVector vec_copy) { 293 CeedSize length; 294 CeedVector_Hip *impl; 295 296 CeedCallBackend(CeedVectorGetData(vec, &impl)); 297 { 298 CeedSize length_vec, length_copy; 299 300 CeedCallBackend(CeedVectorGetLength(vec, &length_vec)); 301 CeedCallBackend(CeedVectorGetLength(vec_copy, &length_copy)); 302 length = length_vec < length_copy ? length_vec : length_copy; 303 } 304 if (stop == -1) stop = length; 305 // Set value for synced device/host array 306 if (impl->d_array) { 307 CeedScalar *copy_array; 308 309 CeedCallBackend(CeedVectorGetArray(vec_copy, CEED_MEM_DEVICE, ©_array)); 310 #if (HIP_VERSION >= 60000000) 311 hipblasHandle_t handle; 312 Ceed ceed; 313 314 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 315 CeedCallBackend(CeedGetHipblasHandle_Hip(ceed, &handle)); 316 #if defined(CEED_SCALAR_IS_FP32) 317 CeedCallHipblas(ceed, hipblasScopy_64(handle, (int64_t)(stop - start), impl->d_array + start, (int64_t)step, copy_array + start, (int64_t)step)); 318 #else /* CEED_SCALAR */ 319 CeedCallHipblas(ceed, hipblasDcopy_64(handle, (int64_t)(stop - start), impl->d_array + start, (int64_t)step, copy_array + start, (int64_t)step)); 320 #endif /* CEED_SCALAR */ 321 #else /* HIP_VERSION */ 322 CeedCallBackend(CeedDeviceCopyStrided_Hip(impl->d_array, start, stop, step, copy_array)); 323 #endif /* HIP_VERSION */ 324 CeedCallBackend(CeedVectorRestoreArray(vec_copy, ©_array)); 325 impl->h_array = NULL; 326 CeedCallBackend(CeedDestroy(&ceed)); 327 } else if (impl->h_array) { 328 CeedScalar *copy_array; 329 330 CeedCallBackend(CeedVectorGetArray(vec_copy, CEED_MEM_HOST, ©_array)); 331 CeedCallBackend(CeedHostCopyStrided_Hip(impl->h_array, start, stop, step, copy_array)); 332 CeedCallBackend(CeedVectorRestoreArray(vec_copy, ©_array)); 333 impl->d_array = NULL; 334 } else { 335 return CeedError(CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "CeedVector must have valid data set"); 336 } 337 return CEED_ERROR_SUCCESS; 338 } 339 340 //------------------------------------------------------------------------------ 341 // Set host array to value 342 //------------------------------------------------------------------------------ 343 static int CeedHostSetValue_Hip(CeedScalar *h_array, CeedSize length, CeedScalar val) { 344 for (CeedSize i = 0; i < length; i++) h_array[i] = val; 345 return CEED_ERROR_SUCCESS; 346 } 347 348 //------------------------------------------------------------------------------ 349 // Set device array to value (impl in .hip file) 350 //------------------------------------------------------------------------------ 351 int CeedDeviceSetValue_Hip(CeedScalar *d_array, CeedSize length, CeedScalar val); 352 353 //------------------------------------------------------------------------------ 354 // Set a vector to a value 355 //------------------------------------------------------------------------------ 356 static int CeedVectorSetValue_Hip(CeedVector vec, CeedScalar val) { 357 CeedSize length; 358 CeedVector_Hip *impl; 359 Ceed_Hip *hip_data; 360 361 CeedCallBackend(CeedVectorGetData(vec, &impl)); 362 CeedCallBackend(CeedGetData(CeedVectorReturnCeed(vec), &hip_data)); 363 CeedCallBackend(CeedVectorGetLength(vec, &length)); 364 // Set value for synced device/host array 365 if (!impl->d_array && !impl->h_array) { 366 if (impl->d_array_borrowed) { 367 impl->d_array = impl->d_array_borrowed; 368 } else if (impl->h_array_borrowed) { 369 impl->h_array = impl->h_array_borrowed; 370 } else if (impl->d_array_owned) { 371 impl->d_array = impl->d_array_owned; 372 } else if (impl->h_array_owned) { 373 impl->h_array = impl->h_array_owned; 374 } else { 375 CeedCallBackend(CeedVectorSetArray(vec, CEED_MEM_DEVICE, CEED_COPY_VALUES, NULL)); 376 } 377 } 378 if (impl->d_array) { 379 if (val == 0 && !impl->h_array_borrowed) { 380 CeedCallHip(CeedVectorReturnCeed(vec), hipMemset(impl->d_array, 0, length * sizeof(CeedScalar))); 381 } else { 382 CeedCallBackend(CeedDeviceSetValue_Hip(impl->d_array, length, val)); 383 } 384 impl->h_array = NULL; 385 } else if (impl->h_array) { 386 CeedCallBackend(CeedHostSetValue_Hip(impl->h_array, length, val)); 387 impl->d_array = NULL; 388 } 389 return CEED_ERROR_SUCCESS; 390 } 391 392 //------------------------------------------------------------------------------ 393 // Set host array to value strided 394 //------------------------------------------------------------------------------ 395 static int CeedHostSetValueStrided_Hip(CeedScalar *h_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val) { 396 for (CeedSize i = start; i < stop; i += step) h_array[i] = val; 397 return CEED_ERROR_SUCCESS; 398 } 399 400 //------------------------------------------------------------------------------ 401 // Set device array to value strided (impl in .hip.cpp file) 402 //------------------------------------------------------------------------------ 403 int CeedDeviceSetValueStrided_Hip(CeedScalar *d_array, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val); 404 405 //------------------------------------------------------------------------------ 406 // Set a vector to a value strided 407 //------------------------------------------------------------------------------ 408 static int CeedVectorSetValueStrided_Hip(CeedVector vec, CeedSize start, CeedSize stop, CeedSize step, CeedScalar val) { 409 CeedSize length; 410 CeedVector_Hip *impl; 411 412 CeedCallBackend(CeedVectorGetData(vec, &impl)); 413 CeedCallBackend(CeedVectorGetLength(vec, &length)); 414 // Set value for synced device/host array 415 if (stop == -1) stop = length; 416 if (impl->d_array) { 417 CeedCallBackend(CeedDeviceSetValueStrided_Hip(impl->d_array, start, stop, step, val)); 418 impl->h_array = NULL; 419 } else if (impl->h_array) { 420 CeedCallBackend(CeedHostSetValueStrided_Hip(impl->h_array, start, stop, step, val)); 421 impl->d_array = NULL; 422 } else { 423 return CeedError(CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "CeedVector must have valid data set"); 424 } 425 return CEED_ERROR_SUCCESS; 426 } 427 428 //------------------------------------------------------------------------------ 429 // Vector Take Array 430 //------------------------------------------------------------------------------ 431 static int CeedVectorTakeArray_Hip(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 432 CeedVector_Hip *impl; 433 434 CeedCallBackend(CeedVectorGetData(vec, &impl)); 435 436 // Sync array to requested mem_type 437 CeedCallBackend(CeedVectorSyncArray(vec, mem_type)); 438 439 // Update pointer 440 switch (mem_type) { 441 case CEED_MEM_HOST: 442 (*array) = impl->h_array_borrowed; 443 impl->h_array_borrowed = NULL; 444 impl->h_array = NULL; 445 break; 446 case CEED_MEM_DEVICE: 447 (*array) = impl->d_array_borrowed; 448 impl->d_array_borrowed = NULL; 449 impl->d_array = NULL; 450 break; 451 } 452 return CEED_ERROR_SUCCESS; 453 } 454 455 //------------------------------------------------------------------------------ 456 // Core logic for array synchronization for GetArray. 457 // If a different memory type is most up to date, this will perform a copy 458 //------------------------------------------------------------------------------ 459 static int CeedVectorGetArrayCore_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 460 CeedVector_Hip *impl; 461 462 CeedCallBackend(CeedVectorGetData(vec, &impl)); 463 464 // Use device memory for unified memory 465 mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type; 466 467 // Sync array to requested mem_type 468 CeedCallBackend(CeedVectorSyncArray(vec, mem_type)); 469 470 // Update pointer 471 switch (mem_type) { 472 case CEED_MEM_HOST: 473 *array = impl->h_array; 474 break; 475 case CEED_MEM_DEVICE: 476 *array = impl->d_array; 477 break; 478 } 479 return CEED_ERROR_SUCCESS; 480 } 481 482 //------------------------------------------------------------------------------ 483 // Get read-only access to a vector via the specified mem_type 484 //------------------------------------------------------------------------------ 485 static int CeedVectorGetArrayRead_Hip(const CeedVector vec, const CeedMemType mem_type, const CeedScalar **array) { 486 return CeedVectorGetArrayCore_Hip(vec, mem_type, (CeedScalar **)array); 487 } 488 489 //------------------------------------------------------------------------------ 490 // Get read/write access to a vector via the specified mem_type 491 //------------------------------------------------------------------------------ 492 static int CeedVectorGetArray_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 493 CeedVector_Hip *impl; 494 495 CeedCallBackend(CeedVectorGetData(vec, &impl)); 496 497 // Use device memory for unified memory 498 mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type; 499 500 // 'Get' array and set only 'get'ed array as valid 501 CeedCallBackend(CeedVectorGetArrayCore_Hip(vec, mem_type, array)); 502 CeedCallBackend(CeedVectorSetAllInvalid_Hip(vec)); 503 switch (mem_type) { 504 case CEED_MEM_HOST: 505 impl->h_array = *array; 506 if (impl->has_unified_addressing) impl->d_array = *array; 507 break; 508 case CEED_MEM_DEVICE: 509 impl->d_array = *array; 510 break; 511 } 512 return CEED_ERROR_SUCCESS; 513 } 514 515 //------------------------------------------------------------------------------ 516 // Get write access to a vector via the specified mem_type 517 //------------------------------------------------------------------------------ 518 static int CeedVectorGetArrayWrite_Hip(const CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 519 bool has_array_of_type = true; 520 CeedVector_Hip *impl; 521 Ceed_Hip *hip_data; 522 523 CeedCallBackend(CeedVectorGetData(vec, &impl)); 524 CeedCallBackend(CeedGetData(CeedVectorReturnCeed(vec), &hip_data)); 525 526 // Use device memory for unified memory 527 mem_type = impl->has_unified_addressing && !impl->h_array_borrowed ? CEED_MEM_DEVICE : mem_type; 528 529 CeedCallBackend(CeedVectorHasArrayOfType_Hip(vec, mem_type, &has_array_of_type)); 530 if (!has_array_of_type) { 531 // Allocate if array is not yet allocated 532 CeedCallBackend(CeedVectorSetArray(vec, mem_type, CEED_COPY_VALUES, NULL)); 533 } else { 534 // Select dirty array 535 switch (mem_type) { 536 case CEED_MEM_HOST: 537 if (impl->h_array_borrowed) impl->h_array = impl->h_array_borrowed; 538 else impl->h_array = impl->h_array_owned; 539 break; 540 case CEED_MEM_DEVICE: 541 if (impl->d_array_borrowed) impl->d_array = impl->d_array_borrowed; 542 else impl->d_array = impl->d_array_owned; 543 } 544 } 545 return CeedVectorGetArray_Hip(vec, mem_type, array); 546 } 547 548 //------------------------------------------------------------------------------ 549 // Get the norm of a CeedVector 550 //------------------------------------------------------------------------------ 551 static int CeedVectorNorm_Hip(CeedVector vec, CeedNormType type, CeedScalar *norm) { 552 Ceed ceed; 553 CeedSize length; 554 #if (HIP_VERSION < 60000000) 555 CeedSize num_calls; 556 #endif /* HIP_VERSION */ 557 const CeedScalar *d_array; 558 CeedVector_Hip *impl; 559 hipblasHandle_t handle; 560 Ceed_Hip *hip_data; 561 562 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 563 CeedCallBackend(CeedGetData(ceed, &hip_data)); 564 CeedCallBackend(CeedVectorGetData(vec, &impl)); 565 CeedCallBackend(CeedVectorGetLength(vec, &length)); 566 CeedCallBackend(CeedGetHipblasHandle_Hip(ceed, &handle)); 567 568 #if (HIP_VERSION < 60000000) 569 // With ROCm 6, we can use the 64-bit integer interface. Prior to that, 570 // we need to check if the vector is too long to handle with int32, 571 // and if so, divide it into subsections for repeated hipBLAS calls. 572 num_calls = length / INT_MAX; 573 if (length % INT_MAX > 0) num_calls += 1; 574 #endif /* HIP_VERSION */ 575 576 // Compute norm 577 CeedCallBackend(CeedVectorGetArrayRead(vec, CEED_MEM_DEVICE, &d_array)); 578 switch (type) { 579 case CEED_NORM_1: { 580 *norm = 0.0; 581 #if defined(CEED_SCALAR_IS_FP32) 582 #if (HIP_VERSION >= 60000000) // We have ROCm 6, and can use 64-bit integers 583 CeedCallHipblas(ceed, hipblasSasum_64(handle, (int64_t)length, (float *)d_array, 1, (float *)norm)); 584 #else /* HIP_VERSION */ 585 float sub_norm = 0.0; 586 float *d_array_start; 587 588 for (CeedInt i = 0; i < num_calls; i++) { 589 d_array_start = (float *)d_array + (CeedSize)(i)*INT_MAX; 590 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 591 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 592 593 CeedCallHipblas(ceed, hipblasSasum(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &sub_norm)); 594 *norm += sub_norm; 595 } 596 #endif /* HIP_VERSION */ 597 #else /* CEED_SCALAR */ 598 #if (HIP_VERSION >= 60000000) 599 CeedCallHipblas(ceed, hipblasDasum_64(handle, (int64_t)length, (double *)d_array, 1, (double *)norm)); 600 #else /* HIP_VERSION */ 601 double sub_norm = 0.0; 602 double *d_array_start; 603 604 for (CeedInt i = 0; i < num_calls; i++) { 605 d_array_start = (double *)d_array + (CeedSize)(i)*INT_MAX; 606 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 607 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 608 609 CeedCallHipblas(ceed, hipblasDasum(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &sub_norm)); 610 *norm += sub_norm; 611 } 612 #endif /* HIP_VERSION */ 613 #endif /* CEED_SCALAR */ 614 break; 615 } 616 case CEED_NORM_2: { 617 #if defined(CEED_SCALAR_IS_FP32) 618 #if (HIP_VERSION >= 60000000) 619 CeedCallHipblas(ceed, hipblasSnrm2_64(handle, (int64_t)length, (float *)d_array, 1, (float *)norm)); 620 #else /* HIP_VERSION */ 621 float sub_norm = 0.0, norm_sum = 0.0; 622 float *d_array_start; 623 624 for (CeedInt i = 0; i < num_calls; i++) { 625 d_array_start = (float *)d_array + (CeedSize)(i)*INT_MAX; 626 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 627 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 628 629 CeedCallHipblas(ceed, hipblasSnrm2(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &sub_norm)); 630 norm_sum += sub_norm * sub_norm; 631 } 632 *norm = sqrt(norm_sum); 633 #endif /* HIP_VERSION */ 634 #else /* CEED_SCALAR */ 635 #if (HIP_VERSION >= 60000000) 636 CeedCallHipblas(ceed, hipblasDnrm2_64(handle, (int64_t)length, (double *)d_array, 1, (double *)norm)); 637 #else /* HIP_VERSION */ 638 double sub_norm = 0.0, norm_sum = 0.0; 639 double *d_array_start; 640 641 for (CeedInt i = 0; i < num_calls; i++) { 642 d_array_start = (double *)d_array + (CeedSize)(i)*INT_MAX; 643 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 644 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 645 646 CeedCallHipblas(ceed, hipblasDnrm2(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &sub_norm)); 647 norm_sum += sub_norm * sub_norm; 648 } 649 *norm = sqrt(norm_sum); 650 #endif /* HIP_VERSION */ 651 #endif /* CEED_SCALAR */ 652 break; 653 } 654 case CEED_NORM_MAX: { 655 #if defined(CEED_SCALAR_IS_FP32) 656 #if (HIP_VERSION >= 60000000) 657 int64_t index; 658 CeedScalar norm_no_abs; 659 660 CeedCallHipblas(ceed, hipblasIsamax_64(handle, (int64_t)length, (float *)d_array, 1, &index)); 661 CeedCallHip(ceed, hipMemcpy(&norm_no_abs, impl->d_array + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost)); 662 *norm = fabs(norm_no_abs); 663 #else /* HIP_VERSION */ 664 CeedInt index; 665 float sub_max = 0.0, current_max = 0.0; 666 float *d_array_start; 667 668 for (CeedInt i = 0; i < num_calls; i++) { 669 d_array_start = (float *)d_array + (CeedSize)(i)*INT_MAX; 670 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 671 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 672 673 CeedCallHipblas(ceed, hipblasIsamax(handle, (CeedInt)sub_length, (float *)d_array_start, 1, &index)); 674 if (hip_data->has_unified_addressing) { 675 CeedCallHip(ceed, hipDeviceSynchronize()); 676 sub_max = fabs(d_array[index - 1]); 677 } else { 678 CeedCallHip(ceed, hipMemcpy(&sub_max, d_array_start + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost)); 679 } 680 if (fabs(sub_max) > current_max) current_max = fabs(sub_max); 681 } 682 *norm = current_max; 683 #endif /* HIP_VERSION */ 684 #else /* CEED_SCALAR */ 685 #if (HIP_VERSION >= 60000000) 686 int64_t index; 687 CeedScalar norm_no_abs; 688 689 CeedCallHipblas(ceed, hipblasIdamax_64(handle, (int64_t)length, (double *)d_array, 1, &index)); 690 if (hip_data->has_unified_addressing) { 691 CeedCallHip(ceed, hipDeviceSynchronize()); 692 norm_no_abs = fabs(d_array[index - 1]); 693 } else { 694 CeedCallHip(ceed, hipMemcpy(&norm_no_abs, impl->d_array + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost)); 695 } 696 *norm = fabs(norm_no_abs); 697 #else /* HIP_VERSION */ 698 CeedInt index; 699 double sub_max = 0.0, current_max = 0.0; 700 double *d_array_start; 701 702 for (CeedInt i = 0; i < num_calls; i++) { 703 d_array_start = (double *)d_array + (CeedSize)(i)*INT_MAX; 704 CeedSize remaining_length = length - (CeedSize)(i)*INT_MAX; 705 CeedInt sub_length = (i == num_calls - 1) ? (CeedInt)(remaining_length) : INT_MAX; 706 707 CeedCallHipblas(ceed, hipblasIdamax(handle, (CeedInt)sub_length, (double *)d_array_start, 1, &index)); 708 if (hip_data->has_unified_addressing) { 709 CeedCallHip(ceed, hipDeviceSynchronize()); 710 sub_max = fabs(d_array[index - 1]); 711 } else { 712 CeedCallHip(ceed, hipMemcpy(&sub_max, d_array_start + index - 1, sizeof(CeedScalar), hipMemcpyDeviceToHost)); 713 } 714 if (fabs(sub_max) > current_max) current_max = fabs(sub_max); 715 } 716 *norm = current_max; 717 #endif /* HIP_VERSION */ 718 #endif /* CEED_SCALAR */ 719 break; 720 } 721 } 722 CeedCallBackend(CeedVectorRestoreArrayRead(vec, &d_array)); 723 CeedCallBackend(CeedDestroy(&ceed)); 724 return CEED_ERROR_SUCCESS; 725 } 726 727 //------------------------------------------------------------------------------ 728 // Take reciprocal of a vector on host 729 //------------------------------------------------------------------------------ 730 static int CeedHostReciprocal_Hip(CeedScalar *h_array, CeedSize length) { 731 for (CeedSize i = 0; i < length; i++) { 732 if (fabs(h_array[i]) > CEED_EPSILON) h_array[i] = 1. / h_array[i]; 733 } 734 return CEED_ERROR_SUCCESS; 735 } 736 737 //------------------------------------------------------------------------------ 738 // Take reciprocal of a vector on device (impl in .hip.cpp file) 739 //------------------------------------------------------------------------------ 740 int CeedDeviceReciprocal_Hip(CeedScalar *d_array, CeedSize length); 741 742 //------------------------------------------------------------------------------ 743 // Take reciprocal of a vector 744 //------------------------------------------------------------------------------ 745 static int CeedVectorReciprocal_Hip(CeedVector vec) { 746 CeedSize length; 747 CeedVector_Hip *impl; 748 749 CeedCallBackend(CeedVectorGetData(vec, &impl)); 750 CeedCallBackend(CeedVectorGetLength(vec, &length)); 751 // Set value for synced device/host array 752 if (impl->d_array) CeedCallBackend(CeedDeviceReciprocal_Hip(impl->d_array, length)); 753 if (impl->h_array) CeedCallBackend(CeedHostReciprocal_Hip(impl->h_array, length)); 754 return CEED_ERROR_SUCCESS; 755 } 756 757 //------------------------------------------------------------------------------ 758 // Compute x = alpha x on the host 759 //------------------------------------------------------------------------------ 760 static int CeedHostScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedSize length) { 761 for (CeedSize i = 0; i < length; i++) x_array[i] *= alpha; 762 return CEED_ERROR_SUCCESS; 763 } 764 765 //------------------------------------------------------------------------------ 766 // Compute x = alpha x on device (impl in .hip.cpp file) 767 //------------------------------------------------------------------------------ 768 int CeedDeviceScale_Hip(CeedScalar *x_array, CeedScalar alpha, CeedSize length); 769 770 //------------------------------------------------------------------------------ 771 // Compute x = alpha x 772 //------------------------------------------------------------------------------ 773 static int CeedVectorScale_Hip(CeedVector x, CeedScalar alpha) { 774 CeedSize length; 775 CeedVector_Hip *impl; 776 777 CeedCallBackend(CeedVectorGetData(x, &impl)); 778 CeedCallBackend(CeedVectorGetLength(x, &length)); 779 // Set value for synced device/host array 780 if (impl->d_array) { 781 #if (HIP_VERSION >= 60000000) 782 hipblasHandle_t handle; 783 784 CeedCallBackend(CeedGetHipblasHandle_Hip(CeedVectorReturnCeed(x), &handle)); 785 #if defined(CEED_SCALAR_IS_FP32) 786 CeedCallHipblas(CeedVectorReturnCeed(x), hipblasSscal_64(handle, (int64_t)length, &alpha, impl->d_array, 1)); 787 #else /* CEED_SCALAR */ 788 CeedCallHipblas(CeedVectorReturnCeed(x), hipblasDscal_64(handle, (int64_t)length, &alpha, impl->d_array, 1)); 789 #endif /* CEED_SCALAR */ 790 #else /* HIP_VERSION */ 791 CeedCallBackend(CeedDeviceScale_Hip(impl->d_array, alpha, length)); 792 #endif /* HIP_VERSION */ 793 impl->h_array = NULL; 794 } 795 if (impl->h_array) { 796 CeedCallBackend(CeedHostScale_Hip(impl->h_array, alpha, length)); 797 impl->d_array = NULL; 798 } 799 return CEED_ERROR_SUCCESS; 800 } 801 802 //------------------------------------------------------------------------------ 803 // Compute y = alpha x + y on the host 804 //------------------------------------------------------------------------------ 805 static int CeedHostAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedSize length) { 806 for (CeedSize i = 0; i < length; i++) y_array[i] += alpha * x_array[i]; 807 return CEED_ERROR_SUCCESS; 808 } 809 810 //------------------------------------------------------------------------------ 811 // Compute y = alpha x + y on device (impl in .hip.cpp file) 812 //------------------------------------------------------------------------------ 813 int CeedDeviceAXPY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar *x_array, CeedSize length); 814 815 //------------------------------------------------------------------------------ 816 // Compute y = alpha x + y 817 //------------------------------------------------------------------------------ 818 static int CeedVectorAXPY_Hip(CeedVector y, CeedScalar alpha, CeedVector x) { 819 CeedSize length; 820 CeedVector_Hip *y_impl, *x_impl; 821 822 CeedCallBackend(CeedVectorGetData(y, &y_impl)); 823 CeedCallBackend(CeedVectorGetData(x, &x_impl)); 824 CeedCallBackend(CeedVectorGetLength(y, &length)); 825 // Set value for synced device/host array 826 if (y_impl->d_array) { 827 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE)); 828 #if (HIP_VERSION >= 60000000) 829 hipblasHandle_t handle; 830 831 CeedCallBackend(CeedGetHipblasHandle_Hip(CeedVectorReturnCeed(y), &handle)); 832 #if defined(CEED_SCALAR_IS_FP32) 833 CeedCallHipblas(CeedVectorReturnCeed(y), hipblasSaxpy_64(handle, (int64_t)length, &alpha, x_impl->d_array, 1, y_impl->d_array, 1)); 834 #else /* CEED_SCALAR */ 835 CeedCallHipblas(CeedVectorReturnCeed(y), hipblasDaxpy_64(handle, (int64_t)length, &alpha, x_impl->d_array, 1, y_impl->d_array, 1)); 836 #endif /* CEED_SCALAR */ 837 #else /* HIP_VERSION */ 838 CeedCallBackend(CeedDeviceAXPY_Hip(y_impl->d_array, alpha, x_impl->d_array, length)); 839 #endif /* HIP_VERSION */ 840 y_impl->h_array = NULL; 841 } else if (y_impl->h_array) { 842 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST)); 843 CeedCallBackend(CeedHostAXPY_Hip(y_impl->h_array, alpha, x_impl->h_array, length)); 844 y_impl->d_array = NULL; 845 } 846 return CEED_ERROR_SUCCESS; 847 } 848 849 //------------------------------------------------------------------------------ 850 // Compute y = alpha x + beta y on the host 851 //------------------------------------------------------------------------------ 852 static int CeedHostAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedSize length) { 853 for (CeedSize i = 0; i < length; i++) y_array[i] = alpha * x_array[i] + beta * y_array[i]; 854 return CEED_ERROR_SUCCESS; 855 } 856 857 //------------------------------------------------------------------------------ 858 // Compute y = alpha x + beta y on device (impl in .hip.cpp file) 859 //------------------------------------------------------------------------------ 860 int CeedDeviceAXPBY_Hip(CeedScalar *y_array, CeedScalar alpha, CeedScalar beta, CeedScalar *x_array, CeedSize length); 861 862 //------------------------------------------------------------------------------ 863 // Compute y = alpha x + beta y 864 //------------------------------------------------------------------------------ 865 static int CeedVectorAXPBY_Hip(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) { 866 CeedSize length; 867 CeedVector_Hip *y_impl, *x_impl; 868 869 CeedCallBackend(CeedVectorGetData(y, &y_impl)); 870 CeedCallBackend(CeedVectorGetData(x, &x_impl)); 871 CeedCallBackend(CeedVectorGetLength(y, &length)); 872 // Set value for synced device/host array 873 if (y_impl->d_array) { 874 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE)); 875 CeedCallBackend(CeedDeviceAXPBY_Hip(y_impl->d_array, alpha, beta, x_impl->d_array, length)); 876 } 877 if (y_impl->h_array) { 878 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST)); 879 CeedCallBackend(CeedHostAXPBY_Hip(y_impl->h_array, alpha, beta, x_impl->h_array, length)); 880 } 881 return CEED_ERROR_SUCCESS; 882 } 883 884 //------------------------------------------------------------------------------ 885 // Compute the pointwise multiplication w = x .* y on the host 886 //------------------------------------------------------------------------------ 887 static int CeedHostPointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedSize length) { 888 for (CeedSize i = 0; i < length; i++) w_array[i] = x_array[i] * y_array[i]; 889 return CEED_ERROR_SUCCESS; 890 } 891 892 //------------------------------------------------------------------------------ 893 // Compute the pointwise multiplication w = x .* y on device (impl in .hip.cpp file) 894 //------------------------------------------------------------------------------ 895 int CeedDevicePointwiseMult_Hip(CeedScalar *w_array, CeedScalar *x_array, CeedScalar *y_array, CeedSize length); 896 897 //------------------------------------------------------------------------------ 898 // Compute the pointwise multiplication w = x .* y 899 //------------------------------------------------------------------------------ 900 static int CeedVectorPointwiseMult_Hip(CeedVector w, CeedVector x, CeedVector y) { 901 CeedSize length; 902 CeedVector_Hip *w_impl, *x_impl, *y_impl; 903 904 CeedCallBackend(CeedVectorGetData(w, &w_impl)); 905 CeedCallBackend(CeedVectorGetData(x, &x_impl)); 906 CeedCallBackend(CeedVectorGetData(y, &y_impl)); 907 CeedCallBackend(CeedVectorGetLength(w, &length)); 908 909 // Set value for synced device/host array 910 if (!w_impl->d_array && !w_impl->h_array) { 911 CeedCallBackend(CeedVectorSetValue(w, 0.0)); 912 } 913 if (w_impl->d_array) { 914 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_DEVICE)); 915 CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_DEVICE)); 916 CeedCallBackend(CeedDevicePointwiseMult_Hip(w_impl->d_array, x_impl->d_array, y_impl->d_array, length)); 917 } 918 if (w_impl->h_array) { 919 CeedCallBackend(CeedVectorSyncArray(x, CEED_MEM_HOST)); 920 CeedCallBackend(CeedVectorSyncArray(y, CEED_MEM_HOST)); 921 CeedCallBackend(CeedHostPointwiseMult_Hip(w_impl->h_array, x_impl->h_array, y_impl->h_array, length)); 922 } 923 return CEED_ERROR_SUCCESS; 924 } 925 926 //------------------------------------------------------------------------------ 927 // Destroy the vector 928 //------------------------------------------------------------------------------ 929 static int CeedVectorDestroy_Hip(const CeedVector vec) { 930 CeedVector_Hip *impl; 931 932 CeedCallBackend(CeedVectorGetData(vec, &impl)); 933 CeedCallHip(CeedVectorReturnCeed(vec), hipFree(impl->d_array_owned)); 934 CeedCallBackend(CeedFree(&impl->h_array_owned)); 935 CeedCallBackend(CeedFree(&impl)); 936 return CEED_ERROR_SUCCESS; 937 } 938 939 //------------------------------------------------------------------------------ 940 // Create a vector of the specified length (does not allocate memory) 941 //------------------------------------------------------------------------------ 942 int CeedVectorCreate_Hip(CeedSize n, CeedVector vec) { 943 CeedVector_Hip *impl; 944 Ceed_Hip *hip_impl; 945 Ceed ceed; 946 947 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 948 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Hip)); 949 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Hip)); 950 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Hip)); 951 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Hip)); 952 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "CopyStrided", CeedVectorCopyStrided_Hip)); 953 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetValue", CeedVectorSetValue_Hip)); 954 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetValueStrided", CeedVectorSetValueStrided_Hip)); 955 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SyncArray", CeedVectorSyncArray_Hip)); 956 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Hip)); 957 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Hip)); 958 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Hip)); 959 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Norm", CeedVectorNorm_Hip)); 960 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Reciprocal", CeedVectorReciprocal_Hip)); 961 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Scale", CeedVectorScale_Hip)); 962 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPY", CeedVectorAXPY_Hip)); 963 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "AXPBY", CeedVectorAXPBY_Hip)); 964 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "PointwiseMult", CeedVectorPointwiseMult_Hip)); 965 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Hip)); 966 CeedCallBackend(CeedCalloc(1, &impl)); 967 CeedCallBackend(CeedGetData(ceed, &hip_impl)); 968 CeedCallBackend(CeedDestroy(&ceed)); 969 impl->has_unified_addressing = hip_impl->has_unified_addressing; 970 CeedCallBackend(CeedVectorSetData(vec, impl)); 971 return CEED_ERROR_SUCCESS; 972 } 973 974 //------------------------------------------------------------------------------ 975