void FObjectMemoryAnalyzer::PrintResults(FOutputDevice& Ar, uint32 PrintFlags)
{
	TArray<FObjectMemoryUsage> Results;
	GetResults(Results);

	Results.Sort(FCompareFSortBySize(ESortKey::InclusiveTotal));

	Ar.Logf( TEXT("%-100s %-10s %-10s %-10s %-10s"), TEXT("Object"), TEXT("InclBytes"), TEXT("ExclBytes"), TEXT("InclResKBytes"), TEXT("ExclResKBytes") );
	
	for( int32 i=0; i < Results.Num(); ++i )
	{
		const FObjectMemoryUsage& Annotation = Results[i];

		if (Annotation.IsRoot() || (Annotation.RootReferencer.Num() == 0 && Annotation.NonRootReferencer.Num() == 0) )
		{
			Ar.Logf( TEXT("%-100s %-10d %-10d %-10d %-10d"), *FString::Printf(TEXT("%s %s"), *Annotation.Object->GetClass()->GetName(), *Annotation.Object->GetName()), 
					 (int32)Annotation.InclusiveMemoryUsage, (int32)Annotation.ExclusiveMemoryUsage, 
					 (int32)(Annotation.InclusiveResourceSize/1024), (int32)(Annotation.ExclusiveResourceSize/1024) );


			if (!!(PrintFlags&EPrintFlags::PrintReferences))
			{
				PrintSubObjects(Ar, TEXT(" -> "), Annotation.Object, PrintFlags);
			}
		}
	}
}
示例#2
0
void ConsoleCommandLibrary_DumpLibrary(UWorld* InWorld, FExec& SubSystem, const FString& Pattern, FOutputDevice& Ar)
{
	ConsoleCommandLibrary LocalConsoleCommandLibrary(Pattern);

	FOutputDeviceNull Null;

	bool bExecuted = SubSystem.Exec( InWorld, *Pattern, Null);

	{
		IConsoleManager::Get().ForEachConsoleObjectThatStartsWith(
			FConsoleObjectVisitor::CreateStatic< TSet<FString>& >(
			&FConsoleVariableDumpVisitor::OnConsoleVariable,
			LocalConsoleCommandLibrary.KnownNames ) );
	}

	LocalConsoleCommandLibrary.KnownNames.Sort( TLess<FString>() );

	for(TSet<FString>::TConstIterator It(LocalConsoleCommandLibrary.KnownNames); It; ++It)
	{
		const FString Name = *It;

		Ar.Logf(TEXT("%s"), *Name);
	}
	Ar.Logf(TEXT(""));

	// the pattern (e.g. Motion*) should not really trigger the execution
	if(bExecuted)
	{
		Ar.Logf(TEXT("ERROR: The function was supposed to only find matching commands but not have any side effect."));
		Ar.Logf(TEXT("However Exec() returned true which means we either executed a command or the command parsing returned true where it shouldn't."));
	}
}
void UExporter::ExportComponentDefinitions(const FExportObjectInnerContext* Context, const TArray<UObject*>& Components, FOutputDevice& Ar, uint32 PortFlags)
{
	PortFlags |= PPF_ExportsNotFullyQualified;

	if (!(PortFlags & PPF_SeparateDefine))
	{
		// export forward declarations
		// technically we only need to do this if there are circular references but it doesn't seem worth it
		// to complicate this code for a minor speed improvement in the text import path
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				if (Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject))
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s%s"), FCString::Spc(TextIndent), *Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), LINE_TERMINATOR);
				}
				else
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s Archetype=%s'%s'%s"),FCString::Spc(TextIndent),*Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), *Component->GetArchetype()->GetClass()->GetName(), *Component->GetArchetype()->GetPathName(), LINE_TERMINATOR);
				}
				if (PortFlags & PPF_SeparateDeclare)
				{
					ExportObjectInner(Context, Component, Ar, PortFlags, false);
				}
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
			}
		}
	}

	if (!(PortFlags & PPF_SeparateDeclare))
	{
		// export property definitions
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				Ar.Logf(TEXT("%sBegin Object Name=%s%s"), FCString::Spc(TextIndent), *ComponentName.ToString(), LINE_TERMINATOR);

				uint32 OldPortFlags = PortFlags;

				if (!(Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject)))
				{
					// we created this thing with an archetype (see archetype=, above), so we don't want to list the archetype because it is unqualified and will clash, resetting the archetype pointer to something silly
					PortFlags |= PPF_NoInternalArcheType;
				}
				ExportObjectInner(Context, Component, Ar, PortFlags, false);

				PortFlags = OldPortFlags;
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);

				Component->Mark(OBJECTMARK_TagImp);
			}
		}
	}
}
/**
 * Dump allocation information.
 */
