// Copyright Epic Games, Inc. All Rights Reserved. #include "MemoryProfilerManager.h" #include "Modules/ModuleManager.h" #include "TraceServices/AnalysisService.h" #include "TraceServices/Model/Memory.h" #include "WorkspaceMenuStructure.h" #include "WorkspaceMenuStructureModule.h" // Insights #include "Insights/Common/InsightsMenuBuilder.h" #include "Insights/InsightsManager.h" #include "Insights/InsightsStyle.h" #include "Insights/MemoryProfiler/ViewModels/MemorySharedState.h" #include "Insights/MemoryProfiler/Widgets/SMemoryProfilerWindow.h" #include "Insights/Table/Widgets/STableTreeView.h" #include "Insights/Widgets/STimingView.h" //////////////////////////////////////////////////////////////////////////////////////////////////// #define LOCTEXT_NAMESPACE "MemoryProfilerManager" DEFINE_LOG_CATEGORY(MemoryProfiler); TSharedPtr FMemoryProfilerManager::Instance = nullptr; //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedPtr FMemoryProfilerManager::Get() { return FMemoryProfilerManager::Instance; } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedPtr FMemoryProfilerManager::CreateInstance() { ensure(!FMemoryProfilerManager::Instance.IsValid()); if (FMemoryProfilerManager::Instance.IsValid()) { FMemoryProfilerManager::Instance.Reset(); } FMemoryProfilerManager::Instance = MakeShared(FInsightsManager::Get()->GetCommandList()); return FMemoryProfilerManager::Instance; } //////////////////////////////////////////////////////////////////////////////////////////////////// FMemoryProfilerManager::FMemoryProfilerManager(TSharedRef InCommandList) : bIsInitialized(false), bIsAvailable(false), CommandList(InCommandList), ActionManager(this), ProfilerWindow(nullptr), bIsTimingViewVisible(false), bIsMemTagTreeViewVisible(false) { } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::Initialize(IUnrealInsightsModule& InsightsModule) { ensure(!bIsInitialized); if (bIsInitialized) { return; } bIsInitialized = true; UE_LOG(MemoryProfiler, Log, TEXT("Initialize")); // Register tick functions. OnTick = FTickerDelegate::CreateSP(this, &FMemoryProfilerManager::Tick); OnTickHandle = FTicker::GetCoreTicker().AddTicker(OnTick, 0.0f); FMemoryProfilerCommands::Register(); BindCommands(); FInsightsManager::Get()->GetSessionChangedEvent().AddSP(this, &FMemoryProfilerManager::OnSessionChanged); OnSessionChanged(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::Shutdown() { if (!bIsInitialized) { return; } bIsInitialized = false; FInsightsManager::Get()->GetSessionChangedEvent().RemoveAll(this); FMemoryProfilerCommands::Unregister(); // Unregister tick function. FTicker::GetCoreTicker().RemoveTicker(OnTickHandle); FMemoryProfilerManager::Instance.Reset(); UE_LOG(MemoryProfiler, Log, TEXT("Shutdown")); } //////////////////////////////////////////////////////////////////////////////////////////////////// FMemoryProfilerManager::~FMemoryProfilerManager() { ensure(!bIsInitialized); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::BindCommands() { ActionManager.Map_ToggleTimingViewVisibility_Global(); ActionManager.Map_ToggleMemTagTreeViewVisibility_Global(); } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::RegisterMajorTabs(IUnrealInsightsModule& InsightsModule) { const FInsightsMajorTabConfig& Config = InsightsModule.FindMajorTabConfig(FInsightsManagerTabs::MemoryProfilerTabId); if (Config.bIsAvailable) { // Register tab spawner for the Memory Insights. FTabSpawnerEntry& TabSpawnerEntry = FGlobalTabmanager::Get()->RegisterNomadTabSpawner(FInsightsManagerTabs::MemoryProfilerTabId, FOnSpawnTab::CreateRaw(this, &FMemoryProfilerManager::SpawnTab), FCanSpawnTab::CreateRaw(this, &FMemoryProfilerManager::CanSpawnTab)) .SetDisplayName(Config.TabLabel.IsSet() ? Config.TabLabel.GetValue() : LOCTEXT("MemoryProfilerTabTitle", "Memory Insights")) .SetTooltipText(Config.TabTooltip.IsSet() ? Config.TabTooltip.GetValue() : LOCTEXT("MemoryProfilerTooltipText", "Open the Memory Insights tab.")) .SetIcon(Config.TabIcon.IsSet() ? Config.TabIcon.GetValue() : FSlateIcon(FInsightsStyle::GetStyleSetName(), "MemoryProfiler.Icon.Small")); TSharedRef Group = Config.WorkspaceGroup.IsValid() ? Config.WorkspaceGroup.ToSharedRef() : FInsightsManager::Get()->GetInsightsMenuBuilder()->GetInsightsToolsGroup(); TabSpawnerEntry.SetGroup(Group); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::UnregisterMajorTabs() { FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(FInsightsManagerTabs::MemoryProfilerTabId); } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef FMemoryProfilerManager::SpawnTab(const FSpawnTabArgs& Args) { const TSharedRef DockTab = SNew(SDockTab) .TabRole(ETabRole::NomadTab); // Register OnTabClosed to handle I/O profiler manager shutdown. DockTab->SetOnTabClosed(SDockTab::FOnTabClosedCallback::CreateRaw(this, &FMemoryProfilerManager::OnTabClosed)); // Create the SMemoryProfilerWindow widget. TSharedRef Window = SNew(SMemoryProfilerWindow, DockTab, Args.GetOwnerWindow()); DockTab->SetContent(Window); AssignProfilerWindow(Window); return DockTab; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool FMemoryProfilerManager::CanSpawnTab(const FSpawnTabArgs& Args) const { return bIsAvailable; } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::OnTabClosed(TSharedRef TabBeingClosed) { RemoveProfilerWindow(); // Disable TabClosed delegate. TabBeingClosed->SetOnTabClosed(SDockTab::FOnTabClosedCallback()); } //////////////////////////////////////////////////////////////////////////////////////////////////// const TSharedRef FMemoryProfilerManager::GetCommandList() const { return CommandList; } //////////////////////////////////////////////////////////////////////////////////////////////////// const FMemoryProfilerCommands& FMemoryProfilerManager::GetCommands() { return FMemoryProfilerCommands::Get(); } //////////////////////////////////////////////////////////////////////////////////////////////////// FMemoryProfilerActionManager& FMemoryProfilerManager::GetActionManager() { return FMemoryProfilerManager::Instance->ActionManager; } //////////////////////////////////////////////////////////////////////////////////////////////////// FMemorySharedState* FMemoryProfilerManager::GetSharedState() { TSharedPtr Wnd = GetProfilerWindow(); return Wnd.IsValid() ? &Wnd->GetSharedState() : nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool FMemoryProfilerManager::Tick(float DeltaTime) { // Check if session has Memory events (to spawn the tab), but not too often. if (!bIsAvailable && AvailabilityCheck.Tick()) { uint32 TagCount = 0; TSharedPtr Session = FInsightsManager::Get()->GetSession(); if (Session.IsValid()) { Trace::FAnalysisSessionReadScope SessionReadScope(*Session.Get()); if (Session->IsAnalysisComplete()) { // Never check again during this session. AvailabilityCheck.Disable(); } const Trace::IMemoryProvider& MemoryProvider = Trace::ReadMemoryProvider(*Session.Get()); TagCount = MemoryProvider.GetTagCount(); } else { // Do not check again until the next session changed event (see OnSessionChanged). AvailabilityCheck.Disable(); } if (TagCount > 0) { bIsAvailable = true; #if !WITH_EDITOR const FName& TabId = FInsightsManagerTabs::MemoryProfilerTabId; if (FGlobalTabmanager::Get()->HasTabSpawner(TabId)) { UE_LOG(MemoryProfiler, Log, TEXT("Opening the \"Memory Insights\" tab...")); FGlobalTabmanager::Get()->TryInvokeTab(TabId); } #endif } } return true; } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::OnSessionChanged() { UE_LOG(MemoryProfiler, Log, TEXT("OnSessionChanged")); bIsAvailable = false; if (FInsightsManager::Get()->GetSession().IsValid()) { AvailabilityCheck.Enable(0.5); } else { AvailabilityCheck.Disable(); } TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->Reset(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::ShowHideTimingView(const bool bIsVisible) { bIsTimingViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FMemoryProfilerTabs::TimingViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void FMemoryProfilerManager::ShowHideMemTagTreeView(const bool bIsVisible) { bIsMemTagTreeViewVisible = bIsVisible; TSharedPtr Wnd = GetProfilerWindow(); if (Wnd.IsValid()) { Wnd->ShowHideTab(FMemoryProfilerTabs::MemTagTreeViewID, bIsVisible); } } //////////////////////////////////////////////////////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE