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

918 lines
37 KiB
C++

// Copyright (c) 2024 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/platform/profiler.h"
#include <mutex> // NOLINT
#include <random>
#include <sstream>
#include <string>
#include <type_traits>
#include "paddle/phi/api/profiler/common_event.h"
#include "paddle/phi/api/profiler/device_tracer.h"
#include "paddle/phi/api/profiler/event.h" // import EventRole, TODO(TIEXING): remove later
#include "paddle/phi/api/profiler/host_tracer.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/core/platform/profiler/host_event_recorder.h"
#include "paddle/phi/core/platform/profiler_helper.h"
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_XPU)
#include "paddle/phi/backends/dynload/nvtx.h"
#endif
#include "paddle/common/flags.h"
#include "paddle/phi/core/os_info.h"
COMMON_DECLARE_bool(enable_record_memory);
COMMON_DECLARE_int64(host_trace_level);
struct ProfilerOptions {
uint32_t trace_switch = 0; // bit 0: cpu, bit 1: gpu, bit 2: xpu
uint32_t trace_level = FLAGS_host_trace_level;
};
// #if defined(_WIN32) && defined(PHI_SHARED)
// inline phi::ProfilerState phi::ProfilerHelper::g_state =
// phi::ProfilerState::kDisabled;
// inline bool phi::ProfilerHelper::g_enable_nvprof_hook = false;
// inline thread_local uint64_t phi::ProfilerHelper::g_thread_id;
// inline uint32_t phi::ProfilerHelper::g_next_thread_id = 0;
// inline std::mutex phi::ProfilerHelper::g_all_event_lists_mutex;
// inline std::list<std::shared_ptr<phi::EventList<phi::Event>>>
// phi::ProfilerHelper::g_all_event_lists;
// inline thread_local std::shared_ptr<phi::EventList<phi::Event>>
// phi::ProfilerHelper::g_event_list;
// inline std::list<std::shared_ptr<phi::EventList<phi::MemEvent>>>
// phi::ProfilerHelper::g_all_mem_event_lists;
// inline thread_local std::shared_ptr<phi::EventList<phi::MemEvent>>
// phi::ProfilerHelper::g_mem_event_list;
// inline std::mutex phi::ProfilerHelper::g_all_mem_event_lists_mutex;
// #endif
namespace paddle::platform {
MemEventRecorder MemEventRecorder::recorder;
RecordInstantEvent::RecordInstantEvent(const char *name,
phi::TracerEventType type,
uint32_t level) {
if (UNLIKELY(phi::HostTraceLevel::GetInstance().NeedTrace(level) == false)) {
return;
}
auto start_end_ns = phi::PosixInNsec();
HostEventRecorder<phi::CommonEvent>::GetInstance().RecordEvent(
name, start_end_ns, start_end_ns, EventRole::kOrdinary, type);
}
bool RecordMemEvent::IsEnabled() { return FLAGS_enable_record_memory; }
std::map<const char *, std::map<uint64_t, std::vector<uint64_t>>>
RecordMemEvent::size_cache;
std::map<const char *, std::map<uint64_t, bool>>
RecordMemEvent::has_initialized;
RecordMemEvent::RecordMemEvent(const void *ptr,
const Place &place,
size_t size,
const phi::TracerMemEventType type) {
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled &&
FLAGS_enable_host_event_recorder_hook == false) {
return;
}
if (IsEnabled() == false) {
return;
}
if (type == phi::TracerMemEventType::Allocate) {
uint64_t current_allocated = 0;
uint64_t peak_allocated = 0;
uint64_t current_reserved = 0; // 0 means keep the same as before
uint64_t peak_reserved = 0; // 0 means keep the same as before
if (phi::is_cpu_place(place) || phi::is_cuda_pinned_place(place)) {
if (RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] = true;
} else {
current_allocated =
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId());
peak_allocated =
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId());
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0] =
current_allocated;
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2] =
peak_allocated;
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
}
} else {
if (RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] = true;
} else {
current_allocated = DEVICE_MEMORY_STAT_CURRENT_VALUE(
Allocated, place.GetDeviceId()); // NOLINT
peak_allocated =
DEVICE_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId());
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0] =
current_allocated;
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2] =
peak_allocated;
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
}
}
platform::MemEventRecorder::Instance().PushMemRecord(ptr,
place,
size,
type,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
} else if (type == phi::TracerMemEventType::ReservedAllocate) {
uint64_t current_reserved = 0;
uint64_t peak_reserved = 0;
uint64_t current_allocated = 0; // 0 means keep the same as before
uint64_t peak_allocated = 0; // 0 means keep the same as before
if (phi::is_cpu_place(place) || phi::is_cuda_pinned_place(place)) {
if (RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] = true;
} else {
current_reserved =
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId());
peak_reserved =
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId());
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1] =
current_reserved;
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3] =
peak_reserved;
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
}
} else {
if (RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] = true;
} else {
current_reserved = DEVICE_MEMORY_STAT_CURRENT_VALUE(
Reserved, place.GetDeviceId()); // NOLINT
peak_reserved = DEVICE_MEMORY_STAT_PEAK_VALUE(
Reserved, place.GetDeviceId()); // NOLINT
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1] =
current_reserved;
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3] =
peak_reserved;
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
}
}
platform::MemEventRecorder::Instance().PushMemRecord(ptr,
place,
size,
type,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
} else if (type == phi::TracerMemEventType::Free) {
uint64_t current_allocated = 0;
uint64_t peak_allocated = 0;
uint64_t current_reserved = 0; // 0 means keep the same as before
uint64_t peak_reserved = 0; // 0 means keep the same as before
if (phi::is_cpu_place(place) || phi::is_cuda_pinned_place(place)) {
if (RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] = true;
} else {
current_allocated =
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId());
peak_allocated =
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId());
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0] =
current_allocated;
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2] =
peak_allocated;
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
}
} else {
if (RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] = true;
} else {
current_allocated = DEVICE_MEMORY_STAT_CURRENT_VALUE(
Allocated, place.GetDeviceId()); // NOLINT
peak_allocated = DEVICE_MEMORY_STAT_PEAK_VALUE(
Allocated, place.GetDeviceId()); // NOLINT
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0] =
current_allocated;
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2] =
peak_allocated;
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
}
}
platform::MemEventRecorder::Instance().PopMemRecord(ptr,
place,
size,
type,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
} else if (type == phi::TracerMemEventType::ReservedFree) {
uint64_t current_reserved = 0;
uint64_t peak_reserved = 0;
uint64_t current_allocated = 0; // 0 means keep the same as before
uint64_t peak_allocated = 0; // 0 means keep the same as before
if (phi::is_cpu_place(place) || phi::is_cuda_pinned_place(place)) {
if (RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()].push_back(
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["cpu"][place.GetDeviceId()] = true;
} else {
current_reserved =
HOST_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId());
peak_reserved =
HOST_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId());
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][1] =
current_reserved;
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][3] =
peak_reserved;
current_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][0];
peak_allocated =
RecordMemEvent::size_cache["cpu"][place.GetDeviceId()][2];
}
} else {
if (RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] ==
false) {
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_CURRENT_VALUE(Reserved, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Allocated, place.GetDeviceId()));
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()].push_back(
DEVICE_MEMORY_STAT_PEAK_VALUE(Reserved, place.GetDeviceId()));
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
current_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
peak_reserved =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3];
RecordMemEvent::has_initialized["gpu"][place.GetDeviceId()] = true;
} else {
current_reserved = DEVICE_MEMORY_STAT_CURRENT_VALUE(
Reserved, place.GetDeviceId()); // NOLINT
peak_reserved = DEVICE_MEMORY_STAT_PEAK_VALUE(
Reserved, place.GetDeviceId()); // NOLINT
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][1] =
current_reserved;
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][3] =
peak_reserved;
current_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][0];
peak_allocated =
RecordMemEvent::size_cache["gpu"][place.GetDeviceId()][2];
}
}
platform::MemEventRecorder::Instance().PopMemRecord(ptr,
place,
size,
type,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
}
}
void MemEventRecorder::PushMemRecord(const void *ptr,
const Place &place,
size_t size) {
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) {
return;
}
std::lock_guard<std::mutex> guard(mtx_);
auto &events = address_memevent_[place];
PADDLE_ENFORCE_EQ(events.count(ptr),
0,
common::errors::InvalidArgument(
"The Place can't exist in the stage of PushMemRecord"));
events.emplace(
ptr, std::make_unique<MemEventRecorder::RecordMemEvent>(place, size));
}
void MemEventRecorder::PushMemRecord(const void *ptr,
const Place &place,
size_t size,
phi::TracerMemEventType type,
uint64_t current_allocated,
uint64_t current_reserved,
uint64_t peak_allocated,
uint64_t peak_reserved) {
std::lock_guard<std::mutex> guard(mtx_);
if (FLAGS_enable_host_event_recorder_hook) { // new MemRecord
HostEventRecorder<phi::CommonMemEvent>::GetInstance().RecordEvent(
phi::PosixInNsec(),
reinterpret_cast<uint64_t>(ptr),
type,
size,
place,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
return;
}
if (type == phi::TracerMemEventType::ReservedAllocate) {
// old profiler only analyse memory managed by paddle.
return;
}
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) return;
auto &events = address_memevent_[place];
PADDLE_ENFORCE_EQ(events.count(ptr),
0,
common::errors::InvalidArgument(
"The Place can't exist in the stage of PushMemRecord"));
events.emplace(
ptr, std::make_unique<MemEventRecorder::RecordMemEvent>(place, size));
}
void MemEventRecorder::PopMemRecord(const void *ptr, const Place &place) {
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) {
return;
}
std::lock_guard<std::mutex> guard(mtx_);
auto &events = address_memevent_[place];
auto iter = events.find(ptr);
// The ptr maybe not in address_memevent
if (iter != events.end()) {
events.erase(iter);
}
}
void MemEventRecorder::PopMemRecord(const void *ptr,
const Place &place,
size_t size,
phi::TracerMemEventType type,
uint64_t current_allocated,
uint64_t current_reserved,
uint64_t peak_allocated,
uint64_t peak_reserved) {
std::lock_guard<std::mutex> guard(mtx_);
if (FLAGS_enable_host_event_recorder_hook) { // new MemRecord
HostEventRecorder<phi::CommonMemEvent>::GetInstance().RecordEvent(
phi::PosixInNsec(),
reinterpret_cast<uint64_t>(ptr),
type,
-size,
place,
current_allocated,
current_reserved,
peak_allocated,
peak_reserved);
return;
}
if (type == phi::TracerMemEventType::ReservedFree) {
// old profiler only analyse memory managed by paddle.
return;
}
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) return;
auto &events = address_memevent_[place];
auto iter = events.find(ptr);
// The ptr maybe not in address_memevent
if (iter != events.end()) {
events.erase(iter);
}
}
void MemEventRecorder::Flush() {
std::lock_guard<std::mutex> guard(mtx_);
address_memevent_.clear();
}
MemEventRecorder::RecordMemEvent::RecordMemEvent(const Place &place,
size_t bytes)
: place_(place),
bytes_(bytes),
start_ns_(phi::PosixInNsec()),
end_ns_(0),
alloc_in_(phi::CurAnnotationName()) {
PushMemEvent(start_ns_, end_ns_, bytes_, place_, alloc_in_);
}
MemEventRecorder::RecordMemEvent::~RecordMemEvent() { // NOLINT
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
end_ns_ = phi::PosixInNsec();
auto annotation_free = phi::CurAnnotationName();
if (tracer) {
tracer->AddMemInfoRecord(start_ns_,
end_ns_,
bytes_,
place_,
alloc_in_,
annotation_free,
g_mem_thread_id);
}
PopMemEvent(start_ns_, end_ns_, bytes_, place_, annotation_free);
}
RecordBlock::RecordBlock(int block_id)
: is_enabled_(false), start_ns_(phi::PosixInNsec()) {
// lock is not needed, the code below is thread-safe
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) return;
is_enabled_ = true;
phi::SetCurBlock(block_id);
name_ = string::Sprintf("block_%d", block_id);
}
RecordBlock::~RecordBlock() {
// lock is not needed, the code below is thread-safe
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled || !is_enabled_)
return;
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
if (tracer) {
// We try to put all blocks at the same nested depth in the
// same timeline lane. and distinguish the using thread_id.
tracer->AddCPURecords(name_,
start_ns_,
phi::PosixInNsec(),
phi::BlockDepth(),
phi::ProfilerHelper::g_thread_id);
}
phi::ClearCurBlock();
}
void PushMemEvent(uint64_t start_ns,
uint64_t end_ns,
size_t bytes,
const Place &place,
const std::string &annotation) {
GetMemEventList().Record(EventType::kPushRange,
start_ns,
end_ns,
bytes,
place,
g_mem_thread_id,
annotation);
}
void PopMemEvent(uint64_t start_ns,
uint64_t end_ns,
size_t bytes,
const Place &place,
const std::string &annotation) {
GetMemEventList().Record(EventType::kPopRange,
start_ns,
end_ns,
bytes,
place,
g_mem_thread_id,
annotation);
}
void Mark(const std::string &name) {
if (FLAGS_enable_host_event_recorder_hook) {
HostEventRecorder<phi::CommonEvent>::GetInstance().RecordEvent(
name, 0, 0, EventRole::kOrdinary, phi::TracerEventType::UserDefined);
return;
}
GetEventList().Record(
EventType::kMark, name, phi::ProfilerHelper::g_thread_id);
}
void EnableProfiler(ProfilerState state) {
PADDLE_ENFORCE_NE(state,
ProfilerState::kDisabled,
common::errors::InvalidArgument(
"Can't enable profiling, since the input state is "
"ProfilerState::kDisabled"));
SynchronizeAllDevice();
std::lock_guard<std::mutex> l(profiler_mu);
if (state == phi::ProfilerHelper::g_state) {
return;
}
phi::ProfilerHelper::g_state = state;
ProfilerOptions option;
phi::HostTraceLevel::GetInstance().SetLevel(option.trace_level);
should_send_profile_state = true;
phi::GetDeviceTracer()->Enable();
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
if (phi::ProfilerHelper::g_state == ProfilerState::kCUDA ||
phi::ProfilerHelper::g_state == ProfilerState::kAll ||
phi::ProfilerHelper::g_state == ProfilerState::kCPU) {
// Generate some dummy events first to reduce the startup overhead.
DummyKernelAndEvent();
phi::GetDeviceTracer()->Reset();
}
#endif
// Mark the profiling start.
Mark("_start_profiler_");
}
void ResetProfiler() {
SynchronizeAllDevice();
phi::GetDeviceTracer()->Reset();
MemEventRecorder::Instance().Flush();
std::lock_guard<std::mutex> guard(
phi::ProfilerHelper::g_all_event_lists_mutex);
for (auto &all_event_list : phi::ProfilerHelper::g_all_event_lists) {
all_event_list->Clear();
}
for (auto &all_mem_event_list : phi::ProfilerHelper::g_all_mem_event_lists) {
all_mem_event_list->Clear();
}
}
static std::map<uint64_t, phi::ThreadEvents> DockHostEventRecorderHostPart();
static void DockHostEventRecorderDevicePart(
const std::map<uint64_t, phi::ThreadEvents> &thr_events);
void DisableProfiler(EventSortingKey sorted_key,
const std::string &profile_path) {
SynchronizeAllDevice();
auto thr_events = DockHostEventRecorderHostPart();
MemEventRecorder::Instance().Flush();
std::lock_guard<std::mutex> l(profiler_mu);
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) return;
// Mark the profiling stop.
Mark("_stop_profiler_");
DealWithShowName();
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
if (tracer->IsEnabled()) {
tracer->Disable();
DockHostEventRecorderDevicePart(thr_events);
tracer->GenEventKernelCudaElapsedTime();
tracer->GenProfile(profile_path);
}
std::vector<std::vector<Event>> all_events = GetAllEvents();
ParseEvents(all_events, true, sorted_key);
ParseEvents(all_events, false, sorted_key);
std::vector<std::vector<MemEvent>> all_mem_events = GetMemEvents();
ParseMemEvents(all_mem_events);
ResetProfiler();
phi::ProfilerHelper::g_state = ProfilerState::kDisabled;
g_tracer_option = TracerOption::kDefault;
should_send_profile_state = true;
}
void CompleteProfilerEvents(phi::proto::Profile *tracer_profile,
std::vector<std::vector<Event>> *time_events,
std::vector<std::vector<MemEvent>> *mem_events) {
SynchronizeAllDevice();
auto thr_events = DockHostEventRecorderHostPart();
MemEventRecorder::Instance().Flush();
std::lock_guard<std::mutex> l(profiler_mu);
if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) return;
// Mark the profiling stop.
Mark("_stop_profiler_");
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
if (tracer->IsEnabled() && tracer_profile != nullptr) {
tracer->Disable();
DockHostEventRecorderDevicePart(thr_events);
tracer->GenEventKernelCudaElapsedTime();
*tracer_profile = tracer->GetProfile();
}
if (time_events != nullptr) {
*time_events = GetAllEvents();
}
if (mem_events != nullptr) {
*mem_events = GetMemEvents();
}
ResetProfiler();
phi::ProfilerHelper::g_state = ProfilerState::kDisabled;
g_tracer_option = TracerOption::kDefault;
should_send_profile_state = true;
}
std::vector<std::vector<Event>> GetAllEvents() {
std::lock_guard<std::mutex> guard(
phi::ProfilerHelper::g_all_event_lists_mutex);
std::vector<std::vector<Event>> result;
for (auto &all_event_list : phi::ProfilerHelper::g_all_event_lists) {
result.emplace_back(all_event_list->Reduce());
}
return result;
}
bool IsProfileEnabled() {
return phi::ProfilerHelper::g_state != ProfilerState::kDisabled;
}
bool ShouldSendProfileState() { return should_send_profile_state; }
std::string OpName(
const std::map<std::string, std::vector<std::string>> &name_map,
const std::string &type_name) {
if (platform::GetTracerOption() != platform::TracerOption::kAllOpDetail ||
!IsProfileEnabled())
return "";
std::string ret = type_name + "%";
for (const auto &map_item : name_map) {
auto name_outputs = map_item.second;
if (!name_outputs.empty()) {
ret.append(name_outputs[0]);
break;
}
}
ret = ret + "%";
return ret;
}
void SetTracerOption(TracerOption option) {
std::lock_guard<std::mutex> l(profiler_mu);
g_tracer_option = option;
}
platform::TracerOption GetTracerOption() { return g_tracer_option; }
void SetProfileListener() {
std::mt19937 rng;
rng.seed(std::random_device()());
std::uniform_int_distribution<std::mt19937::result_type> dist6(
1, std::numeric_limits<int>::max());
profiler_lister_id = dist6(rng);
}
int64_t ListenerId() { return profiler_lister_id; }
void NvprofEnableRecordEvent() {
SynchronizeAllDevice();
phi::ProfilerHelper::g_enable_nvprof_hook = true;
}
void NvprofDisableRecordEvent() {
phi::ProfilerHelper::g_enable_nvprof_hook = false;
}
void EnableHostEventRecorder() { FLAGS_enable_host_event_recorder_hook = true; }
void DisableHostEventRecorder() {
FLAGS_enable_host_event_recorder_hook = false;
}
void EnableMemoryRecorder() { FLAGS_enable_record_memory = true; }
void DisableMemoryRecorder() { FLAGS_enable_record_memory = false; }
std::string PrintHostEvents() {
std::ostringstream oss;
auto host_evt_sec =
HostEventRecorder<phi::CommonEvent>::GetInstance().GatherEvents();
for (const auto &thr_evt_sec : host_evt_sec.thr_sections) {
oss << thr_evt_sec.thread_id << std::endl;
for (const auto &evt : thr_evt_sec.events) {
oss << "{ " << evt.name << " | " << evt.start_ns << "ns | " << evt.end_ns
<< "ns | " << (evt.end_ns - evt.start_ns) / 1000.000 // NOLINT
<< "us }" << std::endl;
}
}
return oss.str();
}
static void EmulateEventPushAndPop(
const HostEventSection<phi::CommonEvent> &host_sec,
std::map<uint64_t, phi::ThreadEvents> *out) {
for (const auto &thr_sec : host_sec.thr_sections) {
uint64_t tid = thr_sec.thread_id;
auto cur_thr_list = std::make_shared<EventList<Event>>();
phi::ProfilerHelper::g_all_event_lists.emplace_front(cur_thr_list);
// for nesting events
std::stack<size_t> evt_stk;
std::stack<std::string> prefix_stk;
std::map<uint64_t, size_t> start2evt;
for (size_t i = 0; i < thr_sec.events.size(); ++i) {
const auto &evt = thr_sec.events[i];
start2evt[evt.start_ns] = i;
}
auto iter = start2evt.begin();
// loop events
for (size_t i = 0; i < thr_sec.events.size(); ++i) {
const auto &thr_evts = thr_sec.events;
const auto &evt = thr_evts[i];
// For nesting events
while (!evt_stk.empty() && thr_evts[evt_stk.top()].end_ns <= evt.end_ns) {
evt_stk.pop();
prefix_stk.pop();
}
while (iter != start2evt.end() &&
thr_evts[iter->second].start_ns < evt.start_ns) {
if (thr_evts[iter->second].end_ns > evt.start_ns) {
evt_stk.push(iter->second);
std::string prefix = thr_evts[iter->second].name;
if (!prefix_stk.empty()) {
// prefix = prefix_stk.top() + "/" + prefix;
prefix.insert(0, "/").insert(0, prefix_stk.top());
}
prefix_stk.push(prefix);
}
++iter;
}
// Record orig event pair
std::string name =
prefix_stk.empty() ? evt.name : prefix_stk.top() + "/" + evt.name;
const char *attr = (evt.attr == nullptr ? "none" : evt.attr);
Event *orig_evt = cur_thr_list->Record(
EventType::kPushRange, name, tid, evt.role, attr);
(*out)[tid][evt.end_ns] = std::make_pair(orig_evt, evt.start_ns);
cur_thr_list->Record(EventType::kPopRange, name, tid, evt.role, attr);
}
}
}
static void EmulateCPURecordsAdd(
const HostEventSection<phi::CommonEvent> &host_sec) {
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
if (tracer == nullptr) {
return;
}
for (const auto &thr_sec : host_sec.thr_sections) {
uint64_t tid = thr_sec.thread_id;
for (const auto &evt : thr_sec.events) {
tracer->AddCPURecords(
evt.name, evt.start_ns, evt.end_ns, phi::BlockDepth(), tid);
}
}
}
static void EmulateCorrelation(
const std::map<uint64_t, phi::ThreadEvents> &thr_events) {
phi::DeviceTracer *tracer = phi::GetDeviceTracer();
if (tracer == nullptr) {
return;
}
tracer->AddAnnotations(thr_events);
}
static std::map<uint64_t, phi::ThreadEvents> DockHostEventRecorderHostPart() {
std::map<uint64_t, phi::ThreadEvents> thr_events;
if (FLAGS_enable_host_event_recorder_hook == false) {
return thr_events;
}
auto host_evt_sec =
HostEventRecorder<phi::CommonEvent>::GetInstance().GatherEvents();
EmulateEventPushAndPop(host_evt_sec, &thr_events);
EmulateCPURecordsAdd(host_evt_sec);
return thr_events;
}
static void DockHostEventRecorderDevicePart(
const std::map<uint64_t, phi::ThreadEvents> &thr_events) {
if (FLAGS_enable_host_event_recorder_hook == false) {
return;
}
EmulateCorrelation(thr_events);
}
} // namespace paddle::platform