2020-10-27 09:55:35 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "CallstacksProvider.h"
|
|
|
|
|
#include "Misc/ScopeRWLock.h"
|
2021-01-06 05:44:12 -04:00
|
|
|
#include "ModuleProvider.h"
|
2020-10-27 09:55:35 -04:00
|
|
|
#include "TraceServices/Model/AnalysisSession.h"
|
|
|
|
|
#include "Algo/Unique.h"
|
Numerous non-unity fixes
#rb none
#fyi Matt.Kuhlenschmidt, jeanmichel.dignard, Mike.Zyracki, Helge.Mathee, Brett.Miller, Simon.Tovey, Alexis.Matte, Steve.Smith, Sergio.Gardeazabal, Patrick.Boutot, Martin.Ridgers, Brooke.Hubert, Patrick.Enfedaque, Roey.Borsteinas, JeanFrancois.Dube, Jose.Villaroel, John.Hable, Danny.Couture, Zach.Bethel
[CL 14786858 by Jurre deBaare in ue5-main branch]
2020-11-19 11:19:38 -04:00
|
|
|
#include "Containers/ArrayView.h"
|
|
|
|
|
#include "UObject/NameTypes.h"
|
2020-10-27 09:55:35 -04:00
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
namespace TraceServices
|
|
|
|
|
{
|
2020-10-27 09:55:35 -04:00
|
|
|
|
2021-02-15 10:31:58 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2021-04-15 09:39:46 -04:00
|
|
|
static const FResolvedSymbol GNeverResolveSymbol(ESymbolQueryResult::NotLoaded, nullptr, nullptr, nullptr, 0);
|
2021-06-07 08:18:57 -04:00
|
|
|
static const FResolvedSymbol GNotFoundSymbol(ESymbolQueryResult::NotFound, TEXT("Unknown"), nullptr, nullptr, 0);
|
2022-01-13 10:13:55 -05:00
|
|
|
static const FResolvedSymbol GNoSymbol(ESymbolQueryResult::NotFound, TEXT("No callstack recorded"), nullptr, nullptr, 0);
|
2022-02-07 11:28:45 -05:00
|
|
|
static constexpr FStackFrame GNotFoundStackFrame = { 0, &GNotFoundSymbol };
|
|
|
|
|
static constexpr FStackFrame GNoStackFrame = { 0, &GNoSymbol };
|
2021-06-07 08:18:57 -04:00
|
|
|
static const FCallstack GNotFoundCallstack(&GNotFoundStackFrame, 1);
|
2021-02-15 10:31:58 -04:00
|
|
|
|
2020-10-27 09:55:35 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
#ifdef TRACE_CALLSTACK_STATS
|
|
|
|
|
static struct FCallstackProviderStats
|
|
|
|
|
{
|
|
|
|
|
uint64 Callstacks;
|
|
|
|
|
uint64 Frames;
|
|
|
|
|
uint64 FrameCountHistogram[256];
|
|
|
|
|
} GCallstackStats;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
2021-01-06 05:44:12 -04:00
|
|
|
FCallstacksProvider::FCallstacksProvider(IAnalysisSession& InSession)
|
|
|
|
|
: Session(InSession)
|
|
|
|
|
, ModuleProvider(nullptr)
|
|
|
|
|
, Callstacks(InSession.GetLinearAllocator(), CallstacksPerPage)
|
|
|
|
|
, Frames(InSession.GetLinearAllocator(), FramesPerPage)
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
// Let the first callstack to be an empty/undefined callstack.
|
|
|
|
|
FCallstack& FirstCallstack = Callstacks.PushBack();
|
|
|
|
|
FirstCallstack.Init(&GNoStackFrame, 1);
|
2020-10-27 09:55:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
2022-02-07 11:28:45 -05:00
|
|
|
void FCallstacksProvider::AddCallstack(uint32 InCallstackId, const uint64* InFrames, uint8 InFrameCount)
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
if (InCallstackId == 0)
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE_CALLSTACK_STATS
|
|
|
|
|
GCallstackStats.Callstacks++;
|
|
|
|
|
GCallstackStats.Frames += InFrameCount;
|
|
|
|
|
GCallstackStats.FrameCountHistogram[InFrameCount]++;
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-02-07 11:28:45 -05:00
|
|
|
// The module provider is created on the fly so we want to cache it
|
2021-03-31 06:10:22 -04:00
|
|
|
// once it's available. Note that the module provider is conditionally
|
|
|
|
|
// created so EditProvider() may return a null pointer.
|
2021-01-06 05:44:12 -04:00
|
|
|
if (!ModuleProvider)
|
|
|
|
|
{
|
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
[CL 16967698 by ionut matasaru in ue5-main branch]
2021-07-27 08:18:31 -04:00
|
|
|
ModuleProvider = Session.EditProvider<IModuleProvider>(GetModuleProviderName());
|
2021-01-06 05:44:12 -04:00
|
|
|
}
|
|
|
|
|
|
2022-02-07 11:28:45 -05:00
|
|
|
if (InFrameCount > 0)
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
// Make sure all the frames fit on one page by appending dummy entries.
|
|
|
|
|
const uint64 PageHeadroom = Frames.GetPageSize() - (Frames.Num() % Frames.GetPageSize());
|
|
|
|
|
if (PageHeadroom < InFrameCount)
|
|
|
|
|
{
|
|
|
|
|
FRWScopeLock WriteLock(EntriesLock, SLT_Write);
|
|
|
|
|
uint64 EntriesToAdd = PageHeadroom + 1; // Fill page and allocate one on next
|
|
|
|
|
do { Frames.PushBack(); } while (--EntriesToAdd);
|
|
|
|
|
}
|
2020-10-27 09:55:35 -04:00
|
|
|
}
|
|
|
|
|
|
2022-02-07 11:28:45 -05:00
|
|
|
// Append the incoming frames.
|
2020-10-27 09:55:35 -04:00
|
|
|
const uint64 FirstFrame = Frames.Num();
|
|
|
|
|
for (uint32 FrameIdx = 0; FrameIdx < InFrameCount; ++FrameIdx)
|
|
|
|
|
{
|
|
|
|
|
FStackFrame& F = Frames.PushBack();
|
|
|
|
|
F.Addr = InFrames[FrameIdx];
|
2022-02-07 11:28:45 -05:00
|
|
|
|
2021-02-15 10:31:58 -04:00
|
|
|
if (ModuleProvider)
|
|
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
// This will return immediately. The result will be empty if the symbol
|
2021-02-15 10:31:58 -04:00
|
|
|
// has not been encountered before, and resolution has been queued up.
|
|
|
|
|
F.Symbol = ModuleProvider->GetSymbol(InFrames[FrameIdx]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
F.Symbol = &GNeverResolveSymbol;
|
|
|
|
|
}
|
2020-10-27 09:55:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FRWScopeLock WriteLock(EntriesLock, SLT_Write);
|
2022-02-07 11:28:45 -05:00
|
|
|
FCallstack* Callstack = nullptr;
|
|
|
|
|
if (InCallstackId < Callstacks.Num())
|
|
|
|
|
{
|
|
|
|
|
Callstack = &Callstacks[InCallstackId];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (InCallstackId >= Callstacks.Num())
|
|
|
|
|
{
|
|
|
|
|
Callstack = &Callstacks.PushBack();
|
2022-03-15 12:14:28 -04:00
|
|
|
Callstack->Init(&GNoStackFrame, 1);
|
2022-02-07 11:28:45 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-03-15 12:14:28 -04:00
|
|
|
check(Callstack && (Callstack->Num() == 0 || Callstack->Frame(0) == &GNoStackFrame)); // adding same callstack id twice?
|
2022-02-07 11:28:45 -05:00
|
|
|
Callstack->Init(&Frames[FirstFrame], InFrameCount);
|
2020-10-27 09:55:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 12:23:24 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2022-02-07 11:28:45 -05:00
|
|
|
uint32 FCallstacksProvider::AddCallstackWithHash(uint64 InCallstackHash, const uint64* InFrames, uint8 InFrameCount)
|
2021-09-22 12:23:24 -04:00
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
if (InCallstackHash == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 CallstackId;
|
|
|
|
|
{
|
|
|
|
|
FRWScopeLock WriteLock(EntriesLock, SLT_Write);
|
|
|
|
|
CallstackId = Callstacks.Num();
|
|
|
|
|
CallstackMap.Add(InCallstackHash, CallstackId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddCallstack(CallstackId, InFrames, InFrameCount);
|
|
|
|
|
return CallstackId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
uint32 FCallstacksProvider::GetCallstackIdForHash(uint64 InCallstackHash) const
|
|
|
|
|
{
|
|
|
|
|
if (InCallstackHash == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
FRWScopeLock ReadLock(EntriesLock, SLT_ReadOnly);
|
|
|
|
|
const uint32* CallstackIdPtr = CallstackMap.Find(InCallstackHash);
|
|
|
|
|
if (CallstackIdPtr)
|
|
|
|
|
{
|
|
|
|
|
return *CallstackIdPtr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-09-22 12:23:24 -04:00
|
|
|
}
|
|
|
|
|
|
2020-10-27 09:55:35 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
2022-02-08 05:54:58 -05:00
|
|
|
const FCallstack* FCallstacksProvider::GetCallstack(uint32 CallstackId) const
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
|
|
|
|
FRWScopeLock ReadLock(EntriesLock, SLT_ReadOnly);
|
2022-02-07 11:28:45 -05:00
|
|
|
if (CallstackId < Callstacks.Num())
|
2022-01-13 10:13:55 -05:00
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
return &Callstacks[CallstackId];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return &GNotFoundCallstack;
|
2022-01-13 10:13:55 -05:00
|
|
|
}
|
2020-10-27 09:55:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
2022-02-08 05:54:58 -05:00
|
|
|
void FCallstacksProvider::GetCallstacks(const TArrayView<uint32>& CallstackIds, FCallstack const** OutCallstacks) const
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
|
|
|
|
uint64 OutIdx(0);
|
|
|
|
|
check(OutCallstacks != nullptr);
|
|
|
|
|
|
|
|
|
|
FRWScopeLock ReadLock(EntriesLock, SLT_ReadOnly);
|
|
|
|
|
for (uint64 CallstackId : CallstackIds)
|
|
|
|
|
{
|
2022-02-07 11:28:45 -05:00
|
|
|
if (CallstackId < Callstacks.Num())
|
|
|
|
|
{
|
|
|
|
|
OutCallstacks[OutIdx] = &Callstacks[CallstackId];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OutCallstacks[OutIdx] = &GNotFoundCallstack;
|
|
|
|
|
}
|
2020-10-27 09:55:35 -04:00
|
|
|
OutIdx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
[CL 16967698 by ionut matasaru in ue5-main branch]
2021-07-27 08:18:31 -04:00
|
|
|
FName GetCallstacksProviderName()
|
2020-10-27 09:55:35 -04:00
|
|
|
{
|
|
|
|
|
static FName Name(TEXT("CallstacksProvider"));
|
|
|
|
|
return Name;
|
|
|
|
|
}
|
|
|
|
|
|
[Insights]
- TraceServices: Changed ReadNetProfilerProvider, ReadMemoryProvider, ReadDiagnosticsProvider to return a pointer to the respective provider (instead of a reference). Can return nullptr. The UI should not assume the provider exists.
- TraceServices: Added GetNetProfilerProviderName, GetMemoryProviderName, GetDiagnosticsProviderName, GetAllocationsProviderName to return name of respective provider.
- TraceServices: Added ReadModuleProvider + GetModuleProviderName, ReadCallstacksProvider + GetCallstacksProviderName to access respective providers.
- TraceServices: Added a default empty implementation to IModule for GenerateReports, GetLoggers and GetCommandLineArgument.
- TraceServices: Changed FAnalysisService::StartAnalysis to not create default providers for Memory (LLM Stats), NetProfiler and Diagnostics, but to allow the respective modules (FMemoryModule, FNetProfilerModule, FDiagnosticsModule) to create the providers.
- TraceInsights: Fixed UI code to check if the Memory, NetProfiler and Diagnostics provider are available.
#rb Catalin.Dragoiu, Johan.Berg
[CL 16967698 by ionut matasaru in ue5-main branch]
2021-07-27 08:18:31 -04:00
|
|
|
const ICallstacksProvider* ReadCallstacksProvider(const IAnalysisSession& Session)
|
|
|
|
|
{
|
|
|
|
|
return Session.ReadProvider<ICallstacksProvider>(GetCallstacksProviderName());
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
} // namespace TraceServices
|