static
| 207 | |
| 208 | // static |
| 209 | void GPUUtil::DeviceToDeviceCopy( |
| 210 | DeviceContext* send_dev_context, DeviceContext* recv_dev_context, |
| 211 | Device* src, Device* dst, AllocatorAttributes src_alloc_attr, |
| 212 | AllocatorAttributes dst_alloc_attr, const Tensor* input, Tensor* output, |
| 213 | int dev_to_dev_stream_index, StatusCallback done) { |
| 214 | const DeviceBase::GpuDeviceInfo* dev_info = nullptr; |
| 215 | se::Stream* send_stream = nullptr; |
| 216 | Status s = PrepareCopy(src, send_dev_context, *input, output, &dev_info, |
| 217 | &send_stream); |
| 218 | if (!s.ok()) { |
| 219 | done(s); |
| 220 | return; |
| 221 | } |
| 222 | auto send_device_to_device_stream = |
| 223 | static_cast<const GPUDeviceContext*>(send_dev_context) |
| 224 | ->device_to_device_stream(dev_to_dev_stream_index); |
| 225 | if (send_device_to_device_stream == nullptr) { |
| 226 | done(errors::Internal("No send gpu copy-out-stream is available.")); |
| 227 | return; |
| 228 | } |
| 229 | // Wait for the main stream on the sender to make sure the result is |
| 230 | // available. |
| 231 | if (send_device_to_device_stream != send_stream) { |
| 232 | send_device_to_device_stream->ThenWaitFor(send_stream); |
| 233 | } |
| 234 | |
| 235 | const int64 total_bytes = input->TotalBytes(); |
| 236 | if (total_bytes > 0) { |
| 237 | void* src_ptr = GetBase(input); |
| 238 | DeviceMemoryBase gpu_src_ptr(src_ptr, total_bytes); |
| 239 | void* dst_ptr = GetBase(output); |
| 240 | DeviceMemoryBase gpu_dst_ptr(dst_ptr, total_bytes); |
| 241 | auto recv_stream = |
| 242 | static_cast<const GPUDeviceContext*>(recv_dev_context)->stream(); |
| 243 | if (recv_stream == nullptr) { |
| 244 | done(errors::Internal("No recv gpu stream is available.")); |
| 245 | return; |
| 246 | } |
| 247 | // Since we want to use the memory from recv_stream in the |
| 248 | // send_device_to_device_stream, add a dependency to make sure the memory is |
| 249 | // truly free. |
| 250 | // TODO(zhengxq): remove this dependency when we switch to a better way |
| 251 | // to make sure the memory is free. |
| 252 | if (send_device_to_device_stream != recv_stream) { |
| 253 | send_device_to_device_stream->ThenWaitFor(recv_stream); |
| 254 | } |
| 255 | |
| 256 | VLOG(2) << "src_ptr " << src_ptr << " dst_ptr " << dst_ptr; |
| 257 | send_device_to_device_stream->ThenMemcpy(&gpu_dst_ptr, gpu_src_ptr, |
| 258 | total_bytes); |
| 259 | } |
| 260 | |
| 261 | // Use of input may outlive stack scope, so keep a ref. |
| 262 | TensorReference input_ref(*input); |
| 263 | dev_info->event_mgr->ThenExecute( |
| 264 | send_device_to_device_stream, |
| 265 | [done, send_device_to_device_stream, input_ref]() { |
| 266 | input_ref.Unref(); |
nothing calls this directly
no test coverage detected