void FBestFitAllocator::DumpAllocs( FOutputDevice& Ar/*=*GLog*/ )
{		
	// Memory usage stats.
	INT				UsedSize		= 0;
	INT				FreeSize		= 0;
	INT				NumUsedChunks	= 0;
	INT				NumFreeChunks	= 0;
	
	// Fragmentation and allocation size visualization.
	INT				NumBlocks		= MemorySize / AllocationAlignment;
	INT				Dimension		= 1 + NumBlocks / appTrunc(appSqrt(NumBlocks));			
	TArray<FColor>	AllocationVisualization;
	AllocationVisualization.AddZeroed( Dimension * Dimension );
	INT				VisIndex		= 0;

	// Traverse linked list and gather allocation information.
	FMemoryChunk*	CurrentChunk	= FirstChunk;	
	while( CurrentChunk )
	{
		FColor VisColor;
		// Free chunk.
		if( CurrentChunk->bIsAvailable )
		{
			NumFreeChunks++;
			FreeSize += CurrentChunk->Size;
			VisColor = FColor(0,255,0);
		}
		// Allocated chunk.
		else
		{
			NumUsedChunks++;
			UsedSize += CurrentChunk->Size;
			
			// Slightly alternate coloration to also visualize allocation sizes.
			if( NumUsedChunks % 2 == 0 )
			{
				VisColor = FColor(255,0,0);
			}
			else
			{
				VisColor = FColor(192,0,0);
			}
		}

		for( INT i=0; i<(CurrentChunk->Size/AllocationAlignment); i++ )
		{
			AllocationVisualization(VisIndex++) = VisColor;
		}

		CurrentChunk = CurrentChunk->NextChunk;
	}

	check(UsedSize == AllocatedMemorySize);
	check(FreeSize == AvailableMemorySize);

	// Write out bitmap for visualization of fragmentation and allocation patterns.
	appCreateBitmap( TEXT("..\\..\\Binaries\\TextureMemory"), Dimension, Dimension, AllocationVisualization.GetTypedData() );
	Ar.Logf( TEXT("BestFitAllocator: Allocated %i KByte in %i chunks, leaving %i KByte in %i chunks."), UsedSize / 1024, NumUsedChunks, FreeSize / 1024, NumFreeChunks );
	Ar.Logf( TEXT("BestFitAllocator: %5.2f ms in allocator"), TimeSpentInAllocator * 1000 );
}
示例#5
0
/**
* Dumps capture stack trace summary to the passed in log.
*/
void FScriptStackTracker::DumpStackTraces( int32 StackThreshold, FOutputDevice& Ar )
{
	// Avoid distorting results while we log them.
	check( !bAvoidCapturing );
	bAvoidCapturing = true;

	// Make a copy as sorting causes index mismatch with TMap otherwise.
	TArray<FCallStack> SortedCallStacks = CallStacks;
	// Compare function, sorting callstack by stack count in descending order.
	struct FCompareStackCount
	{
		FORCEINLINE bool operator()( const FCallStack& A, const FCallStack& B ) const { return B.StackCount < A.StackCount; }
	};
	// Sort callstacks in descending order by stack count.
	SortedCallStacks.Sort( FCompareStackCount() );

	// Iterate over each callstack to get total stack count.
	uint64 TotalStackCount = 0;
	for( int32 CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks[CallStackIndex];
		TotalStackCount += CallStack.StackCount;
	}

	// Calculate the number of frames we captured.
	int32 FramesCaptured = 0;
	if( bIsEnabled )
	{
		FramesCaptured = GFrameCounter - StartFrameCounter;
	}
	else
	{
		FramesCaptured = StopFrameCounter - StartFrameCounter;
	}

	// Log quick summary as we don't log each individual so totals in CSV won't represent real totals.
	Ar.Logf(TEXT("Captured %i unique callstacks totalling %i function calls over %i frames, averaging %5.2f calls/frame"), SortedCallStacks.Num(), (int32)TotalStackCount, FramesCaptured, (float) TotalStackCount / FramesCaptured);

	// Iterate over each callstack and write out info in human readable form in CSV format
	for( int32 CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks[CallStackIndex];

		// Avoid log spam by only logging above threshold.
		if( CallStack.StackCount > StackThreshold )
		{
			// First row is stack count.
			FString CallStackString = FString::FromInt((int32)CallStack.StackCount);
			CallStackString += LINE_TERMINATOR;
			CallStackString += CallStack.StackTrace;

			// Finally log with ',' prefix so "Log:" can easily be discarded as row in Excel.
			Ar.Logf(TEXT(",%s"),*CallStackString);
		}
	}

	// Done logging.
	bAvoidCapturing = false;
}
示例#6
0
void UExporter::EmitEndObject( FOutputDevice& Ar )
{
    if ( bEnableDebugBrackets )
    {
        Ar.Logf(TEXT("%s}%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
    }
    Ar.Logf( TEXT("%sEnd Object\r\n"), FCString::Spc(TextIndent) );
}
void UK2Node_EditablePinBase::ExportCustomProperties(FOutputDevice& Out, uint32 Indent)
{
	for (int32 PinIndex = 0; PinIndex < UserDefinedPins.Num(); ++PinIndex)
	{
		const FUserPinInfo& PinInfo = *UserDefinedPins[PinIndex].Get();

		Out.Logf( TEXT("%sCustomProperties UserDefinedPin "), FCString::Spc(Indent));
		Out.Logf( TEXT("Name=%s "), *PinInfo.PinName);
		Out.Logf( TEXT("IsArray=%s "), (PinInfo.PinType.bIsArray ? TEXT("1") : TEXT("0")));
		Out.Logf( TEXT("IsReference=%s "), (PinInfo.PinType.bIsReference ? TEXT("1") : TEXT("0")));
		
		if (PinInfo.PinType.PinCategory.Len() > 0)
		{
			Out.Logf( TEXT("Category=%s "), *PinInfo.PinType.PinCategory);
		}

		if (PinInfo.PinType.PinSubCategory.Len() > 0)
		{
			Out.Logf( TEXT("SubCategory=%s "), *PinInfo.PinType.PinSubCategory);
		}

		if (PinInfo.PinType.PinSubCategoryObject.IsValid())
		{
			Out.Logf( TEXT("SubCategoryObject=%s "), *PinInfo.PinType.PinSubCategoryObject.Get()->GetPathName());
		}

		if (PinInfo.PinDefaultValue.Len() > 0)
		{
			Out.Logf( TEXT("DefaultValue=%s "), *PinInfo.PinDefaultValue);
		}

		Out.Logf( TEXT("\r\n"));
	}
}
void FHttpManager::DumpRequests(FOutputDevice& Ar) const
{
	FScopeLock ScopeLock(&RequestLock);
	
	Ar.Logf(TEXT("------- (%d) Http Requests"), Requests.Num());
	for (const TSharedRef<IHttpRequest>& Request : Requests)
	{
		Ar.Logf(TEXT("	verb=[%s] url=[%s] status=%s"),
			*Request->GetVerb(), *Request->GetURL(), EHttpRequestStatus::ToString(Request->GetStatus()));
	}
}
/**
 * Outputs the contents of the ObjectMap to the specified output device.
 */
void FTransaction::DumpObjectMap(FOutputDevice& Ar) const
{
	Ar.Logf( TEXT("===== DumpObjectMap %s ==== "), *Title.ToString() );
	for ( ObjectMapType::TConstIterator It(ObjectMap) ; It ; ++It )
	{
		const UObject* CurrentObject	= It.Key();
		const int32 SaveCount				= It.Value();
		Ar.Logf( TEXT("%i\t: %s"), SaveCount, *CurrentObject->GetPathName() );
	}
	Ar.Logf( TEXT("=== EndDumpObjectMap %s === "), *Title.ToString() );
}
示例#10
0
/**
* Dumps capture stack trace summary to the passed in log.
*/
void FScriptStackTracker::DumpStackTraces( INT StackThreshold, FOutputDevice& Ar )
{
	// Avoid distorting results while we log them.
	check( !bAvoidCapturing );
	bAvoidCapturing = TRUE;

	// Make a copy as sorting causes index mismatch with TMap otherwise.
	TArray<FCallStack> SortedCallStacks = CallStacks;
	// Sort callstacks in descending order by stack count.
	Sort<USE_COMPARE_CONSTREF(FCallStack,StackTracker)>( SortedCallStacks.GetTypedData(), SortedCallStacks.Num() );

	// Iterate over each callstack to get total stack count.
	QWORD TotalStackCount = 0;
	for( INT CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks(CallStackIndex);
		TotalStackCount += CallStack.StackCount;
	}

	// Calculate the number of frames we captured.
	INT FramesCaptured = 0;
	if( bIsEnabled )
	{
		FramesCaptured = GFrameCounter - StartFrameCounter;
	}
	else
	{
		FramesCaptured = StopFrameCounter - StartFrameCounter;
	}

	// Log quick summary as we don't log each individual so totals in CSV won't represent real totals.
	Ar.Logf(TEXT("Captured %i unique callstacks totalling %i function calls over %i frames, averaging %5.2f calls/frame"), SortedCallStacks.Num(), (int)TotalStackCount, FramesCaptured, (FLOAT) TotalStackCount / FramesCaptured);

	// Iterate over each callstack and write out info in human readable form in CSV format
	for( INT CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks(CallStackIndex);

		// Avoid log spam by only logging above threshold.
		if( CallStack.StackCount > StackThreshold )
		{
			// First row is stack count.
			FString CallStackString = appItoa(CallStack.StackCount);
			CallStackString += LINE_TERMINATOR;
			CallStackString += CallStack.StackTrace;

			// Finally log with ',' prefix so "Log:" can easily be discarded as row in Excel.
			Ar.Logf(TEXT(",%s"),*CallStackString);
		}
	}

	// Done logging.
	bAvoidCapturing = FALSE;
}
示例#11
0
bool UIpNetDriver::HandleSocketsCommand( const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld )
{
	Ar.Logf(TEXT(""));
	if (Socket != NULL)
	{
		TSharedRef<FInternetAddr> LocalAddr = GetSocketSubsystem()->CreateInternetAddr();
		Socket->GetAddress(*LocalAddr);
		Ar.Logf(TEXT("%s Socket: %s"), *GetDescription(), *LocalAddr->ToString(true));
	}		
	else
	{
		Ar.Logf(TEXT("%s Socket: null"), *GetDescription());
	}
	return UNetDriver::Exec( InWorld, TEXT("SOCKETS"),Ar);
}
示例#12
0
bool FOSVRHMD::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
{
    if (FParse::Command(&Cmd, TEXT("STEREO")))
    {
        if (FParse::Command(&Cmd, TEXT("ON")))
        {
            if (!IsHMDEnabled())
            {
                Ar.Logf(TEXT("HMD is disabled. Use 'hmd enable' to re-enable it."));
            }
            EnableStereo(true);
            return true;
        }
        else if (FParse::Command(&Cmd, TEXT("OFF")))
        {
            EnableStereo(false);
            return true;
        }
    }
    else if (FParse::Command(&Cmd, TEXT("HMD")))
    {
        if (FParse::Command(&Cmd, TEXT("ENABLE")))
        {
            EnableHMD(true);
            return true;
        }
        else if (FParse::Command(&Cmd, TEXT("DISABLE")))
        {
            EnableHMD(false);
            return true;
        }
    }
    else if (FParse::Command(&Cmd, TEXT("UNCAPFPS")))
    {
        GEngine->bSmoothFrameRate = false;
        return true;
    }
    else if (FParse::Command(&Cmd, TEXT("HEADTRACKING")))
    {
        FString val;
        if (FParse::Value(Cmd, TEXT("SOURCE="), val))
        {
            EnablePositionalTracking(false);
            //OSVRInterfaceName = val;
            EnablePositionalTracking(true);
        }
        if (FParse::Command(&Cmd, TEXT("ENABLE")))
        {
            EnablePositionalTracking(true);
            return true;
        }
        else if (FParse::Command(&Cmd, TEXT("DISABLE")))
        {
            EnablePositionalTracking(false);
            return true;
        }
    }

    return false;
}
示例#13
0
/**
 * Exec handler implementation.
 *
 * @param InWorld World context
 * @param Cmd	Command to parse
 * @param Ar	Output device to log to
 *
 * @return true if command was handled, false otherwise
 */
bool FSystemSettings::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
{
	FSystemSettingsData OldSystemSettings = *this;

	// Keep track whether the command was handled or not.
	bool bHandledCommand = false;

	if( FParse::Command(&Cmd,TEXT("SCALE")) )
	{
		// Some of these settings are used in both threads so we need to stop the rendering thread before changing them.
		FlushRenderingCommands();

		if( FParse::Command(&Cmd,TEXT("LOWEND")) )
		{
			bHandledCommand	= HandleLowendCommand( Cmd, Ar );
		}
		else if( FParse::Command(&Cmd,TEXT("HIGHEND")) )
		{
			bHandledCommand	= HandleHighendCommand( Cmd, Ar );	
		}

		if (!bHandledCommand)
		{
			Ar.Logf(TEXT("Unrecognized system setting (note that console variables can be set much easier)"));
		}
		else
		{
			// Write the new settings to the INI.
			SaveToIni();
		}
	}

	return bHandledCommand;
}
void FPakPlatformFile::HandlePakListCommand(const TCHAR* Cmd, FOutputDevice& Ar)
{
	TArray<FPakListEntry> Paks;
	GetMountedPaks(Paks);
	for (auto Pak : Paks)
	{
		Ar.Logf(TEXT("%s"), *Pak.PakFile->GetFilename());
	}	
}
示例#15
0
static void DumpRHIMemory(FOutputDevice& OutputDevice)
{
	TArray<FStatMessage> Stats;
	GetPermanentStats(Stats);

	FName NAME_STATGROUP_RHI(FStatGroup_STATGROUP_RHI::GetGroupName());
	OutputDevice.Logf(TEXT("RHI resource memory (not tracked by our allocator)"));
	int64 TotalMemory = 0;
	for (int32 Index = 0; Index < Stats.Num(); Index++)
	{
		FStatMessage const& Meta = Stats[Index];
		FName LastGroup = Meta.NameAndInfo.GetGroupName();
		if (LastGroup == NAME_STATGROUP_RHI && Meta.NameAndInfo.GetFlag(EStatMetaFlags::IsMemory))
		{
			OutputDevice.Logf(TEXT("%s"), *FStatsUtils::DebugPrint(Meta));
			TotalMemory += Meta.GetValue_int64();
		}
	}
	OutputDevice.Logf(TEXT("%.3fMB total"), TotalMemory / 1024.f / 1024.f);
}
示例#16
0
// Disassemble all functions in any classes that have matching names.
void FKismetBytecodeDisassembler::DisassembleAllFunctionsInClasses(FOutputDevice& Ar, const FString& ClassnameSubstring)
{
	FKismetBytecodeDisassembler Disasm(Ar);
		
	for (TObjectIterator<UClass> ClassIter; ClassIter; ++ClassIter)
	{
		UClass* Class = *ClassIter;

		FString ClassName = Class->GetName();
		if (FCString::Strfind(*ClassName, *ClassnameSubstring))
		{
			Ar.Logf(TEXT("Processing class %s"), *ClassName);

			for (TFieldIterator<UFunction> FunctionIter(Class, EFieldIteratorFlags::ExcludeSuper); FunctionIter; ++FunctionIter)
			{
				UFunction* Function = *FunctionIter;
				FString FunctionName = Function->GetName();
				Ar.Logf(TEXT("  Processing function %s (%d bytes)"), *FunctionName, Function->Script.Num());

				Disasm.DisassembleStructure(Function);

				Ar.Logf(TEXT(""));
			}

			Ar.Logf(TEXT(""));
			Ar.Logf(TEXT("-----------"));
			Ar.Logf(TEXT(""));
		}

	}
}
示例#17
0
void UExporter::EmitBeginObject( FOutputDevice& Ar, UObject* Obj, uint32 PortFlags )
{
    check(Obj);

    // figure out how to export
    bool bIsExportingDefaultObject = Obj->HasAnyFlags(RF_ClassDefaultObject) || Obj->GetArchetype()->HasAnyFlags(RF_ClassDefaultObject);

    // start outputting the string for the Begin Object line
    Ar.Logf(TEXT("%sBegin Object"), FCString::Spc(TextIndent));

    if (!(PortFlags & PPF_SeparateDefine))
    {
        Ar.Logf(TEXT(" Class=%s"), *Obj->GetClass()->GetName());
    }

    // always need a name, adding "" for space handling
    Ar.Logf(TEXT(" Name=\"%s\""), *Obj->GetName());

    if (!(PortFlags & PPF_SeparateDefine))
    {
        // do we want the archetype string?
        if (!bIsExportingDefaultObject)
        {
            Ar.Logf(TEXT(" Archetype=%s'%s'"), *Obj->GetArchetype()->GetClass()->GetName(), *Obj->GetArchetype()->GetPathName());
        }
    }

    // end in a return
    Ar.Logf(TEXT("\r\n"));

    if ( bEnableDebugBrackets )
    {
        Ar.Logf(TEXT("%s{%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
    }
}
void FObjectMemoryAnalyzer::PrintSubObjects(FOutputDevice& Ar, const FString& Indent, UObject* Parent, uint32 PrintFlags)
{
	TArray<UObject*> ReferencedObjects;
	GetReferencedObjects(Parent, ReferencedObjects);

	for( int32 ObjIndex = 0; ObjIndex < ReferencedObjects.Num(); ObjIndex++ )
	{
		UObject* SubObj = ReferencedObjects[ObjIndex];
		const FObjectMemoryUsage& Annotation = GetObjectMemoryUsage(SubObj);

		if (!Annotation.IsRoot())
		{
			Ar.Logf( TEXT("%-100s %-10d %-10d %-10d %-10d"), *FString::Printf(TEXT("%s%s %s"), *Indent, *SubObj->GetClass()->GetName(), *SubObj->GetName()),
					 (int32)Annotation.InclusiveMemoryUsage, (int32)Annotation.ExclusiveMemoryUsage, 
					 (int32)(Annotation.InclusiveResourceSize/1024), (int32)(Annotation.ExclusiveResourceSize/1024) );

			if (!!(PrintFlags&EPrintFlags::PrintReferencer))
			{
				for (int32 i=0; i < Annotation.NonRootReferencer.Num(); ++i)
				{
					Ar.Logf(TEXT("%s  >> NonRootRef: %s"), *Indent, *Annotation.NonRootReferencer[i]->GetName());
				}

				for (int32 i=0; i < Annotation.RootReferencer.Num(); ++i)
				{
					Ar.Logf(TEXT("%s  >> RootRef: %s"), *Indent, *Annotation.RootReferencer[i]->GetName());
				}
			}
			
			if (!!(PrintFlags&EPrintFlags::PrintReferences))
			{
				PrintSubObjects(Ar, Indent + TEXT(" -> "), SubObj, PrintFlags);
			}
		}
	}
}
示例#19
0
void FName::DisplayHash( FOutputDevice& Ar )
{
    int32 UsedBins=0, NameCount=0, MemUsed = 0;
    for( int32 i=0; i<ARRAY_COUNT(NameHash); i++ )
    {
        if( NameHash[i] != NULL ) UsedBins++;
        for( FNameEntry *Hash = NameHash[i]; Hash; Hash=Hash->HashNext )
        {
            NameCount++;
            // Count how much memory this entry is using
            MemUsed += FNameEntry::GetSize( Hash->GetNameLength(), Hash->IsWide() );
        }
    }
    Ar.Logf( TEXT("Hash: %i names, %i/%i hash bins, Mem in bytes %i"), NameCount, UsedBins, ARRAY_COUNT(NameHash), MemUsed);
}
示例#20
0
/**
 * Prints the subtitle associated with the SoundWave to the console
 */
void USoundWave::LogSubtitle( FOutputDevice& Ar )
{
	FString Subtitle = "";
	for( int32 i = 0; i < Subtitles.Num(); i++ )
	{
		Subtitle += Subtitles[ i ].Text.ToString();
	}

	if( Subtitle.Len() == 0 )
	{
		Subtitle = SpokenText;
	}

	if( Subtitle.Len() == 0 )
	{
		Subtitle = "<NO SUBTITLE>";
	}

	Ar.Logf( TEXT( "Subtitle:  %s" ), *Subtitle );
#if WITH_EDITORONLY_DATA
	Ar.Logf( TEXT( "Comment:   %s" ), *Comment );
#endif // WITH_EDITORONLY_DATA
	Ar.Logf( bMature ? TEXT( "Mature:    Yes" ) : TEXT( "Mature:    No" ) );
}
	/**
	 * Process a "[cat] only" string command to the logging suppression system
	 * @param CmdString, string to process
	 * @return true if CmdString was a "[cat] only" string command, false otherwise
	 */
	bool ProcessLogOnly(const FString& CmdString, FOutputDevice& Ar)
	{
		TArray<FString> CommandParts;
		CmdString.ParseIntoArrayWS(CommandParts);
		if (CommandParts.Num() <= 1)
		{
			return false;
		}
		
		static FName NAME_Only(TEXT("only"));
		if (NAME_Only != FName(*CommandParts[1]))
		{
			return false;
		}
		
		FName LogCategory = FName(*CommandParts[0]);
		static const FString OffString = FString(" off");
		static const FString OnString = FString(" Verbose");
		for (auto It : Associations)
		{
			FName Name = It.Value;
			if (Name == LogCategory)
			{
				ProcessCmdString(Name.ToString() + OnString);
				FLogCategoryBase* Verb = It.Key;
				Ar.Logf(TEXT("%s is now %s"), *CommandParts[0], FOutputDevice::VerbosityToString(Verb ? ELogVerbosity::Type(Verb->Verbosity) : ELogVerbosity::Verbose));
			}
			else
			{
				ProcessCmdString(Name.ToString() + OffString);
			}
		}

		Ar.Logf(TEXT("Disabling other logs finished"));
		return true;
	}
示例#22
0
bool UGameInstance::HandleOpenCommand(const TCHAR* Cmd, FOutputDevice& Ar, UWorld* InWorld)
{
	check(WorldContext && WorldContext->World() == InWorld);

	UEngine* const Engine = GetEngine();

	FURL TestURL(&WorldContext->LastURL, Cmd, TRAVEL_Absolute);
	if (TestURL.IsLocalInternal())
	{
		// make sure the file exists if we are opening a local file
		if (!Engine->MakeSureMapNameIsValid(TestURL.Map))
		{
			Ar.Logf(TEXT("ERROR: The map '%s' does not exist."), *TestURL.Map);
			return true;
		}
	}

	Engine->SetClientTravel(InWorld, Cmd, TRAVEL_Absolute);
	return true;
}
示例#23
0
/**
 * Dumps capture stack trace summary to the passed in log.
 */
void FStackTracker::DumpStackTraces( INT StackThreshold, FOutputDevice& Ar )
{
	// Avoid distorting results while we log them.
	check( !bAvoidCapturing );
	bAvoidCapturing = TRUE;

	// Make a copy as sorting causes index mismatch with TMap otherwise.
	TArray<FCallStack> SortedCallStacks = CallStacks;
	// Sort callstacks in descending order by stack count.
	Sort<USE_COMPARE_CONSTREF(FCallStack,StackTracker)>( SortedCallStacks.GetTypedData(), SortedCallStacks.Num() );

	// Iterate over each callstack to get total stack count.
	QWORD TotalStackCount = 0;
	for( INT CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks(CallStackIndex);
		TotalStackCount += CallStack.StackCount;
	}

	// Calculate the number of frames we captured.
	INT FramesCaptured = 0;
	if( bIsEnabled )
	{
		FramesCaptured = GFrameCounter - StartFrameCounter;
	}
	else
	{
		FramesCaptured = StopFrameCounter - StartFrameCounter;
	}

	// Log quick summary as we don't log each individual so totals in CSV won't represent real totals.
	Ar.Logf(TEXT("Captured %i unique callstacks totalling %i function calls over %i frames, averaging %5.2f calls/frame, Avg Per Frame"), SortedCallStacks.Num(), (int)TotalStackCount, FramesCaptured, (FLOAT) TotalStackCount / FramesCaptured);

	// Iterate over each callstack and write out info in human readable form in CSV format
	for( INT CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks(CallStackIndex);

		// Avoid log spam by only logging above threshold.
		if( CallStack.StackCount > StackThreshold )
		{
			// First row is stack count.
			FString CallStackString = appItoa(CallStack.StackCount);
			CallStackString += FString::Printf( TEXT(",%5.2f"), static_cast<FLOAT>(CallStack.StackCount)/static_cast<FLOAT>(FramesCaptured) );
			

			// Iterate over all addresses in the callstack to look up symbol name.
			for( INT AddressIndex=0; AddressIndex<ARRAY_COUNT(CallStack.Addresses) && CallStack.Addresses[AddressIndex]; AddressIndex++ )
			{
				ANSICHAR AddressInformation[512];
				AddressInformation[0] = 0;
				appProgramCounterToHumanReadableString( CallStack.Addresses[AddressIndex], AddressInformation, ARRAY_COUNT(AddressInformation)-1, VF_DISPLAY_FILENAME );
				CallStackString = CallStackString + LINE_TERMINATOR TEXT(",,,") + FString(AddressInformation);
			}

			// Finally log with ',' prefix so "Log:" can easily be discarded as row in Excel.
			Ar.Logf(TEXT(",%s"),*CallStackString);
            
			//Append any user information before moving on to the next callstack
			if (ReportFn)
			{
				ReportFn(CallStack, Ar);
			}
		}
	}

	// Done logging.
	bAvoidCapturing = FALSE;
}
示例#24
0
/**
 * Exports the property values for the specified object as text to the output device.
 *
 * @param	Context			Context from which the set of 'inner' objects is extracted.  If NULL, an object iterator will be used.
 * @param	Out				the output device to send the exported text to
 * @param	ObjectClass		the class of the object to dump properties for
 * @param	Object			the address of the object to dump properties for
 * @param	Indent			number of spaces to prepend to each line of output
 * @param	DiffClass		the class to use for comparing property values when delta export is desired.
 * @param	Diff			the address of the object to use for determining whether a property value should be exported.  If the value in Object matches the corresponding
 *							value in Diff, it is not exported.  Specify NULL to export all properties.
 * @param	Parent			the UObject corresponding to Object
 * @param	PortFlags		flags used for modifying the output and/or behavior of the export
 */
void ExportProperties
(
    const FExportObjectInnerContext* Context,
    FOutputDevice&	Out,
    UClass*			ObjectClass,
    uint8*			Object,
    int32				Indent,
    UClass*			DiffClass,
    uint8*			Diff,
    UObject*		Parent,
    uint32			PortFlags,
    UObject*		ExportRootScope
)
{
    FString ThisName = TEXT("(none)");
    check(ObjectClass != NULL);

    for( UProperty* Property = ObjectClass->PropertyLink; Property; Property = Property->PropertyLinkNext )
    {
        if (!Property->ShouldPort(PortFlags))
            continue;

        ThisName = Property->GetName();
        UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
        UObjectPropertyBase* ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(Property) : NULL;
        const uint32 ExportFlags = PortFlags | PPF_Delimited;

        if ( ArrayProperty != NULL )
        {
            // Export dynamic array.
            UProperty* InnerProp = ArrayProperty->Inner;
            ExportObjectProp = (Property->PropertyFlags & CPF_ExportObject) != 0 ? Cast<UObjectPropertyBase>(InnerProp) : NULL;
            // This is used as the default value in the case of an array property that has
            // fewer elements than the exported object.
            uint8* StructDefaults = NULL;
            UStructProperty* StructProperty = Cast<UStructProperty>(InnerProp);
            if ( StructProperty != NULL )
            {
                checkSlow(StructProperty->Struct);
                StructDefaults = (uint8*)FMemory::Malloc(StructProperty->Struct->GetStructureSize());
                StructProperty->InitializeValue(StructDefaults);
            }

            for( int32 PropertyArrayIndex=0; PropertyArrayIndex<Property->ArrayDim; PropertyArrayIndex++ )
            {
                void* Arr = Property->ContainerPtrToValuePtr<void>(Object, PropertyArrayIndex);
                FScriptArrayHelper ArrayHelper(ArrayProperty, Arr);

                void*	DiffArr = NULL;
                if( DiffClass )
                {
                    DiffArr = Property->ContainerPtrToValuePtrForDefaults<void>(DiffClass, Diff, PropertyArrayIndex);
                }
                // we won't use this if DiffArr is NULL, but we have to set it up to something
                FScriptArrayHelper DiffArrayHelper(ArrayProperty, DiffArr);

                bool bAnyElementDiffered = false;
                for( int32 DynamicArrayIndex=0; DynamicArrayIndex<ArrayHelper.Num(); DynamicArrayIndex++ )
                {
                    FString	Value;

                    // compare each element's value manually so that elements which match the NULL value for the array's inner property type
                    // but aren't in the diff array are still exported
                    uint8* SourceData = ArrayHelper.GetRawPtr(DynamicArrayIndex);
                    uint8* DiffData = DiffArr && DynamicArrayIndex < DiffArrayHelper.Num()
                                      ? DiffArrayHelper.GetRawPtr(DynamicArrayIndex)
                                      : StructDefaults;

                    bool bExportItem = DiffData == NULL || (DiffData != SourceData && !InnerProp->Identical(SourceData, DiffData, ExportFlags));
                    if ( bExportItem )
                    {
                        bAnyElementDiffered = true;
                        InnerProp->ExportTextItem(Value, SourceData, DiffData, Parent, ExportFlags, ExportRootScope);
                        if(ExportObjectProp)
                        {
                            UObject* Obj = ExportObjectProp->GetObjectPropertyValue(ArrayHelper.GetRawPtr(DynamicArrayIndex));
                            check(!Obj || Obj->IsValidLowLevel());
                            if( Obj && !Obj->HasAnyMarks(OBJECTMARK_TagImp) )
                            {
                                // only export the BEGIN OBJECT block for a component if Parent is the component's Outer....when importing subobject definitions,
                                // (i.e. BEGIN OBJECT), whichever BEGIN OBJECT block a component's BEGIN OBJECT block is located within is the object that will be
                                // used as the Outer to create the component

                                // Is this an array of components?
                                if ( InnerProp->HasAnyPropertyFlags(CPF_InstancedReference) )
                                {
                                    if ( Obj->GetOuter() == Parent )
                                    {
                                        // Don't export more than once.
                                        Obj->Mark(OBJECTMARK_TagImp);
                                        UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags );
                                    }
                                    else
                                    {
                                        // set the OBJECTMARK_TagExp flag so that the calling code knows we wanted to export this object
                                        Obj->Mark(OBJECTMARK_TagExp);
                                    }
                                }
                                else
                                {
                                    // Don't export more than once.
                                    Obj->Mark(OBJECTMARK_TagImp);
                                    UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags );
                                }
                            }
                        }

                        Out.Logf( TEXT("%s%s(%i)=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), DynamicArrayIndex, *Value );
                    }
                    // if some other element has already been determined to differ from the defaults, then export this item with no data so that
                    // the different array's size is maintained on import (this item will get the default values for that index, if any)
                    // however, if no elements of the array have changed, we still don't want to export anything
                    // so that the array size will also be taken from the defaults, which won't be the case if any element is exported
                    else if (bAnyElementDiffered)
                    {
                        Out.Logf( TEXT("%s%s(%i)=()\r\n"), FCString::Spc(Indent), *Property->GetName(), DynamicArrayIndex );
                    }
                }
            }
            if (StructDefaults)
            {
                StructProperty->DestroyValue(StructDefaults);
                FMemory::Free(StructDefaults);
            }
        }
        else
        {
            for( int32 PropertyArrayIndex=0; PropertyArrayIndex<Property->ArrayDim; PropertyArrayIndex++ )
            {
                FString	Value;
                // Export single element.

                uint8* DiffData = (DiffClass && Property->IsInContainer(DiffClass->GetPropertiesSize())) ? Diff : NULL;
                if( Property->ExportText_InContainer( PropertyArrayIndex, Value, Object, DiffData, Parent, ExportFlags, ExportRootScope ) )
                {
                    if ( ExportObjectProp )
                    {
                        UObject* Obj = ExportObjectProp->GetObjectPropertyValue(Property->ContainerPtrToValuePtr<void>(Object, PropertyArrayIndex));
                        if( Obj && !Obj->HasAnyMarks(OBJECTMARK_TagImp) )
                        {
                            // only export the BEGIN OBJECT block for a component if Parent is the component's Outer....when importing subobject definitions,
                            // (i.e. BEGIN OBJECT), whichever BEGIN OBJECT block a component's BEGIN OBJECT block is located within is the object that will be
                            // used as the Outer to create the component
                            if ( Property->HasAnyPropertyFlags(CPF_InstancedReference) )
                            {
                                if ( Obj->GetOuter() == Parent )
                                {
                                    // Don't export more than once.
                                    Obj->Mark(OBJECTMARK_TagImp);
                                    UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags );
                                }
                                else
                                {
                                    // set the OBJECTMARK_TagExp flag so that the calling code knows we wanted to export this object
                                    Obj->Mark(OBJECTMARK_TagExp);
                                }
                            }
                            else
                            {
                                // Don't export more than once.
                                Obj->Mark(OBJECTMARK_TagImp);
                                UExporter::ExportToOutputDevice( Context, Obj, NULL, Out, TEXT("T3D"), Indent, PortFlags );
                            }
                        }
                    }

                    if( Property->ArrayDim == 1 )
                    {
                        Out.Logf( TEXT("%s%s=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), *Value );
                    }
                    else
                    {
                        Out.Logf( TEXT("%s%s(%i)=%s\r\n"), FCString::Spc(Indent), *Property->GetName(), PropertyArrayIndex, *Value );
                    }
                }
            }
        }
    }

    // Allows to import/export C++ properties in case the automatic unreal script mesh wouldn't work.
    Parent->ExportCustomProperties(Out, Indent);
}
FProcHandle FDesktopPlatformBase::InvokeUnrealBuildToolAsync(const FString& InCmdLineParams, FOutputDevice &Ar, void*& OutReadPipe, void*& OutWritePipe, bool bSkipBuildUBT)
{
	FString CmdLineParams = InCmdLineParams;

#if PLATFORM_WINDOWS
	#if _MSC_VER >= 1900
		CmdLineParams += TEXT(" -2015");
	#elif _MSC_VER >= 1800
		CmdLineParams += TEXT(" -2013");
	#else
		CmdLineParams += TEXT(" -2012");
	#endif
#endif // PLATFORM_WINDOWS

	// UnrealBuildTool is currently always located in the Binaries/DotNET folder
	FString ExecutableFileName = GetUnrealBuildToolExecutableFilename(FPaths::RootDir());

	// Rocket never builds UBT, UnrealBuildTool should already exist
	bool bSkipBuild = FApp::IsEngineInstalled() || bSkipBuildUBT;
	if (!bSkipBuild)
	{
		// When not using rocket, we should attempt to build UBT to make sure it is up to date
		// Only do this if we have not already successfully done it once during this session.
		static bool bSuccessfullyBuiltUBTOnce = false;
		if (!bSuccessfullyBuiltUBTOnce)
		{
			Ar.Log(TEXT("Building UnrealBuildTool..."));
			if (BuildUnrealBuildTool(FPaths::RootDir(), Ar))
			{
				bSuccessfullyBuiltUBTOnce = true;
			}
			else
			{
				// Failed to build UBT
				Ar.Log(TEXT("Failed to build UnrealBuildTool."));
				return FProcHandle();
			}
		}
	}

#if PLATFORM_LINUX
	CmdLineParams += (" -progress");
#endif // PLATFORM_LINUX

	Ar.Logf(TEXT("Launching UnrealBuildTool... [%s %s]"), *ExecutableFileName, *CmdLineParams);

#if PLATFORM_MAC
	// On Mac we launch UBT with Mono
	FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Mac/RunMono.sh"));
	CmdLineParams = FString::Printf(TEXT("\"%s\" \"%s\" %s"), *ScriptPath, *ExecutableFileName, *CmdLineParams);
	ExecutableFileName = TEXT("/bin/sh");
#elif PLATFORM_LINUX
	// Real men run Linux (with Mono??)
	FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Linux/RunMono.sh"));
	CmdLineParams = FString::Printf(TEXT("\"%s\" \"%s\" %s"), *ScriptPath, *ExecutableFileName, *CmdLineParams);
	ExecutableFileName = TEXT("/bin/bash");
#endif

	// Run UnrealBuildTool
	const bool bLaunchDetached = false;
	const bool bLaunchHidden = true;
	const bool bLaunchReallyHidden = bLaunchHidden;

	FProcHandle ProcHandle = FPlatformProcess::CreateProc(*ExecutableFileName, *CmdLineParams, bLaunchDetached, bLaunchHidden, bLaunchReallyHidden, NULL, 0, NULL, OutWritePipe);
	if (!ProcHandle.IsValid())
	{
		Ar.Logf(TEXT("Failed to launch Unreal Build Tool. (%s)"), *ExecutableFileName);
	}

	return ProcHandle;
}
示例#26
0
//
// Command line.
//
UBOOL UXViewport::Exec( const TCHAR* Cmd, FOutputDevice& Ar )
{
	guard(UXViewport::Exec);
	if( UViewport::Exec( Cmd, Ar ) )
	{
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("EndFullscreen")) )
	{
		EndFullscreen();
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("ToggleFullscreen")) )
	{
		ToggleFullscreen();
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("Iconify")) )
	{
		Iconify();
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("GetCurrentRes")) )
	{
		Ar.Logf( TEXT("%ix%i"), SizeX, SizeY, (ColorBytes?ColorBytes:2)*8 );
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("GetCurrentColorDepth")) )
	{
		Ar.Logf( TEXT("%i"), (ColorBytes?ColorBytes:2)*8 );
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("GetColorDepths")) )
	{
		Ar.Log( TEXT("16 32") );
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("GetCurrentRenderDevice")) )
	{
		Ar.Log( RenDev->GetClass()->GetPathName() );
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("SetRenderDevice")) )
	{
		FString Saved = RenDev->GetClass()->GetPathName();
		INT SavedSizeX=SizeX, SavedSizeY=SizeY, SavedColorBytes=ColorBytes, SavedFullscreen=((BlitFlags & BLIT_Fullscreen)!=0);
		TryRenderDevice( Cmd, SizeX, SizeY, ColorBytes, SavedFullscreen );
		if( !RenDev )
		{
			TryRenderDevice( *Saved, SavedSizeX, SavedSizeY, SavedColorBytes, SavedFullscreen );
			check(RenDev);
			Ar.Log(TEXT("0"));
		}
		else Ar.Log(TEXT("1"));
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("GetRes")) )
	{
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("SetRes")) )
	{
		INT X=appAtoi(Cmd);
		TCHAR* CmdTemp = (TCHAR*) (appStrchr(Cmd,'x') ? appStrchr(Cmd,'x')+1 : appStrchr(Cmd,'X') ? appStrchr(Cmd,'X')+1 : TEXT(""));
		INT Y=appAtoi(CmdTemp);
		Cmd = CmdTemp;
		CmdTemp = (TCHAR*) (appStrchr(Cmd,'x') ? appStrchr(Cmd,'x')+1 : appStrchr(Cmd,'X') ? appStrchr(Cmd,'X')+1 : TEXT(""));
		INT C=appAtoi(CmdTemp);
		INT NewColorBytes = C ? C/8 : ColorBytes;
		if( X && Y )
		{
			HoldCount++;
			UBOOL Result = RenDev->SetRes( X, Y, NewColorBytes, IsFullscreen() );
			HoldCount--;
			if( !Result )
				EndFullscreen();
		}
		return 1;
	}
	else if( ParseCommand(&Cmd,TEXT("Preferences")) )
	{
		// No preferences window.
	
		return 1;
	}
	else return 0;
	unguard;
}
示例#27
0
/**
 * Dumps capture stack trace summary to the passed in log.
 */
