/** * Captures the current stack and updates stack tracking information. * optionally stores a user data pointer that the tracker will take ownership of and delete upon reset * you must allocate the memory with FMemory::Malloc() */ void FStackTracker::CaptureStackTrace(int32 EntriesToIgnore /*=2*/, void* UserData /*=NULL*/) { // Avoid re-rentrancy as the code uses TArray/TMap. if( !bAvoidCapturing && bIsEnabled ) { // Scoped true/ false. bAvoidCapturing = true; // Capture callstack and create CRC. uint64* FullBackTrace = NULL; FullBackTrace = static_cast<uint64*>(FMemory_Alloca((MAX_BACKTRACE_DEPTH + EntriesToIgnore) * sizeof(uint64))); FPlatformStackWalk::CaptureStackBackTrace( FullBackTrace, MAX_BACKTRACE_DEPTH + EntriesToIgnore ); CA_ASSUME(FullBackTrace); // Skip first NUM_ENTRIES_TO_SKIP entries as they are inside this code uint64* BackTrace = &FullBackTrace[EntriesToIgnore]; uint32 CRC = FCrc::MemCrc_DEPRECATED( BackTrace, MAX_BACKTRACE_DEPTH * sizeof(uint64) ); // Use index if found int32* IndexPtr = CRCToCallStackIndexMap.Find( CRC ); if( IndexPtr ) { // Increase stack count for existing callstack. CallStacks[*IndexPtr].StackCount++; if (UpdateFn) { UpdateFn(CallStacks[*IndexPtr], UserData); } //We can delete this since the user gives ownership at the beginning of this call //and had a chance to update their data inside the above callback if (UserData) { FMemory::Free(UserData); } } // Encountered new call stack, add to array and set index mapping. else { // Add to array and set mapping for future use. int32 Index = CallStacks.AddUninitialized(); CRCToCallStackIndexMap.Add( CRC, Index ); // Fill in callstack and count. FCallStack& CallStack = CallStacks[Index]; FMemory::Memcpy( CallStack.Addresses, BackTrace, sizeof(uint64) * MAX_BACKTRACE_DEPTH ); CallStack.StackCount = 1; CallStack.UserData = UserData; } // We're done capturing. bAvoidCapturing = false; } }
/** * Captures the current stack and updates stack tracking information. * optionally stores a user data pointer that the tracker will take ownership of and delete upon reset * you must allocate the memory with appMalloc() */ void FStackTracker::CaptureStackTrace(INT EntriesToIgnore /*=2*/, void* UserData /*=NULL*/) { // Avoid re-rentrancy as the code uses TArray/TMap. if( !bAvoidCapturing && bIsEnabled ) { // Scoped TRUE/ FALSE. bAvoidCapturing = TRUE; // Capture callstack and create CRC. QWORD* FullBackTrace = NULL; FullBackTrace = static_cast<QWORD*>(appAlloca((MAX_BACKTRACE_DEPTH + EntriesToIgnore) * sizeof(QWORD))); appCaptureStackBackTrace( FullBackTrace, MAX_BACKTRACE_DEPTH + EntriesToIgnore ); // Skip first NUM_ENTRIES_TO_SKIP entries as they are inside this code QWORD* BackTrace = &FullBackTrace[EntriesToIgnore]; DWORD CRC = appMemCrc( BackTrace, MAX_BACKTRACE_DEPTH * sizeof(QWORD), 0 ); // Use index if found INT* IndexPtr = CRCToCallStackIndexMap.Find( CRC ); if( IndexPtr ) { // Increase stack count for existing callstack. CallStacks(*IndexPtr).StackCount++; if (UpdateFn) { UpdateFn(CallStacks(*IndexPtr), UserData); } //We can delete this since the user gives ownership at the beginning of this call //and had a chance to update their data inside the above callback if (UserData) { appFree(UserData); } } // Encountered new call stack, add to array and set index mapping. else { // Add to array and set mapping for future use. INT Index = CallStacks.Add(); CRCToCallStackIndexMap.Set( CRC, Index ); // Fill in callstack and count. FCallStack& CallStack = CallStacks(Index); appMemcpy( CallStack.Addresses, BackTrace, sizeof(QWORD) * MAX_BACKTRACE_DEPTH ); CallStack.StackCount = 1; CallStack.UserData = UserData; } // We're done capturing. bAvoidCapturing = FALSE; } }
/** * Captures the current stack and updates stack tracking information. * optionally stores a user data pointer that the tracker will take ownership of and delete upon reset * you must allocate the memory with FMemory::Malloc() */ void FStackTracker::CaptureStackTrace(int32 EntriesToIgnore, void* UserData, int32 StackLen, bool bLookupStringsForAliasRemoval) { // Avoid re-rentrancy as the code uses TArray/TMap. if( !bAvoidCapturing && bIsEnabled ) { // Scoped true/ false. bAvoidCapturing = true; // Capture callstack and create CRC. int32 Size = (MAX_BACKTRACE_DEPTH + EntriesToIgnore) * sizeof(uint64); uint64* FullBackTrace = static_cast<uint64*>(FMemory_Alloca(Size)); FMemory::Memzero(FullBackTrace, Size); FPlatformStackWalk::CaptureStackBackTrace( FullBackTrace, MAX_BACKTRACE_DEPTH + EntriesToIgnore ); CA_ASSUME(FullBackTrace); // Skip first NUM_ENTRIES_TO_SKIP entries as they are inside this code uint64* BackTrace = &FullBackTrace[EntriesToIgnore]; if (StackLen < MAX_BACKTRACE_DEPTH) { FMemory::Memzero(BackTrace + StackLen, sizeof(uint64) * (MAX_BACKTRACE_DEPTH - StackLen)); } if (bLookupStringsForAliasRemoval) { for (int32 Index = 0; Index < StackLen; Index++) { if (BackTrace[Index]) { uint64* Existing = AliasMap.Find(BackTrace[Index]); if (Existing) { BackTrace[Index] = *Existing; } else { ANSICHAR AddressInformation[512]; AddressInformation[0] = 0; FPlatformStackWalk::ProgramCounterToHumanReadableString( 1, BackTrace[Index], AddressInformation, ARRAY_COUNT(AddressInformation)-1 ); FString Symbol(AddressInformation); int32 Spot = Symbol.Find(TEXT(" - ")); if (Spot != INDEX_NONE) { Symbol = Symbol.RightChop(Spot + 3); } Existing = StringAliasMap.Find(Symbol); if (Existing) { AliasMap.Add(BackTrace[Index], *Existing); BackTrace[Index] = *Existing; } else { AliasMap.Add(BackTrace[Index], BackTrace[Index]); StringAliasMap.Add(Symbol, BackTrace[Index]); } } } } } uint32 CRC = FCrc::MemCrc_DEPRECATED( BackTrace, MAX_BACKTRACE_DEPTH * sizeof(uint64) ); // Use index if found int32* IndexPtr = CRCToCallStackIndexMap.Find( CRC ); if( IndexPtr ) { // Increase stack count for existing callstack. CallStacks[*IndexPtr].StackCount++; if (UpdateFn) { UpdateFn(CallStacks[*IndexPtr], UserData); } //We can delete this since the user gives ownership at the beginning of this call //and had a chance to update their data inside the above callback if (UserData) { FMemory::Free(UserData); } } // Encountered new call stack, add to array and set index mapping. else { // Add to array and set mapping for future use. int32 Index = CallStacks.AddUninitialized(); CRCToCallStackIndexMap.Add( CRC, Index ); // Fill in callstack and count. FCallStack& CallStack = CallStacks[Index]; FMemory::Memcpy( CallStack.Addresses, BackTrace, sizeof(uint64) * MAX_BACKTRACE_DEPTH ); CallStack.StackCount = 1; CallStack.UserData = UserData; } // We're done capturing. bAvoidCapturing = false; } }