| 221 | } |
| 222 | |
| 223 | inline phi::DenseTensor TransDataPlace(const phi::DenseTensor& tensor, |
| 224 | Place dst_place) { |
| 225 | VLOG(3) << "DeviceTransform in, src_place " << tensor.place() |
| 226 | << " dst_place: " << dst_place; |
| 227 | |
| 228 | auto& pool = phi::DeviceContextPool::Instance(); |
| 229 | #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) |
| 230 | // NOTE(yy): TransDataPlace should wait for computation of input. |
| 231 | if (tensor.place().GetType() != phi::AllocationType::GPUPINNED) { |
| 232 | pool.Get(tensor.place())->Wait(); |
| 233 | pool.Get(dst_place)->Wait(); |
| 234 | } |
| 235 | #endif |
| 236 | |
| 237 | // FIXME(zcd): TransDataPlace is used to transform data from GPU to CPU and |
| 238 | // the enforced checks have been done in GetDeviceContext, so the |
| 239 | // `dev_ctx->Wait()` is necessary. But `dev_ctx->Wait()` will make the program |
| 240 | // slow, especially when the number of elements is little, for example, |
| 241 | // the elements of learning rate are one and it's CPU side. |
| 242 | // One solution is to use a CUDA kernel to complete the copy operation when |
| 243 | // the transforming is from CPU to GPU and the number of elements is little. |
| 244 | // But the embarrassment is that this solution this solution makes training |
| 245 | // slower. |
| 246 | phi::DenseTensor out; |
| 247 | phi::DeviceContext* dev_ctx = nullptr; |
| 248 | if (dst_place.GetType() != AllocationType::CPU) { |
| 249 | dev_ctx = pool.Get(dst_place); |
| 250 | } else { |
| 251 | dev_ctx = pool.Get(tensor.place()); |
| 252 | } |
| 253 | phi::Copy(*dev_ctx, tensor, dst_place, true, &out); |
| 254 | return out; |
| 255 | } |
| 256 | |
| 257 | template <typename Context> |
| 258 | phi::DenseTensor TensorContiguous(const Context& dev_ctx, |
no test coverage detected