void FStackTracker::DumpStackTraces( int32 StackThreshold, FOutputDevice& Ar )
{
	// Avoid distorting results while we log them.
	check( !bAvoidCapturing );
	bAvoidCapturing = true;

	// Make a copy as sorting causes index mismatch with TMap otherwise.
	TArray<FCallStack> SortedCallStacks = CallStacks;
	// Compare function, sorting callstack by stack count in descending order.
	struct FCompareStackCount
	{
		FORCEINLINE bool operator()( const FCallStack& A, const FCallStack& B ) const { return B.StackCount < A.StackCount; }
	};
	// Sort callstacks in descending order by stack count.
	SortedCallStacks.Sort( FCompareStackCount() );

	// Iterate over each callstack to get total stack count.
	uint64 TotalStackCount = 0;
	for( int32 CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks[CallStackIndex];
		TotalStackCount += CallStack.StackCount;
	}

	// Calculate the number of frames we captured.
	int32 FramesCaptured = 0;
	if( bIsEnabled )
	{
		FramesCaptured = GFrameCounter - StartFrameCounter;
	}
	else
	{
		FramesCaptured = StopFrameCounter - StartFrameCounter;
	}

	// Log quick summary as we don't log each individual so totals in CSV won't represent real totals.
	Ar.Logf(TEXT("Captured %i unique callstacks totalling %i function calls over %i frames, averaging %5.2f calls/frame, Avg Per Frame"), SortedCallStacks.Num(), (int32)TotalStackCount, FramesCaptured, (float) TotalStackCount / FramesCaptured);

	// Iterate over each callstack and write out info in human readable form in CSV format
	for( int32 CallStackIndex=0; CallStackIndex<SortedCallStacks.Num(); CallStackIndex++ )
	{
		const FCallStack& CallStack = SortedCallStacks[CallStackIndex];

		// Avoid log spam by only logging above threshold.
		if( CallStack.StackCount > StackThreshold )
		{
			// First row is stack count.
			FString CallStackString = FString::FromInt((int32)CallStack.StackCount);
			CallStackString += FString::Printf( TEXT(",%5.2f"), static_cast<float>(CallStack.StackCount)/static_cast<float>(FramesCaptured) );
			

			// Iterate over all addresses in the callstack to look up symbol name.
			for( int32 AddressIndex=0; AddressIndex<ARRAY_COUNT(CallStack.Addresses) && CallStack.Addresses[AddressIndex]; AddressIndex++ )
			{
				ANSICHAR AddressInformation[512];
				AddressInformation[0] = 0;
				FPlatformStackWalk::ProgramCounterToHumanReadableString( AddressIndex, CallStack.Addresses[AddressIndex], AddressInformation, ARRAY_COUNT(AddressInformation)-1 );
				CallStackString = CallStackString + LINE_TERMINATOR TEXT(",,,") + FString(AddressInformation);
			}

			// Finally log with ',' prefix so "Log:" can easily be discarded as row in Excel.
			Ar.Logf(TEXT(",%s"),*CallStackString);
            
			//Append any user information before moving on to the next callstack
			if (ReportFn)
			{
				ReportFn(CallStack, CallStack.StackCount, Ar);
			}
		}
	}

	// Done logging.
	bAvoidCapturing = false;
}
示例#28
0
bool FSteamVRHMD::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
{
	if (FParse::Command( &Cmd, TEXT("STEREO") ))
	{
		if (FParse::Command(&Cmd, TEXT("ON")))
		{
			if (!IsHMDEnabled())
			{
				Ar.Logf(TEXT("HMD is disabled. Use 'hmd enable' to re-enable it."));
			}
			EnableStereo(true);
			return true;
		}
		else if (FParse::Command(&Cmd, TEXT("OFF")))
		{
			EnableStereo(false);
			return true;
		}

		float val;
		if (FParse::Value(Cmd, TEXT("E="), val))
		{
			IPD = val;
		}
	}
	else if (FParse::Command(&Cmd, TEXT("HMD")))
	{
		if (FParse::Command(&Cmd, TEXT("ENABLE")))
		{
			EnableHMD(true);
			return true;
		}
		else if (FParse::Command(&Cmd, TEXT("DISABLE")))
		{
			EnableHMD(false);
			return true;
		}

		int32 val;
		if (FParse::Value(Cmd, TEXT("MIRROR"), val))
		{
			if ((val >= 0) && (val <= 2))
			{
				WindowMirrorMode = val;
			}
			else
		{
				Ar.Logf(TEXT("HMD MIRROR accepts values from 0 though 2"));
		}

			return true;
		}
	}
	else if (FParse::Command(&Cmd, TEXT("UNCAPFPS")))
	{
		GEngine->bForceDisableFrameRateSmoothing = true;
		return true;
	}

	return false;
}
示例#29
0
/**
 * Dumps detailed information of bulk data usage.
 *
 * @param Log FOutputDevice to use for logging
 */
