// 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 // NOLINT #include #include #include #include #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>> // phi::ProfilerHelper::g_all_event_lists; // inline thread_local std::shared_ptr> // phi::ProfilerHelper::g_event_list; // inline std::list>> // phi::ProfilerHelper::g_all_mem_event_lists; // inline thread_local std::shared_ptr> // 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::GetInstance().RecordEvent( name, start_end_ns, start_end_ns, EventRole::kOrdinary, type); } bool RecordMemEvent::IsEnabled() { return FLAGS_enable_record_memory; } std::map>> RecordMemEvent::size_cache; std::map> 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 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(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 guard(mtx_); if (FLAGS_enable_host_event_recorder_hook) { // new MemRecord HostEventRecorder::GetInstance().RecordEvent( phi::PosixInNsec(), reinterpret_cast(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(place, size)); } void MemEventRecorder::PopMemRecord(const void *ptr, const Place &place) { if (phi::ProfilerHelper::g_state == ProfilerState::kDisabled) { return; } std::lock_guard 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 guard(mtx_); if (FLAGS_enable_host_event_recorder_hook) { // new MemRecord HostEventRecorder::GetInstance().RecordEvent( phi::PosixInNsec(), reinterpret_cast(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 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::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 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 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 DockHostEventRecorderHostPart(); static void DockHostEventRecorderDevicePart( const std::map &thr_events); void DisableProfiler(EventSortingKey sorted_key, const std::string &profile_path) { SynchronizeAllDevice(); auto thr_events = DockHostEventRecorderHostPart(); MemEventRecorder::Instance().Flush(); std::lock_guard 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> all_events = GetAllEvents(); ParseEvents(all_events, true, sorted_key); ParseEvents(all_events, false, sorted_key); std::vector> 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> *time_events, std::vector> *mem_events) { SynchronizeAllDevice(); auto thr_events = DockHostEventRecorderHostPart(); MemEventRecorder::Instance().Flush(); std::lock_guard 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> GetAllEvents() { std::lock_guard guard( phi::ProfilerHelper::g_all_event_lists_mutex); std::vector> 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> &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 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 dist6( 1, std::numeric_limits::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::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 &host_sec, std::map *out) { for (const auto &thr_sec : host_sec.thr_sections) { uint64_t tid = thr_sec.thread_id; auto cur_thr_list = std::make_shared>(); phi::ProfilerHelper::g_all_event_lists.emplace_front(cur_thr_list); // for nesting events std::stack evt_stk; std::stack prefix_stk; std::map 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 &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 &thr_events) { phi::DeviceTracer *tracer = phi::GetDeviceTracer(); if (tracer == nullptr) { return; } tracer->AddAnnotations(thr_events); } static std::map DockHostEventRecorderHostPart() { std::map thr_events; if (FLAGS_enable_host_event_recorder_hook == false) { return thr_events; } auto host_evt_sec = HostEventRecorder::GetInstance().GatherEvents(); EmulateEventPushAndPop(host_evt_sec, &thr_events); EmulateCPURecordsAdd(host_evt_sec); return thr_events; } static void DockHostEventRecorderDevicePart( const std::map &thr_events) { if (FLAGS_enable_host_event_recorder_hook == false) { return; } EmulateCorrelation(thr_events); } } // namespace paddle::platform