@@ -2763,13 +2763,6 @@ hipError_t ihipMemcpy3D_validate(const hipMemcpy3DParms* p) {
27632763 // not have the same element size.
27642764 if ((p->srcArray != nullptr ) && (p->dstArray != nullptr )) {
27652765 if (hip::getElementSize (p->srcArray ) != hip::getElementSize (p->dstArray )) {
2766- return hipErrorInvalidValue;
2767- }
2768-
2769- // If both src and dst are arrays, verify they have the same extents
2770- if (p->srcArray ->width != p->dstArray ->width ||
2771- p->srcArray ->height != p->dstArray ->height ||
2772- p->srcArray ->depth != p->dstArray ->depth ) {
27732766 return hipErrorInvalidValue;
27742767 }
27752768 }
@@ -3015,6 +3008,26 @@ static hipError_t EnqueueBatchCommands(std::vector<std::vector<Operation>>& oper
30153008 return hipSuccess;
30163009}
30173010
3011+ // ================================================================================================
3012+ // Releases the batch commands that EnqueueBatchCommands placed on other GPUs' null streams.
3013+ // When status is hipSuccess, the caller's stream first receives a marker that waits for them.
3014+ static hipError_t EnqueueBatchMarker (hipError_t status, hip::Stream& stream,
3015+ amd::Command::EventWaitList& marker_wait_list) {
3016+ if (status == hipSuccess && !marker_wait_list.empty ()) {
3017+ amd::Command* dependent_marker = new amd::Marker (stream, true , marker_wait_list);
3018+ if (dependent_marker == nullptr ) {
3019+ status = hipErrorOutOfMemory;
3020+ } else {
3021+ dependent_marker->enqueue ();
3022+ dependent_marker->release ();
3023+ }
3024+ }
3025+ for (amd::Event* cmd : marker_wait_list) {
3026+ cmd->release ();
3027+ }
3028+ return status;
3029+ }
3030+
30183031// ================================================================================================
30193032// Returns the attribute flags that apply to copy `copyIdx`.
30203033static inline unsigned int getBatchCopyFlags (hipMemcpyAttributes* attrs, size_t * attrsIdxs,
@@ -3242,29 +3255,7 @@ hipError_t ihipMemcpyBatch(void** dsts, void** srcs, size_t* sizes, size_t count
32423255 stream_wait_cmd->release ();
32433256 }
32443257
3245- if (status != hipSuccess) {
3246- for (auto * cmd : marker_wait_list) {
3247- cmd->release ();
3248- }
3249- return status;
3250- }
3251-
3252- if (!marker_wait_list.empty ()) {
3253- amd::Command* dependent_marker = new amd::Marker (stream, true , marker_wait_list);
3254- if (dependent_marker == nullptr ) {
3255- for (auto * cmd : marker_wait_list) {
3256- cmd->release ();
3257- }
3258- return hipErrorOutOfMemory;
3259- }
3260- dependent_marker->enqueue ();
3261- dependent_marker->release ();
3262- for (auto * cmd : marker_wait_list) {
3263- cmd->release ();
3264- }
3265- }
3266-
3267- return hipSuccess;
3258+ return EnqueueBatchMarker (status, stream, marker_wait_list);
32683259}
32693260
32703261// ================================================================================================
@@ -3339,22 +3330,146 @@ hipError_t hipMemcpyBatchAsync(void** dsts, void** srcs, size_t* sizes, size_t c
33393330hipError_t hipMemcpy3DBatchAsync (size_t numOps, struct hipMemcpy3DBatchOp * opList, size_t * failIdx,
33403331 unsigned long long flags, hipStream_t stream) {
33413332 HIP_INIT_API (hipMemcpy3DBatchAsync, numOps, opList, failIdx, flags, stream);
3333+ size_t ignored_fail_idx = SIZE_MAX ;
3334+ if (failIdx == nullptr ) {
3335+ failIdx = &ignored_fail_idx;
3336+ }
33423337 if (flags != 0 || opList == nullptr || numOps == 0 ) {
3338+ *failIdx = SIZE_MAX ;
33433339 HIP_RETURN (hipErrorInvalidValue);
33443340 }
33453341 if (!hip::isValid (stream)) {
33463342 HIP_RETURN (hipErrorInvalidResourceHandle);
33473343 }
33483344 CHECK_STREAM_DETACHED_API (stream);
33493345
3350- hipError_t status = hipSuccess;
3351-
33523346 *failIdx = SIZE_MAX ;
3353- for (int i = 0 ; i < numOps; ++i) {
3347+ hip::Stream* hip_stream = hip::getStream (stream);
3348+
3349+ std::vector<std::vector<amd::BatchCopyRectOp>> copy_ops_by_device (g_devices.size ());
3350+ std::vector<std::pair<size_t , HIP_MEMCPY3D >> per_entry_copies;
3351+ std::vector<HIP_MEMCPY3D > host_copies;
3352+ for (size_t i = 0 ; i < numOps; ++i) {
3353+ const hipMemcpySrcAccessOrder access_order = opList[i].srcAccessOrder ;
3354+ if (access_order < hipMemcpySrcAccessOrderStream || access_order > hipMemcpySrcAccessOrderAny) {
3355+ *failIdx = i;
3356+ HIP_RETURN (hipErrorInvalidValue);
3357+ }
33543358 hipMemcpy3DParms parms = getMemcpy3DParms (opList[i]);
3355- status = ihipMemcpy3D (&parms, stream, true );
3359+ hipError_t status = ihipMemcpy3D_validate (&parms);
3360+ if (status != hipSuccess) {
3361+ *failIdx = i;
3362+ HIP_RETURN (status);
3363+ }
3364+ HIP_MEMCPY3D desc = getDrvMemcpy3DDesc (parms);
3365+ if (desc.WidthInBytes == 0 || desc.Height == 0 || desc.Depth == 0 ) {
3366+ *failIdx = i;
3367+ HIP_RETURN (hipErrorInvalidValue);
3368+ }
3369+
3370+ hipMemoryType src_memory_type;
3371+ hipMemoryType dst_memory_type;
3372+ ihipCopyMemParamSet (&desc, src_memory_type, dst_memory_type);
3373+
3374+ amd::Coord3D src_origin = {desc.srcXInBytes , desc.srcY , desc.srcZ };
3375+ amd::Coord3D dst_origin = {desc.dstXInBytes , desc.dstY , desc.dstZ };
3376+ amd::Coord3D copy_region = {desc.WidthInBytes , desc.Height , desc.Depth };
3377+ amd::BufferRect src_rect;
3378+ amd::BufferRect dst_rect;
3379+ amd::Image* src_image = nullptr ;
3380+ amd::Image* dst_image = nullptr ;
3381+ status = ihipDrvMemcpy3D_validate (&desc, src_origin, dst_origin, copy_region, &src_rect,
3382+ &dst_rect, &src_image, &dst_image);
33563383 if (status != hipSuccess) {
33573384 *failIdx = i;
3385+ HIP_RETURN (status);
3386+ }
3387+ if (src_memory_type == hipMemoryTypeArray || dst_memory_type == hipMemoryTypeArray) {
3388+ per_entry_copies.emplace_back (i, desc);
3389+ continue ;
3390+ }
3391+
3392+ amd::Memory* src_memory = nullptr ;
3393+ amd::Memory* dst_memory = nullptr ;
3394+ hip::MemcpyType type;
3395+ if (src_memory_type == hipMemoryTypeHost) {
3396+ type = (dst_memory_type == hipMemoryTypeHost) ? hipHostToHost : hipWriteBuffer;
3397+ } else if (dst_memory_type == hipMemoryTypeHost) {
3398+ type = hipReadBuffer;
3399+ } else {
3400+ size_t src_offset = 0 ;
3401+ size_t dst_offset = 0 ;
3402+ getMemoryObjectPairs (hip::getCurrentDevice (), desc.srcDevice , desc.dstDevice , src_memory,
3403+ dst_memory, src_offset, dst_offset);
3404+ const bool src_on_host = getMemoryType (src_memory) == hipMemoryTypeHost &&
3405+ !IsManagedMemory (src_memory->getMemFlags ());
3406+ const bool dst_on_host = getMemoryType (dst_memory) == hipMemoryTypeHost &&
3407+ !IsManagedMemory (dst_memory->getMemFlags ());
3408+ type = (src_on_host && dst_on_host)
3409+ ? hipHostToHost
3410+ : ihipGetMemcpyType (src_memory, dst_memory, hipMemcpyDefault);
3411+ }
3412+
3413+ switch (type) {
3414+ case hipCopyBuffer:
3415+ case hipCopyBufferSDMA: {
3416+ const int device_id = (getMemoryType (src_memory) == hipMemoryTypeDevice &&
3417+ getMemoryType (dst_memory) == hipMemoryTypeHost)
3418+ ? src_memory->getUserData ().deviceId
3419+ : dst_memory->getUserData ().deviceId ;
3420+ copy_ops_by_device[device_id].emplace_back (src_memory, dst_memory, src_rect, dst_rect,
3421+ copy_region);
3422+ break ;
3423+ }
3424+ case hipCopyBufferP2P: {
3425+ const int device_id = hip_stream->DeviceId ();
3426+ copy_ops_by_device[device_id].emplace_back (src_memory, dst_memory, src_rect, dst_rect,
3427+ copy_region);
3428+ break ;
3429+ }
3430+ case hipHostToHost:
3431+ host_copies.push_back (desc);
3432+ break ;
3433+ case hipWriteBuffer:
3434+ case hipReadBuffer:
3435+ per_entry_copies.emplace_back (i, desc);
3436+ break ;
3437+ }
3438+ }
3439+
3440+ if (!host_copies.empty ()) {
3441+ hip_stream->finish ();
3442+ for (const HIP_MEMCPY3D & desc : host_copies) {
3443+ for (size_t z = 0 ; z < desc.Depth ; ++z) {
3444+ for (size_t y = 0 ; y < desc.Height ; ++y) {
3445+ const size_t src_offset =
3446+ ((desc.srcZ + z) * desc.srcHeight + desc.srcY + y) * desc.srcPitch + desc.srcXInBytes ;
3447+ const size_t dst_offset =
3448+ ((desc.dstZ + z) * desc.dstHeight + desc.dstY + y) * desc.dstPitch + desc.dstXInBytes ;
3449+ std::memcpy (static_cast <char *>(desc.dstHost ) + dst_offset,
3450+ static_cast <const char *>(desc.srcHost ) + src_offset, desc.WidthInBytes );
3451+ }
3452+ }
3453+ }
3454+ }
3455+
3456+ amd::Command::EventWaitList marker_wait_list;
3457+ amd::Command* stream_wait_cmd = hip_stream->getLastQueuedCommand (true );
3458+ hipError_t status = EnqueueBatchCommands<amd::BatchCopyMemoryRectCommand>(
3459+ copy_ops_by_device, ROCCLR_COMMAND_BATCH_COPY_BUFFER_RECT , *hip_stream, true , stream_wait_cmd,
3460+ marker_wait_list);
3461+ if (stream_wait_cmd != nullptr ) {
3462+ stream_wait_cmd->release ();
3463+ }
3464+ status = EnqueueBatchMarker (status, *hip_stream, marker_wait_list);
3465+ if (status != hipSuccess) {
3466+ HIP_RETURN (status);
3467+ }
3468+
3469+ for (auto & [index, desc] : per_entry_copies) {
3470+ status = ihipMemcpyParam3D (&desc, stream, true );
3471+ if (status != hipSuccess) {
3472+ *failIdx = index;
33583473 break ;
33593474 }
33603475 }
0 commit comments