void FUntypedBulkData::DumpBulkDataUsage( FOutputDevice& Log )
{
#if TRACK_BULKDATA_USE
	// Arrays about to hold per object and per class size information.
	TArray<FObjectAndSize> PerObjectSizeArray;
	TArray<FObjectAndSize> PerClassSizeArray;

	{
		FScopeLock Lock(&FThreadSafeBulkDataToObjectMap::Get().GetLock());

		// Iterate over all "live" bulk data and add size to arrays if it is loaded.
		for( auto It(FThreadSafeBulkDataToObjectMap::Get().GetIterator()); It; ++It )
		{
			const FUntypedBulkData*	BulkData	= It.Key();
			const UObject*			Owner		= It.Value();
			// Only add bulk data that is consuming memory to array.
			if( Owner && BulkData->IsBulkDataLoaded() && BulkData->GetBulkDataSize() > 0 )
			{
				// Per object stats.
				PerObjectSizeArray.Add( FObjectAndSize( Owner, BulkData->GetBulkDataSize() ) );

				// Per class stats.
				bool bFoundExistingPerClassSize = false;
				// Iterate over array, trying to find existing entry.
				for( int32 PerClassIndex=0; PerClassIndex<PerClassSizeArray.Num(); PerClassIndex++ )
				{
					FObjectAndSize& PerClassSize = PerClassSizeArray[ PerClassIndex ];
					// Add to existing entry if found.
					if( PerClassSize.Object == Owner->GetClass() )
					{
						PerClassSize.Size += BulkData->GetBulkDataSize();
						bFoundExistingPerClassSize = true;
						break;
					}
				}
				// Add new entry if we didn't find an existing one.
				if( !bFoundExistingPerClassSize )
				{
					PerClassSizeArray.Add( FObjectAndSize( Owner->GetClass(), BulkData->GetBulkDataSize() ) );
				}
			}
		}
	}

	/** Compare operator, sorting by size in descending order */
	struct FCompareFObjectAndSize
	{
		FORCEINLINE bool operator()( const FObjectAndSize& A, const FObjectAndSize& B ) const
		{
			return B.Size < A.Size;
		}
	};

	// Sort by size.
	PerObjectSizeArray.Sort( FCompareFObjectAndSize() );
	PerClassSizeArray.Sort( FCompareFObjectAndSize() );

	// Log information.
	UE_LOG(LogSerialization, Log, TEXT(""));
	UE_LOG(LogSerialization, Log, TEXT("Per class summary of bulk data use:"));
	for( int32 PerClassIndex=0; PerClassIndex<PerClassSizeArray.Num(); PerClassIndex++ )
	{
		const FObjectAndSize& PerClassSize = PerClassSizeArray[ PerClassIndex ];
		Log.Logf( TEXT("  %5d KByte of bulk data for Class %s"), PerClassSize.Size / 1024, *PerClassSize.Object->GetPathName() );
	}
	UE_LOG(LogSerialization, Log, TEXT(""));
	UE_LOG(LogSerialization, Log, TEXT("Detailed per object stats of bulk data use:"));
	for( int32 PerObjectIndex=0; PerObjectIndex<PerObjectSizeArray.Num(); PerObjectIndex++ )
	{
		const FObjectAndSize& PerObjectSize = PerObjectSizeArray[ PerObjectIndex ];
		Log.Logf( TEXT("  %5d KByte of bulk data for %s"), PerObjectSize.Size / 1024, *PerObjectSize.Object->GetFullName() );
	}
	UE_LOG(LogSerialization, Log, TEXT(""));
#else
	UE_LOG(LogSerialization, Log, TEXT("Please recompiled with TRACK_BULKDATA_USE set to 1 in UnBulkData.cpp."));
#endif
}
	/** Console commands, see embeded usage statement **/
	virtual bool Exec( UWorld* Inworld, const TCHAR* Cmd, FOutputDevice& Ar )
	{
		if(FParse::Command(&Cmd,TEXT("LOG")))
		{
			if(FParse::Command(&Cmd,TEXT("LIST"))) // if they didn't use the list command, we will show usage
			{
				TArray<FLogCategoryPtrs> Found;

				FString Cat(FParse::Token(Cmd, 0));
				for (TMap<FLogCategoryBase*, FName>::TIterator It(Associations); It; ++It)
				{
					FLogCategoryBase* Verb = It.Key();
					FString Name = It.Value().ToString();
					if (!Cat.Len() || Name.Contains(Cat) )
					{
						Found.Add(FLogCategoryPtrs(Name, ELogVerbosity::Type(Verb->Verbosity), Verb->DebugBreakOnLog));
					}
				}

				Found.Sort();

				for (TArray<FLogCategoryPtrs>::TConstIterator It = Found.CreateConstIterator(); It; ++It)
				{
					Ar.Logf(TEXT("%-40s  %-12s  %s"), *It->Name, FOutputDevice::VerbosityToString(It->Verbosity), It->Postfix ? TEXT(" - DebugBreak") : TEXT(""));
				}
			}
			else
			{
				FString Rest(Cmd);
				Rest = Rest.Trim();
				if (Rest.Len())
				{
					if (ProcessLogOnly(Rest, Ar))
					{
						return true;
					}

					TMap<FName, uint8> OldValues;
					for (TMap<FLogCategoryBase*, FName>::TIterator It(Associations); It; ++It)
					{
						FLogCategoryBase* Verb = It.Key();
						FName Name = It.Value();
						OldValues.Add(Name, Verb->Verbosity);
					}
					ProcessCmdString(Rest);
					for (TMap<FLogCategoryBase*, FName>::TIterator It(Associations); It; ++It)
					{
						FLogCategoryBase* Verb = It.Key();
						FName Name = It.Value();
						uint8 OldValue = OldValues.FindRef(Name);
						if (Verb->Verbosity != OldValue)
						{
							Ar.Logf(TEXT("%-40s  %-12s  %s"), *Name.ToString(), FOutputDevice::VerbosityToString(ELogVerbosity::Type(Verb->Verbosity)), Verb->DebugBreakOnLog ? TEXT(" - DebugBreak") : TEXT(""));
						}
					}
				}
				else
				{
					Ar.Logf( TEXT("------- Log conventions") );
					Ar.Logf( TEXT("[cat]   = a category for the command to operate on, or 'global' for all categories.") );
					Ar.Logf( TEXT("[level] = verbosity level, one of: none, error, warning, display, log, verbose, all, default") );
					Ar.Logf( TEXT("At boot time, compiled in default is overridden by ini files setting, which is overridden by command line") );
					Ar.Logf( TEXT("------- Log console command usage") );
					Ar.Logf( TEXT("Log list            - list all log categories") );
					Ar.Logf( TEXT("Log list [string]   - list all log categories containing a substring") );
					Ar.Logf( TEXT("Log reset           - reset all log categories to their boot-time default") );
					Ar.Logf( TEXT("Log [cat]           - toggle the display of the category [cat]") );
					Ar.Logf( TEXT("Log [cat] off       - disable display of the category [cat]") );
					Ar.Logf( TEXT("Log [cat] on        - resume display of the category [cat]") );
					Ar.Logf( TEXT("Log [cat] only      - enables [cat] and disables all other categories"));
					Ar.Logf( TEXT("Log [cat] [level]   - set the verbosity level of the category [cat]") );
					Ar.Logf( TEXT("Log [cat] break     - toggle the debug break on display of the category [cat]") );
					Ar.Logf( TEXT("------- Log command line") );
					Ar.Logf( TEXT("-LogCmds=\"[arguments],[arguments]...\"           - applies a list of console commands at boot time") );
					Ar.Logf( TEXT("-LogCmds=\"foo verbose, bar off\"         - turns on the foo category and turns off the bar category") );					
					Ar.Logf( TEXT("------- Environment variables") );
					Ar.Logf( TEXT("Any command line option can be set via the environment variable UE-CmdLineArgs") );
					Ar.Logf( TEXT("set UE-CmdLineArgs=\"-LogCmds=foo verbose breakon, bar off\"") );
					Ar.Logf( TEXT("------- Config file") );
					Ar.Logf( TEXT("[Core.Log]") );
					Ar.Logf( TEXT("global=[default verbosity for things not listed later]") );					
					Ar.Logf( TEXT("[cat]=[level]") );					
					Ar.Logf( TEXT("foo=verbose break") );					
				}
			}
			return true;
		}
		return false;
	}