| 515 | |
| 516 | |
| 517 | void copyMatrixIfGpuCompiled(qcomp** cpuMatr, qcomp* gpuArr, qindex matrDim, enum CopyDirection direction) { |
| 518 | #if COMPILE_CUDA |
| 519 | |
| 520 | // NOTE: |
| 521 | // this function copies a 2D CPU matrix into a 1D row-major GPU array, |
| 522 | // although this is not actually needed by the QuEST backend which |
| 523 | // maintains 1D row-major CPU memories merely aliased by 2D structures |
| 524 | // for the user's benefit. As such, this is dead code, but preserved in |
| 525 | // case it is ever needed (like if custom user 2D data was needed in GPU). |
| 526 | error_gpuDeadCopyMatrixFunctionCalled(); |
| 527 | |
| 528 | // for completeness, we permit copying from the 1D GPU memory to the 2D CPU memory, |
| 529 | // although we never actually have the need to do this! |
| 530 | auto flag = (direction == TO_HOST)? |
| 531 | cudaMemcpyDeviceToHost: |
| 532 | cudaMemcpyHostToDevice; |
| 533 | |
| 534 | // copy each CPU row into flattened GPU memory. we make each memcpy asynch, |
| 535 | // but it's unclear it helps, nor whether single-stream sync is necessary |
| 536 | size_t numBytesPerRow = matrDim * sizeof(**cpuMatr); |
| 537 | gpu_sync(); |
| 538 | |
| 539 | for (qindex r=0; r<matrDim; r++) { |
| 540 | qcomp* cpuRow = cpuMatr[r]; |
| 541 | qcomp* gpuSlice = &gpuArr[r*matrDim]; |
| 542 | |
| 543 | auto src = (direction == TO_HOST)? gpuSlice : cpuRow; |
| 544 | auto dst = (direction == TO_HOST)? cpuRow : gpuSlice; |
| 545 | |
| 546 | CUDA_CHECK( cudaMemcpyAsync(dst, src, numBytesPerRow, flag) ); |
| 547 | } |
| 548 | |
| 549 | // wait for async copies to complete |
| 550 | gpu_sync(); |
| 551 | |
| 552 | #else |
| 553 | error_gpuCopyButGpuNotCompiled(); |
| 554 | #endif |
| 555 | } |
| 556 | |
| 557 | |
| 558 | template <typename T> |
nothing calls this directly
no test coverage detected