Files
UnrealEngine/Engine/Source/Developer/TraceInsights/Private/Insights/ContextSwitches/ContextSwitchesProfilerManager.cpp
2025-05-18 13:04:45 +08:00

206 lines
6.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ContextSwitchesProfilerManager.h"
#include "Features/IModularFeatures.h"
#include "Framework/Commands/UICommandList.h"
#include "Modules/ModuleManager.h"
// TraceServices
#include "TraceServices/Model/ContextSwitches.h"
// TraceInsights
#include "Insights/ContextSwitches/ViewModels/ContextSwitchesSharedState.h"
#include "Insights/ITimingViewExtender.h"
#include "Insights/TimingProfiler/TimingProfilerManager.h"
#include "Insights/TimingProfiler/Widgets/STimingProfilerWindow.h"
#include "Insights/Widgets/STimingView.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace UE::Insights::ContextSwitches
{
////////////////////////////////////////////////////////////////////////////////////////////////////
TSharedPtr<FContextSwitchesProfilerManager> FContextSwitchesProfilerManager::Instance = nullptr;
////////////////////////////////////////////////////////////////////////////////////////////////////
TSharedPtr<FContextSwitchesProfilerManager> FContextSwitchesProfilerManager::Get()
{
return FContextSwitchesProfilerManager::Instance;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TSharedPtr<FContextSwitchesProfilerManager> FContextSwitchesProfilerManager::CreateInstance()
{
ensure(!FContextSwitchesProfilerManager::Instance.IsValid());
if (FContextSwitchesProfilerManager::Instance.IsValid())
{
FContextSwitchesProfilerManager::Instance.Reset();
}
FContextSwitchesProfilerManager::Instance = MakeShared<FContextSwitchesProfilerManager>(FInsightsManager::Get()->GetCommandList());
return FContextSwitchesProfilerManager::Instance;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FContextSwitchesProfilerManager::FContextSwitchesProfilerManager(TSharedRef<FUICommandList> InCommandList)
: bIsInitialized(false)
, bIsAvailable(false)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::Initialize(IUnrealInsightsModule& InsightsModule)
{
ensure(!bIsInitialized);
if (bIsInitialized)
{
return;
}
bIsInitialized = true;
// Register tick functions.
OnTick = FTickerDelegate::CreateSP(this, &FContextSwitchesProfilerManager::Tick);
OnTickHandle = FTSTicker::GetCoreTicker().AddTicker(OnTick, 0.0f);
FOnRegisterMajorTabExtensions* TimingProfilerLayoutExtension = InsightsModule.FindMajorTabLayoutExtension(FInsightsManagerTabs::TimingProfilerTabId);
if (TimingProfilerLayoutExtension)
{
TimingProfilerLayoutExtension->AddRaw(this, &FContextSwitchesProfilerManager::RegisterTimingProfilerLayoutExtensions);
}
FInsightsManager::Get()->GetSessionChangedEvent().AddSP(this, &FContextSwitchesProfilerManager::OnSessionChanged);
OnSessionChanged();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::Shutdown()
{
if (!bIsInitialized)
{
return;
}
bIsInitialized = false;
FInsightsManager::Get()->GetSessionChangedEvent().RemoveAll(this);
// Unregister tick function.
FTSTicker::GetCoreTicker().RemoveTicker(OnTickHandle);
FContextSwitchesProfilerManager::Instance.Reset();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FContextSwitchesProfilerManager::~FContextSwitchesProfilerManager()
{
ensure(!bIsInitialized);
if (ContextSwitchesSharedState.IsValid())
{
IModularFeatures::Get().UnregisterModularFeature(Timing::TimingViewExtenderFeatureName, ContextSwitchesSharedState.Get());
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::RegisterMajorTabs(IUnrealInsightsModule& InsightsModule)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::UnregisterMajorTabs()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool FContextSwitchesProfilerManager::Tick(float DeltaTime)
{
// Check if session has ContextSwitch events (to spawn the tab), but not too often.
if (!bIsAvailable && AvailabilityCheck.Tick())
{
bool bShouldBeAvailable = false;
TSharedPtr<const TraceServices::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
if (Session.IsValid())
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
const TraceServices::IContextSwitchesProvider* ContextSwitchesProvider = TraceServices::ReadContextSwitchesProvider(*Session.Get());
if (ContextSwitchesProvider && ContextSwitchesProvider->HasData())
{
using namespace UE::Insights::TimingProfiler;
TSharedPtr<STimingProfilerWindow> Window = FTimingProfilerManager::Get()->GetProfilerWindow();
if (!Window.IsValid())
{
return true;
}
TSharedPtr<STimingView> TimingView = Window->GetTimingView();
if (!TimingView.IsValid())
{
return true;
}
bIsAvailable = true;
if (!ContextSwitchesSharedState.IsValid())
{
ContextSwitchesSharedState = MakeShared<FContextSwitchesSharedState>(TimingView.Get());
ContextSwitchesSharedState->AddCommands();
IModularFeatures::Get().RegisterModularFeature(Timing::TimingViewExtenderFeatureName, ContextSwitchesSharedState.Get());
}
}
if (Session->IsAnalysisComplete())
{
// Never check again during this session.
AvailabilityCheck.Disable();
}
}
else
{
// Do not check again until the next session changed event (see OnSessionChanged).
AvailabilityCheck.Disable();
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::OnSessionChanged()
{
bIsAvailable = false;
if (FInsightsManager::Get()->GetSession().IsValid())
{
AvailabilityCheck.Enable(0.5);
}
else
{
AvailabilityCheck.Disable();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FContextSwitchesProfilerManager::RegisterTimingProfilerLayoutExtensions(FInsightsMajorTabExtender& InOutExtender)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace UE::Insights::ContextSwitches