Files
paddlepaddle--paddle/paddle/phi/core/memory/memcpy.cc
T
2026-07-13 12:40:42 +08:00

1152 lines
43 KiB
C++

/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/phi/core/memory/memcpy.h"
#include "glog/logging.h"
#include "paddle/phi/api/profiler/event_tracing.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/platform/device/device_wrapper.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/utils/test_macros.h"
#ifdef PADDLE_WITH_XPU
#include <cuda.h>
#include <cuda_runtime.h>
#include <chrono>
#include "paddle/phi/backends/xpu/xpu_header.h"
#include "xpu/runtime.h"
#include "xpu/runtime_ex.h"
#endif
#include "paddle/common/flags.h"
COMMON_DECLARE_bool(use_default_stream);
namespace paddle::memory {
#ifdef PADDLE_WITH_CUSTOM_DEVICE
template <>
void Copy<CPUPlace, CustomPlace>(CPUPlace dst_place,
void* dst,
CustomPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
auto src_type = phi::PlaceHelper::GetDeviceType(src_place);
auto dst_type = phi::PlaceHelper::GetDeviceType(dst_place);
std::string msg = "Memcpy:" + src_type + "->" + dst_type;
phi::RecordEvent record_event(msg);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << ", stream=" << stream;
phi::DeviceManager::SetDevice(src_place);
phi::stream::Stream stream_wrapper(src_place, stream);
phi::DeviceManager::GetDeviceWithPlace(src_place)->MemoryCopyD2H(
dst, src, num, &stream_wrapper);
}
template <>
void Copy<CustomPlace, CPUPlace>(CustomPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
auto src_type = phi::PlaceHelper::GetDeviceType(src_place);
auto dst_type = phi::PlaceHelper::GetDeviceType(dst_place);
std::string msg = "Memcpy:" + src_type + "->" + dst_type;
phi::RecordEvent record_event(msg);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << ", stream=" << stream;
phi::DeviceManager::SetDevice(dst_place);
phi::stream::Stream stream_wrapper(dst_place, stream);
phi::DeviceManager::GetDeviceWithPlace(dst_place)->MemoryCopyH2D(
dst, src, num, &stream_wrapper);
}
template <>
void Copy<CustomPlace, CustomPlace>(CustomPlace dst_place,
void* dst,
CustomPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
auto src_type = phi::PlaceHelper::GetDeviceType(src_place);
auto dst_type = phi::PlaceHelper::GetDeviceType(dst_place);
std::string msg = "Memcpy:" + src_type + "->" + dst_type;
phi::RecordEvent record_event(msg);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << ", stream=" << stream;
if (src_type == dst_type) {
phi::DeviceManager::SetDevice(src_place);
phi::stream::Stream stream_wrapper(src_place, stream);
auto src_id = phi::PlaceHelper::GetDeviceId(src_place);
auto dst_id = phi::PlaceHelper::GetDeviceId(dst_place);
if (src_id == dst_id) {
phi::DeviceManager::GetDeviceWithPlace(src_place)->MemoryCopyD2D(
dst, src, num, &stream_wrapper);
} else {
phi::DeviceManager::GetDeviceWithPlace(src_place)->MemoryCopyP2P(
dst_place, dst, src, num, &stream_wrapper);
}
} else {
PADDLE_THROW(common::errors::Unavailable(
"Copy between %s and %s is not supported.", src_type, dst_type));
}
}
#endif // PADDLE_WITH_CUSTOM_DEVICE
template <>
PADDLE_API void Copy<CPUPlace, CPUPlace>(
CPUPlace, void* dst, CPUPlace, const void* src, size_t num) {
if (UNLIKELY(num == 0)) return;
VLOG(4) << "src: " << src << ", dst: " << dst << ", num: " << num;
std::memcpy(dst, src, num);
}
#ifdef PADDLE_WITH_IPU
template <>
void Copy<IPUPlace, CPUPlace>(IPUPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num) {
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<CPUPlace, IPUPlace>(CPUPlace dst_place,
void* dst,
IPUPlace src_place,
const void* src,
size_t num) {
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<IPUPlace, IPUPlace>(IPUPlace dst_place,
void* dst,
IPUPlace src_place,
const void* src,
size_t num) {
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
// NOTE: only for (CPUPlace and IPUPlace) -> (IPUPlace).
template <>
void Copy<IPUPlace, Place>(IPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num) {
if (src_place.GetType() == AllocationType::CPU) {
CPUPlace place_src;
return Copy(dst_place, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::IPU) {
IPUPlace place_src(src_place.GetDeviceId());
return Copy(dst_place, dst, place_src, src, num);
}
}
// NOTE: only for (IPUPlace) -> (CPUPlace and IPUPlace).
template <>
void Copy<Place, IPUPlace>(Place dst_place,
void* dst,
IPUPlace src_place,
const void* src,
size_t num) {
if (dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst;
return Copy(place_dst, dst, src_place, src, num);
} else if (dst_place.GetType() == AllocationType::IPU) {
IPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, src_place, src, num);
}
}
#endif
#ifdef PADDLE_WITH_XPU
template <>
void Copy<XPUPlace, CPUPlace>(XPUPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_HOST_TO_DEVICE size <= 0 (" << num << ")";
return;
}
platform::MemcpySyncH2D(dst, src, num, dst_place);
}
template <>
void Copy<CPUPlace, XPUPlace>(CPUPlace dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_DEVICE_TO_HOST size <= 0 (" << num << ")";
return;
}
platform::MemcpySyncD2H(dst, src, num, src_place);
}
template <>
void Copy<XPUPlace, XPUPlace>(XPUPlace dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_DEVICE_TO_DEVICE size <= 0 (" << num << ")";
return;
}
platform::MemcpySyncD2D(dst, dst_place, src, src_place, num);
}
// NOTE: only for (CPUPlace and XPUPlace) -> (XPUPlace).
template <>
void Copy<XPUPlace, Place>(XPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num) {
if (src_place.GetType() == AllocationType::CPU) {
CPUPlace place_src;
return Copy(dst_place, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPU) {
XPUPlace place_src(src_place.GetDeviceId());
return Copy(dst_place, dst, place_src, src, num);
}
}
// NOTE: only for (XPUPlace) -> (CPUPlace and XPUPlace).
template <>
void Copy<Place, XPUPlace>(Place dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num) {
if (dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst;
return Copy(place_dst, dst, src_place, src, num);
} else if (dst_place.GetType() == AllocationType::XPU) {
XPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, src_place, src, num);
}
}
template <>
void Copy<XPUPlace, CPUPlace>(XPUPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_HOST_TO_DEVICE size <= 0 (" << num << ")";
return;
}
// platform::MemcpySyncH2D(dst, src, num, dst_place);
xpu_memcpy_async(dst, src, num, XPU_HOST_TO_DEVICE, stream);
}
template <>
void Copy<CPUPlace, XPUPlace>(CPUPlace dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_DEVICE_TO_HOST size <= 0 (" << num << ")";
return;
}
// platform::MemcpySyncD2H(dst, src, num, src_place);
xpu_memcpy_async(dst, src, num, XPU_DEVICE_TO_HOST, stream);
}
template <>
void Copy<XPUPlace, XPUPlace>(XPUPlace dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (num <= 0) {
VLOG(1) << "memcpy XPU_DEVICE_TO_DEVICE size <= 0 (" << num << ")";
return;
}
platform::MemcpySyncD2D(dst, dst_place, src, src_place, num);
}
// NOTE: only for (CPUPlace and XPUPlace) -> (XPUPlace).
template <>
void Copy<XPUPlace, Place>(XPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
if (src_place.GetType() == AllocationType::CPU) {
CPUPlace place_src;
return Copy(dst_place, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPU) {
XPUPlace place_src(src_place.GetDeviceId());
return Copy(dst_place, dst, place_src, src, num);
}
}
// NOTE: only for (XPUPlace) -> (CPUPlace and XPUPlace).
template <>
void Copy<Place, XPUPlace>(Place dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst;
return Copy(place_dst, dst, src_place, src, num);
} else if (dst_place.GetType() == AllocationType::XPU) {
XPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, src_place, src, num);
}
}
template <>
void Copy<CPUPlace, XPUPinnedPlace>(CPUPlace dst_place,
void* dst,
XPUPinnedPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
PADDLE_API void Copy<XPUPinnedPlace, CPUPlace>(XPUPinnedPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<XPUPinnedPlace, XPUPinnedPlace>(XPUPinnedPlace dst_place,
void* dst,
XPUPinnedPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<XPUPinnedPlace, XPUPlace>(XPUPinnedPlace dst_place,
void* dst,
XPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetXPUDeviceId(src_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
// Record start time using std::chrono
auto start = std::chrono::high_resolution_clock::now();
if (stream) {
phi::RecordEvent record_event(
"cudaMemcpyAsync:XPU->XPUPinned", phi::TracerEventType::UserDefined, 1);
cudaMemcpyAsync(dst,
src,
num,
cudaMemcpyDeviceToHost,
reinterpret_cast<cudaStream_t>(stream));
} else {
cudaDeviceSynchronize();
phi::RecordEvent record_event(
"cudaMemcpy:XPU->XPUPinned", phi::TracerEventType::UserDefined, 1);
cudaMemcpy(dst, src, num, cudaMemcpyDeviceToHost);
}
// Record end time and calculate elapsed time in milliseconds
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end - start;
VLOG(4) << "cudaMemcpy time: " << elapsed.count() << " ms";
}
template <>
void Copy<XPUPlace, XPUPinnedPlace>(XPUPlace dst_place,
void* dst,
XPUPinnedPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetXPUDeviceId(dst_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
// Record start time using std::chrono
auto start = std::chrono::high_resolution_clock::now();
if (stream) {
phi::RecordEvent record_event(
"cudaMemcpyAsync:XPUPinned->XPU", phi::TracerEventType::UserDefined, 1);
cudaMemcpyAsync(dst,
src,
num,
cudaMemcpyHostToDevice,
reinterpret_cast<cudaStream_t>(stream));
} else {
cudaDeviceSynchronize();
phi::RecordEvent record_event(
"cudaMemcpy:XPUPinned->XPU", phi::TracerEventType::UserDefined, 1);
cudaMemcpy(dst, src, num, cudaMemcpyHostToDevice);
}
// Synchronize to ensure the memcpy operation is finished
if (stream) {
cudaStreamSynchronize(reinterpret_cast<cudaStream_t>(stream));
} else {
cudaDeviceSynchronize();
}
// Record end time and calculate elapsed time in milliseconds
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end - start;
VLOG(4) << "cudaMemcpy time: " << elapsed.count() << " ms";
}
// NOTE: for XPU and XPUPINNED.
template <>
PADDLE_API void Copy<Place, Place>(Place dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
if (src_place.GetType() == AllocationType::XPUPINNED &&
dst_place.GetType() == AllocationType::XPU) {
XPUPinnedPlace place_src;
XPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::XPU &&
dst_place.GetType() == AllocationType::XPUPINNED) {
XPUPinnedPlace place_dst;
XPUPlace place_src(src_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, stream);
} else {
PADDLE_THROW(::common::errors::Unimplemented(
"Asynchronous Copy from %s to %s is not supported.",
src_place,
dst_place));
}
}
template <>
void Copy<XPUPinnedPlace, Place>(XPUPinnedPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, stream);
}
template <>
void Copy<Place, XPUPinnedPlace>(Place dst_place,
void* dst,
XPUPinnedPlace src_place,
const void* src,
size_t num,
void* stream) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, stream);
}
template <>
void Copy<XPUPinnedPlace, Place>(XPUPinnedPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, nullptr);
}
template <>
void Copy<Place, XPUPinnedPlace>(Place dst_place,
void* dst,
XPUPinnedPlace src_place,
const void* src,
size_t num) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, nullptr);
}
#endif
#if (defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)) && \
!defined(PADDLE_WITH_CUSTOM_DEVICE)
static constexpr size_t kMaxGpuAsyncCopyBytes = 64 * 1024; // 64K
#ifdef PADDLE_WITH_HIP
inline void SyncCUDAStream() {
#if !defined(_WIN32)
hipStreamSynchronize(0);
#else
hipError_t e_sync = hipSuccess;
while (e_sync = hipStreamQuery(0)) {
if (e_sync == hipErrorNotReady) continue;
break;
}
#endif
}
#else
inline void SyncCUDAStream() {
#if !defined(_WIN32)
cudaStreamSynchronize(nullptr);
#else
cudaError_t e_sync = cudaSuccess;
while (e_sync = cudaStreamQuery(0)) {
if (e_sync == cudaErrorNotReady) continue;
break;
}
#endif
}
#endif
// NOTE(zcd): Do not use GpuMemcpySync as much as possible.
// because GpuMemcpySync issues the copying command to the default stream,
// which will make two commands from different streams cannot run concurrently.
// Reference:
// https://devblogs.nvidia.com/gpu-pro-tip-cuda-7-streams-simplify-concurrency/
template <>
PADDLE_API void Copy<CPUPlace, GPUPlace>(CPUPlace dst_place,
void* dst,
GPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetDeviceId(src_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
if (stream || FLAGS_use_default_stream) {
phi::RecordEvent record_event(
"GpuMemcpyAsync:GPU->CPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpyAsync(dst,
src,
num,
hipMemcpyDeviceToHost,
reinterpret_cast<gpuStream_t>(stream));
#else
platform::GpuMemcpyAsync(dst,
src,
num,
cudaMemcpyDeviceToHost,
reinterpret_cast<gpuStream_t>(stream));
#endif
} else {
phi::RecordEvent record_event(
"GpuMemcpySync:GPU->CPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpySync(dst, src, num, hipMemcpyDeviceToHost);
#else
platform::GpuMemcpySync(dst, src, num, cudaMemcpyDeviceToHost);
#endif
// FIXME(zjl): do we really need it?
if (num <= kMaxGpuAsyncCopyBytes) {
SyncCUDAStream();
}
}
}
template <>
PADDLE_API void Copy<GPUPlace, CPUPlace>(GPUPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetDeviceId(dst_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
if (stream || FLAGS_use_default_stream) {
phi::RecordEvent record_event(
"GpuMemcpyAsync:CPU->GPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpyAsync(dst,
src,
num,
hipMemcpyHostToDevice,
reinterpret_cast<gpuStream_t>(stream));
#else
platform::GpuMemcpyAsync(dst,
src,
num,
cudaMemcpyHostToDevice,
reinterpret_cast<gpuStream_t>(stream));
#endif
} else {
phi::RecordEvent record_event(
"GpuMemcpySync:CPU->GPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpySync(dst, src, num, hipMemcpyHostToDevice);
#else
platform::GpuMemcpySync(dst, src, num, cudaMemcpyHostToDevice);
#endif
// FIXME(zjl): do we really need it?
if (num <= kMaxGpuAsyncCopyBytes) {
SyncCUDAStream();
}
}
}
template <>
PADDLE_API void Copy<GPUPlace, GPUPlace>(GPUPlace dst_place,
void* dst,
GPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
VLOG(7) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
if (dst_place == src_place) {
platform::SetDeviceId(src_place.device);
if (stream || FLAGS_use_default_stream) {
phi::RecordEvent record_event("GpuMemcpyAsync(same_gpu):GPU->GPU",
phi::TracerEventType::UserDefined,
1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpyAsync(dst,
src,
num,
hipMemcpyDeviceToDevice,
reinterpret_cast<gpuStream_t>(stream));
#else
platform::GpuMemcpyAsync(dst,
src,
num,
cudaMemcpyDeviceToDevice,
reinterpret_cast<gpuStream_t>(stream));
#endif
} else {
phi::RecordEvent record_event("GpuMemcpySync(same_gpu):GPU->GPU",
phi::TracerEventType::UserDefined,
1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpySync(dst, src, num, hipMemcpyDeviceToDevice);
#else
platform::GpuMemcpySync(dst, src, num, cudaMemcpyDeviceToDevice);
#endif
}
} else {
if (stream) {
phi::RecordEvent record_event(
"GpuMemcpyPeerAsync:GPU->GPU", phi::TracerEventType::UserDefined, 1);
platform::GpuMemcpyPeerAsync(dst,
dst_place.device,
src,
src_place.device,
num,
reinterpret_cast<gpuStream_t>(stream));
} else {
phi::RecordEvent record_event(
"GpuMemcpyPeerSync:GPU->GPU", phi::TracerEventType::UserDefined, 1);
platform::GpuMemcpyPeerSync(
dst, dst_place.device, src, src_place.device, num);
}
}
}
template <>
void Copy<CPUPlace, GPUPinnedPlace>(CPUPlace dst_place,
void* dst,
GPUPinnedPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
PADDLE_API void Copy<GPUPinnedPlace, CPUPlace>(GPUPinnedPlace dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<GPUPinnedPlace, GPUPinnedPlace>(GPUPinnedPlace dst_place,
void* dst,
GPUPinnedPlace src_place,
const void* src,
size_t num) {
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (UNLIKELY(num == 0)) return;
std::memcpy(dst, src, num);
}
template <>
void Copy<GPUPinnedPlace, GPUPlace>(GPUPinnedPlace dst_place,
void* dst,
GPUPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetDeviceId(src_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
if (stream || FLAGS_use_default_stream) {
phi::RecordEvent record_event(
"GpuMemcpyAsync:GPU->CUDAPinned", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpyAsync(dst,
src,
num,
hipMemcpyDeviceToHost,
reinterpret_cast<gpuStream_t>(stream));
#else
platform::GpuMemcpyAsync(dst,
src,
num,
cudaMemcpyDeviceToHost,
reinterpret_cast<gpuStream_t>(stream));
#endif
} else {
phi::RecordEvent record_event(
"GpuMemcpySync:GPU->CUDAPinned", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpySync(dst, src, num, hipMemcpyDeviceToHost);
#else
platform::GpuMemcpySync(dst, src, num, cudaMemcpyDeviceToHost);
#endif
}
}
template <>
void Copy<GPUPlace, GPUPinnedPlace>(GPUPlace dst_place,
void* dst,
GPUPinnedPlace src_place,
const void* src,
size_t num,
void* stream) {
if (UNLIKELY(num == 0)) return;
platform::SetDeviceId(dst_place.device);
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place << " by stream(" << stream << ")";
if (stream || FLAGS_use_default_stream) {
phi::RecordEvent record_event(
"GpuMemcpyAsync:CUDAPinned->GPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpyAsync(dst,
src,
num,
hipMemcpyHostToDevice,
reinterpret_cast<gpuStream_t>(stream));
#else
platform::GpuMemcpyAsync(dst,
src,
num,
cudaMemcpyHostToDevice,
reinterpret_cast<gpuStream_t>(stream));
#endif
} else {
phi::RecordEvent record_event(
"GpuMemcpySync:CUDAPinned->GPU", phi::TracerEventType::UserDefined, 1);
#ifdef PADDLE_WITH_HIP
platform::GpuMemcpySync(dst, src, num, hipMemcpyHostToDevice);
#else
platform::GpuMemcpySync(dst, src, num, cudaMemcpyHostToDevice);
#endif
}
}
// NOTE: only for CPUPlace、CUDAPlace and CUDAPinnedPlace.
template <>
PADDLE_API void Copy<Place, Place>(Place dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst, place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::GPU) {
GPUPlace place_dst(dst_place.GetDeviceId());
CPUPlace place_src;
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::GPU &&
dst_place.GetType() == AllocationType::CPU) {
GPUPlace place_src(src_place.GetDeviceId());
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::GPU &&
dst_place.GetType() == AllocationType::GPU) {
GPUPlace place_src(src_place.GetDeviceId());
GPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::GPUPINNED) {
CPUPlace place_src;
GPUPinnedPlace place_dst;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::GPUPINNED &&
dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst;
GPUPinnedPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::GPUPINNED &&
dst_place.GetType() == AllocationType::GPUPINNED) {
GPUPinnedPlace place_dst;
GPUPinnedPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::GPUPINNED &&
dst_place.GetType() == AllocationType::GPU) {
GPUPinnedPlace place_src;
GPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::GPU &&
dst_place.GetType() == AllocationType::GPUPINNED) {
GPUPinnedPlace place_dst;
GPUPlace place_src(src_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, stream);
}
}
// NOTE: only for (CPUPlace, CUDAPlace and CUDAPinnedPlace) -> (CPUPlace).
template <>
PADDLE_API void Copy<CPUPlace, Place>(CPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, stream);
}
// NOTE: only for (CPUPlace) -> (CPUPlace, CUDAPlace and CUDAPinnedPlace).
template <>
PADDLE_API void Copy<Place, CPUPlace>(Place dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num,
void* stream) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, stream);
}
// NOTE: only for (CPUPlace, CUDAPlace and CUDAPinnedPlace) -> (CUDAPlace)
template <>
void Copy<GPUPlace, Place>(GPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
Copy(Place(dst_place.GetType(), dst_place.GetDeviceId()),
dst,
src_place,
src,
num,
stream);
}
// NOTE: only for (CUDAPlace) -> (CPUPlace, CUDAPlace and CUDAPinnedPlace)
template <>
PADDLE_API void Copy<Place, GPUPlace>(Place dst_place,
void* dst,
GPUPlace src_place,
const void* src,
size_t num,
void* stream) {
Copy(dst_place,
dst,
Place(src_place.GetType(), src_place.GetDeviceId()),
src,
num,
stream);
}
// NOTE: only for (CPUPlace, CUDAPlace and CUDAPinnedPlace) -> (CUDAPinnedPlace)
template <>
void Copy<GPUPinnedPlace, Place>(GPUPinnedPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, stream);
}
// NOTE: only for (CUDAPinnedPlace) -> (CPUPlace, CUDAPlace and CUDAPinnedPlace)
template <>
PADDLE_API void Copy<Place, GPUPinnedPlace>(Place dst_place,
void* dst,
GPUPinnedPlace src_place,
const void* src,
size_t num,
void* stream) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, stream);
}
// NOTE: only for (CPUPlace) -> (CUDAPinnedPlace)
template <>
void Copy<GPUPinnedPlace, Place>(GPUPinnedPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, nullptr);
}
// NOTE: only for (CUDAPinnedPlace) -> (CPUPlace)
template <>
void Copy<Place, GPUPinnedPlace>(Place dst_place,
void* dst,
GPUPinnedPlace src_place,
const void* src,
size_t num) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, nullptr);
}
#endif
// NOTE: Synchronous Copy for All Place.
template <>
PADDLE_API void Copy<Place, Place>(
Place dst_place, void* dst, Place src_place, const void* src, size_t num) {
if (UNLIKELY(num == 0)) return;
VLOG(4) << "memory::Copy " << num << " Bytes from " << src_place << " to "
<< dst_place;
if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::CPU) { // NOLINT
std::memcpy(dst, src, num);
}
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
else if (src_place.GetType() == AllocationType::GPU && // NOLINT
dst_place.GetType() == AllocationType::CPU) {
GPUPlace place_src(src_place.GetDeviceId());
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num, nullptr);
} else if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::GPUPINNED) {
std::memcpy(dst, src, num);
} else if (src_place.GetType() == AllocationType::GPUPINNED &&
dst_place.GetType() == AllocationType::CPU) {
std::memcpy(dst, src, num);
} else if (src_place.GetType() == AllocationType::GPUPINNED &&
dst_place.GetType() == AllocationType::GPUPINNED) {
std::memcpy(dst, src, num);
}
#endif
#ifdef PADDLE_WITH_XPU
else if (src_place.GetType() == AllocationType::CPU && // NOLINT
dst_place.GetType() == AllocationType::XPU) {
XPUPlace place_dst(dst_place.GetDeviceId());
CPUPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPU &&
dst_place.GetType() == AllocationType::CPU) {
XPUPlace place_src(src_place.GetDeviceId());
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPU &&
dst_place.GetType() == AllocationType::XPU) {
XPUPlace place_src(src_place.GetDeviceId());
XPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::CPU &&
dst_place.GetType() == AllocationType::XPUPINNED) {
CPUPlace place_src;
XPUPinnedPlace place_dst;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPUPINNED &&
dst_place.GetType() == AllocationType::CPU) {
CPUPlace place_dst;
XPUPinnedPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPUPINNED &&
dst_place.GetType() == AllocationType::XPUPINNED) {
XPUPinnedPlace place_dst;
XPUPinnedPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::XPUPINNED &&
dst_place.GetType() == AllocationType::XPU) {
XPUPinnedPlace place_src;
XPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, nullptr);
} else if (src_place.GetType() == AllocationType::XPU &&
dst_place.GetType() == AllocationType::XPUPINNED) {
XPUPinnedPlace place_dst;
XPUPlace place_src(src_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, nullptr);
}
#endif
#ifdef PADDLE_WITH_IPU
else if (src_place.GetType() == AllocationType::CPU && // NOLINT
dst_place.GetType() == AllocationType::IPU) {
IPUPlace place_dst(dst_place.GetDeviceId());
CPUPlace place_src;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::IPU &&
dst_place.GetType() == AllocationType::CPU) {
IPUPlace place_src(src_place.GetDeviceId());
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num);
} else if (src_place.GetType() == AllocationType::IPU &&
dst_place.GetType() == AllocationType::IPU) {
IPUPlace place_src(src_place.GetDeviceId());
IPUPlace place_dst(dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num);
}
#endif
#ifdef PADDLE_WITH_CUSTOM_DEVICE
else if (src_place.GetType() == AllocationType::CPU && // NOLINT
dst_place.GetType() == AllocationType::CUSTOM) {
CustomPlace place_dst(dst_place.GetDeviceType(), dst_place.GetDeviceId());
CPUPlace place_src;
return Copy(place_dst, dst, place_src, src, num, nullptr);
} else if (src_place.GetType() == AllocationType::CUSTOM &&
dst_place.GetType() == AllocationType::CPU) {
CustomPlace place_src(src_place.GetDeviceType(), src_place.GetDeviceId());
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num, nullptr);
} else if (src_place.GetType() == AllocationType::CUSTOM &&
dst_place.GetType() == AllocationType::CUSTOM) {
CustomPlace place_src(src_place.GetDeviceType(), src_place.GetDeviceId());
CustomPlace place_dst(dst_place.GetDeviceType(), dst_place.GetDeviceId());
return Copy(place_dst, dst, place_src, src, num, nullptr);
}
#endif
else { // NOLINT
PADDLE_THROW(::common::errors::Unimplemented(
"Copy from %s to %s is not supported.", src_place, dst_place));
}
}
// NOTE: Only for (CPUPlace) -> (CPUPlace and PinnedPlace).
template <>
PADDLE_API void Copy<Place, CPUPlace>(Place dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num);
}
// NOTE: Only for (CPUPlace and PinnedPlace) -> (CPUPlace).
template <>
PADDLE_API void Copy<CPUPlace, Place>(CPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num);
}
#if defined(PADDLE_WITH_CUSTOM_DEVICE) && !defined(PADDLE_WITH_CUDA) && \
!defined(PADDLE_WITH_HIP)
template <>
PADDLE_API void Copy<Place, Place>(Place dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
if (src_place.GetType() == AllocationType::CPU && // NOLINT
dst_place.GetType() == AllocationType::CUSTOM) {
CPUPlace place_src;
CustomPlace place_dst(dst_place);
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::CUSTOM && // NOLINT
dst_place.GetType() == AllocationType::CPU) {
CustomPlace place_src(src_place);
CPUPlace place_dst;
return Copy(place_dst, dst, place_src, src, num, stream);
} else if (src_place.GetType() == AllocationType::CUSTOM && // NOLINT
dst_place.GetType() == AllocationType::CUSTOM) {
CustomPlace place_src(src_place);
CustomPlace place_dst(dst_place);
return Copy(place_dst, dst, place_src, src, num, stream);
}
}
template <>
PADDLE_API void Copy<CPUPlace, Place>(CPUPlace dst_place,
void* dst,
Place src_place,
const void* src,
size_t num,
void* stream) {
Copy(Place(dst_place.GetType()), dst, src_place, src, num, stream);
}
// NOTE: only for (CPUPlace) -> (CPUPlace, CUDAPlace and CUDAPinnedPlace).
template <>
PADDLE_API void Copy<Place, CPUPlace>(Place dst_place,
void* dst,
CPUPlace src_place,
const void* src,
size_t num,
void* stream) {
Copy(dst_place, dst, Place(src_place.GetType()), src, num, stream);
}
#endif
} // namespace paddle::memory