void FProfilerStatMetaData::Update( const FStatMetaData& ClientStatMetaData )
{
	PROFILER_SCOPE_LOG_TIME( TEXT( "FProfilerStatMetaData.Update" ), nullptr );

	// Iterate through all thread descriptions.
	ThreadDescriptions.Append( ClientStatMetaData.ThreadDescriptions );

	// Initialize fake stat for Self.
	const uint32 NoGroupID = 0;

	InitializeGroup( NoGroupID, "NoGroup" );
	InitializeStat( 0, NoGroupID, TEXT( "Self" ), STATTYPE_CycleCounter );
	InitializeStat( 1, NoGroupID, FStatConstants::NAME_ThreadRoot.GetPlainNameString(), STATTYPE_CycleCounter, FStatConstants::NAME_ThreadRoot );

	// Iterate through all stat group descriptions.
	for( auto It = ClientStatMetaData.GroupDescriptions.CreateConstIterator(); It; ++It )
	{
		const FStatGroupDescription& GroupDesc = It.Value();
		InitializeGroup( GroupDesc.ID, GroupDesc.Name );
	}

	// Iterate through all stat descriptions.
	for( auto It = ClientStatMetaData.StatDescriptions.CreateConstIterator(); It; ++It )
	{
		const FStatDescription& StatDesc = It.Value();
		InitializeStat( StatDesc.ID, StatDesc.GroupID, StatDesc.Name, (EStatType)StatDesc.StatType );
	}

	SecondsPerCycle = ClientStatMetaData.SecondsPerCycle;
}
	void CBioSIMModelBase::GetFValue(const std::vector<double>& paramArray, CStatisticXY& stat)
	{
		Randomize((unsigned int)m_info.m_seed);
		InitRandomGenerator(m_info.m_seed);

		for (size_t i = 0, j = 0; i < m_info.m_inputParameters.size() && j < paramArray.size(); i++)
		{
			if (m_info.m_inputParameters[i].IsVariable())
			{
				std::string value;
				value = ToString(paramArray[j]);
				m_info.m_inputParameters[i].SetString(value);
				j++;
			}
		}

		ProcessParameters(m_info.m_inputParameters);

		InitializeStat(stat);

		for (size_t i = 0; i < m_info.m_repCounter.GetTotal(); i++)
		{
			CStatisticXY statTmp;

			switch (m_info.m_TM.Type())
			{
			case CTM::HOURLY: GetFValueHourly(statTmp); break;
			case CTM::DAILY: GetFValueDaily(statTmp); break;
			case CTM::MONTHLY: GetFValueMonthly(statTmp); break;
			case CTM::ANNUAL: GetFValueAnnual(statTmp); break;
			case CTM::ATEMPORAL: GetFValueAtemporal(statTmp); break;
			default: _ASSERTE(false);
			}

			stat += statTmp;
		}


		FinalizeStat(stat);
	}
void FProfilerStatMetaData::UpdateFromStatsState( const FStatsThreadState& StatsThreadStats )
{
	TMap<FName, int32> GroupFNameIDs;

	for( auto It = StatsThreadStats.Threads.CreateConstIterator(); It; ++It )
	{
		ThreadDescriptions.Add( It.Key(), It.Value().ToString() );
	}

	const uint32 NoGroupID = 0;
	const uint32 ThreadGroupID = 1;

	// Special groups.
	InitializeGroup( NoGroupID, "NoGroup" );

	// Self must be 0.
	InitializeStat( 0, NoGroupID, TEXT( "Self" ), STATTYPE_CycleCounter );

	// ThreadRoot must be 1.
	InitializeStat( 1, NoGroupID, FStatConstants::NAME_ThreadRoot.GetPlainNameString(), STATTYPE_CycleCounter, FStatConstants::NAME_ThreadRoot );

	int32 UniqueID = 15;

	TArray<FName> GroupFNames;
	StatsThreadStats.Groups.MultiFind( NAME_Groups, GroupFNames );
	for( const auto& GroupFName : GroupFNames  )
	{
		UniqueID++;
		InitializeGroup( UniqueID, GroupFName.ToString() );
		GroupFNameIDs.Add( GroupFName, UniqueID );
	}

	for( auto It = StatsThreadStats.ShortNameToLongName.CreateConstIterator(); It; ++It )
	{
		const FStatMessage& LongName = It.Value();
		
		const FName GroupName = LongName.NameAndInfo.GetGroupName();
		if( GroupName == NAME_Groups )
		{
			continue;
		}
		const int32 GroupID = GroupFNameIDs.FindChecked( GroupName );

		const FName StatName = It.Key();
		UniqueID++;

		EStatType StatType = STATTYPE_Error;
		if( LongName.NameAndInfo.GetField<EStatDataType>() == EStatDataType::ST_int64 )
		{
			if( LongName.NameAndInfo.GetFlag( EStatMetaFlags::IsCycle ) )
			{
				StatType = STATTYPE_CycleCounter;
			}
			else if( LongName.NameAndInfo.GetFlag( EStatMetaFlags::IsMemory ) )
			{
				StatType = STATTYPE_MemoryCounter;
			}
			else
			{
				StatType = STATTYPE_AccumulatorDWORD;
			}
		}
		else if( LongName.NameAndInfo.GetField<EStatDataType>() == EStatDataType::ST_double )
		{
			StatType = STATTYPE_AccumulatorFLOAT;
		}
		else if( LongName.NameAndInfo.GetField<EStatDataType>() == EStatDataType::ST_Ptr )
		{
			// Not supported at this moment.
			continue;
		}

		check( StatType != STATTYPE_Error );

		int32 StatID = UniqueID;
		// Some hackery.
		if( StatName == TEXT( "STAT_FrameTime" ) )
		{
			StatID = 2;
		}

		const FString Description = LongName.NameAndInfo.GetDescription();
		const FString StatDesc = !Description.IsEmpty() ? Description : StatName.ToString();

		InitializeStat( StatID, GroupID, StatDesc, StatType, StatName );

		// Setup thread id to stat id.
		if( GroupName == FStatConstants::NAME_ThreadGroup )
		{
			uint32 ThreadID = 0;
			for( auto ThreadsIt = StatsThreadStats.Threads.CreateConstIterator(); ThreadsIt; ++ThreadsIt )
			{
				if (ThreadsIt.Value() == StatName)
				{
					ThreadID = ThreadsIt.Key();
					break;
				}
			}
			ThreadIDtoStatID.Add( ThreadID, StatID );

			// Game thread is always NAME_GameThread
			if( StatName == NAME_GameThread )
			{
				GameThreadID = ThreadID;
			}
			// Rendering thread may be "Rendering thread" or NAME_RenderThread with an index
			else if( StatName.GetPlainNameString().Contains( FName(NAME_RenderThread).GetPlainNameString() ) )
			{
				RenderThreadIDs.AddUnique( ThreadID );
			}
			else if( StatName.GetPlainNameString().Contains( TEXT( "RenderingThread" ) ) )
			{
				RenderThreadIDs.AddUnique( ThreadID );
			}
		}
	}
}