!F (Profiling) (DEV-7030) Rewrite of the profiling system to have a unified interface...
[CRYENGINE.git] / Code / CryEngine / CrySystem / Statistics.cpp
blob67ec2eab595e617d134c658c265cb4b6a63bc265
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include <StdAfx.h>
5 #include <CrySystem/ISystem.h>
6 #include <Cry3DEngine/I3DEngine.h>
7 #include <CryRenderer/IRenderer.h>
8 #include <CrySystem/IConsole.h>
9 #include <CryAnimation/ICryAnimation.h>
10 #include <CrySystem/Profilers/IPerfHud.h>
11 #include <CryString/CryPath.h>
12 #include <CryMemory/CrySizer.h>
13 #include "CrySizerImpl.h"
14 #include "CrySizerStats.h"
15 #include "System.h"
16 #include <CryMemory/CryMemoryManager.h>
17 #include <CryScriptSystem/IScriptSystem.h>
18 #include <CryCore/ToolsHelpers/ResourceCompilerHelper.h>
19 #include "PhysRenderer.h"
20 #include <CrySystem/File/IResourceManager.h>
21 #include <CrySystem/Scaleform/IFlashPlayer.h>
22 #include <CrySystem/IStreamEngine.h>
23 #include <CryAction/ITimeDemoRecorder.h>
24 #include <CrySystem/Profilers/ILegacyProfiler.h>
26 // Access to some game info.
27 #include <CryGame/IGameFramework.h>
28 #include <../CryAction/ILevelSystem.h>
29 #include <CryEntitySystem/IEntitySystem.h>
31 const std::vector<string>& GetModuleNames()
33 static std::vector<string> moduleNames;
35 if (moduleNames.empty())
37 static_cast<CSystem*>(gEnv->pSystem)->GetLoadedDynamicLibraries(moduleNames);
40 return moduleNames;
43 #if (!defined (_RELEASE) || defined(ENABLE_PROFILING_CODE))
44 #if CRY_PLATFORM_WINDOWS
45 #pragma pack(push,1)
46 const struct PEHeader_DLL
48 DWORD signature;
49 IMAGE_FILE_HEADER _head;
50 IMAGE_OPTIONAL_HEADER opt_head;
51 IMAGE_SECTION_HEADER* section_header; // actual number in NumberOfSections
53 #pragma pack(pop)
54 #endif
56 extern int CryMemoryGetAllocatedSize();
57 static void SaveLevelStats(IConsoleCmdArgs* pArgs);
59 #define g_szTestResults "%USER%/TestResults"
61 class CResourceCollector : public IResourceCollector
63 struct SInstanceEntry
65 // AABB m_AABB;
66 uint32 m_dwFileNameId; // use with m_FilenameToId, m_IdToFilename
69 struct SAssetEntry
71 SAssetEntry() : m_dwInstanceCnt(0), m_dwDependencyCnt(0), m_dwMemSize(0xffffffff), m_dwFileSize(0xffffffff)
75 string m_sFileName;
76 uint32 m_dwInstanceCnt; // 1=this asset is used only once in the level, 2, 3, ...
77 uint32 m_dwDependencyCnt; // 1=this asset is only used by one asset, 2, 3, ...
78 uint32 m_dwMemSize; // 0xffffffff if unknown (only needed to verify disk file size)
79 uint32 m_dwFileSize; // 0xffffffff if unknown
82 public: // -----------------------------------------------------------------------------
84 CResourceCollector()
86 m_bEnabled = false;
88 void Enable(bool bEnabled) { m_bEnabled = bEnabled; }
90 // compute m_dwDependencyCnt
91 void ComputeDependencyCnt()
93 std::set<SDependencyPair>::const_iterator it, end = m_Dependencies.end();
95 for (it = m_Dependencies.begin(); it != end; ++it)
97 const SDependencyPair& rRef = *it;
99 ++m_Assets[rRef.m_idDependsOnAsset].m_dwDependencyCnt;
103 // watch out: this function modifies internal data
104 void LogData(ILog& rLog)
106 if (!m_bEnabled)
107 return;
109 rLog.Log(" ");
112 rLog.Log("Assets:");
114 std::vector<SAssetEntry>::const_iterator it, end = m_Assets.end();
115 uint32 dwAssetID = 0;
117 for (it = m_Assets.begin(); it != end; ++it, ++dwAssetID)
119 const SAssetEntry& rRef = *it;
121 rLog.Log(" A%u: inst:%5u dep:%u mem:%9u file:%9u name:%s", dwAssetID, rRef.m_dwInstanceCnt, rRef.m_dwDependencyCnt, rRef.m_dwMemSize, rRef.m_dwFileSize, rRef.m_sFileName.c_str());
125 rLog.Log(" ");
128 rLog.Log("Dependencies:");
130 std::set<SDependencyPair>::const_iterator it, end = m_Dependencies.end();
132 uint32 dwCurrentAssetID = 0xffffffff;
133 uint32 dwSumFile = 0;
135 for (it = m_Dependencies.begin(); it != end; ++it)
137 const SDependencyPair& rRef = *it;
139 if (rRef.m_idAsset != dwCurrentAssetID)
141 if (dwSumFile != 0 && dwSumFile != 0xffffffff)
142 rLog.Log(" ---> sum file: %u KB", (dwSumFile + 1023) / 1024);
144 dwSumFile = 0;
146 rLog.Log(" ");
147 rLog.Log(" A%u '%s' depends on", rRef.m_idAsset, m_Assets[rRef.m_idAsset].m_sFileName.c_str());
150 uint32 dwFileSize = m_Assets[rRef.m_idDependsOnAsset].m_dwFileSize;
152 rLog.Log(" A%u file:%9u dep:%u '%s'", rRef.m_idDependsOnAsset, dwFileSize, m_Assets[rRef.m_idDependsOnAsset].m_dwDependencyCnt, m_Assets[rRef.m_idDependsOnAsset].m_sFileName.c_str());
154 if (dwFileSize != 0xffffffff)
155 dwSumFile += dwFileSize;
157 dwCurrentAssetID = rRef.m_idAsset;
160 if (dwSumFile != 0 && dwSumFile != 0xffffffff)
161 rLog.Log(" ---> sum file: %u KB", (dwSumFile + 1023) / 1024);
164 rLog.Log(" ");
167 rLog.Log("SourceAtoms:");
169 std::set<SDependencyPair>::const_iterator it;
171 while (!m_Dependencies.empty())
173 for (it = m_Dependencies.begin(); it != m_Dependencies.end(); ++it)
175 const SDependencyPair& rRef1 = *it;
177 rLog.Log(" ");
178 std::set<uint32> localDependencies;
180 localDependencies.insert(rRef1.m_idAsset);
182 RecursiveMove(rRef1.m_idAsset, localDependencies);
184 PrintDependencySet(rLog, localDependencies);
185 break;
191 // interface IResourceCollector -------------------------------------------------
193 virtual bool AddResource(const char* szFileName, const uint32 dwSize = 0xffffffff)
195 if (!m_bEnabled)
196 return true;
198 uint32 dwNewAssetIdOrInvalid = _AddResource(szFileName, dwSize);
200 return dwNewAssetIdOrInvalid != 0xffffffff;
203 virtual void AddInstance(const char* _szFileName, void* pInstance)
205 if (!m_bEnabled)
206 return;
208 assert(pInstance);
211 std::set<void*>::const_iterator itInstance = m_ReportedInstances.find(pInstance);
213 if (itInstance != m_ReportedInstances.end())
214 return;
217 string sOutputFileName = UnifyFilename(_szFileName);
219 std::map<string, uint32>::const_iterator it = m_FilenameToId.find(sOutputFileName);
221 if (it == m_FilenameToId.end())
223 OutputDebugString("ERROR: file wasn't registered with AddResource(): '");
224 OutputDebugString(sOutputFileName.c_str());
225 OutputDebugString("'\n");
226 CRY_ASSERT_MESSAGE(0, "The asset wasn't registered yet. AddResource() missing - unpredictable result might happen.");
227 return;
230 uint32 dwAssetId = it->second;
232 // debug
233 char str[256];
234 cry_sprintf(str,"AddInstance: %p '",pInstance);
235 OutputDebugString(str);
236 OutputDebugString(sOutputFileName.c_str());
237 OutputDebugString("'\n");
239 ++m_Assets[dwAssetId].m_dwInstanceCnt;
240 m_ReportedInstances.insert(pInstance);
243 virtual void OpenDependencies(const char* _szFileName)
245 if (!m_bEnabled)
246 return;
248 string sOutputFileName = UnifyFilename(_szFileName);
250 std::map<string, uint32>::const_iterator it = m_FilenameToId.find(sOutputFileName);
252 if (it == m_FilenameToId.end())
254 m_OpenedAssetId.push_back(0xffffffff); // CloseDependencies() relies on that
256 OutputDebugString("ERROR: file wasn't registered with AddResource(): '");
257 OutputDebugString(sOutputFileName.c_str());
258 OutputDebugString("'\n");
259 CRY_ASSERT_MESSAGE(0, "The asset wasn't registered yet. AddResource() missing - unpredictable result might happen.");
260 return;
263 uint32 dwAssetId = it->second;
265 m_OpenedAssetId.push_back(dwAssetId);
268 virtual void Reset()
270 m_Assets.resize(0);
271 m_Dependencies.clear();
272 m_FilenameToId.clear();
273 m_OpenedAssetId.resize(0);
274 m_ReportedInstances.clear();
275 m_ResourceEntries.resize(0);
278 virtual void CloseDependencies()
280 if (!m_bEnabled)
281 return;
283 assert(!m_OpenedAssetId.empty()); // internal error - OpenDependencies() should match CloseDependencies()
285 m_OpenedAssetId.pop_back();
288 private: // -----------------------------------------------------------------------
290 struct SDependencyPair
292 SDependencyPair(const uint32 idAsset, const uint32 idDependsOnAsset) : m_idAsset(idAsset), m_idDependsOnAsset(idDependsOnAsset)
296 uint32 m_idAsset; // AssetID
297 uint32 m_idDependsOnAsset; // AssetID
299 bool operator<(const SDependencyPair& rhs) const
301 if (m_idAsset < rhs.m_idAsset) return true;
302 if (m_idAsset > rhs.m_idAsset) return false;
304 return m_idDependsOnAsset < rhs.m_idDependsOnAsset;
308 std::vector<uint32> m_OpenedAssetId; // to track for dependencies
309 std::map<string, uint32> m_FilenameToId; // could be done more efficiently
310 std::vector<SAssetEntry> m_Assets; // could be done more efficiently
311 std::vector<SInstanceEntry> m_ResourceEntries; //
312 std::set<SDependencyPair> m_Dependencies; //
313 std::set<void*> m_ReportedInstances; // to avoid counting them twice
314 bool m_bEnabled;
316 // ---------------------------------------------------------------------
318 string UnifyFilename(const char* _szFileName) const
320 char* szFileName = (char*)_szFileName;
322 // as bump and normal maps become combined during loading e.g. blah.tif+blah_ddn.dds
323 // the filename needs to be adjusted
325 char* pSearchForPlus = szFileName;
327 while (*pSearchForPlus != 0 && *pSearchForPlus != '+')
328 ++pSearchForPlus;
330 if (*pSearchForPlus == '+')
331 szFileName = pSearchForPlus + 1;
334 string sOutputFileName;
336 char buffer[512];
337 CResourceCompilerHelper::GetOutputFilename(szFileName, buffer, sizeof(buffer));
338 sOutputFileName = buffer;
341 sOutputFileName = PathUtil::ToUnixPath(sOutputFileName);
342 sOutputFileName.MakeLower();
344 return sOutputFileName;
347 // Returns:
348 // 0xffffffff if asset was already known (m_dwInstanceCnt will be increased), AssetId otherwise
349 uint32 _AddResource(const char* _szFileName, const uint32 dwSize = 0xffffffff)
351 assert(_szFileName);
353 if (_szFileName[0] == 0)
354 return 0xffffffff; // no name provided - ignore this case - this often means the feature is not used
356 uint32 dwNewAssetIdOrInvalid = 0xffffffff;
358 string sOutputFileName = UnifyFilename(_szFileName);
360 std::map<string, uint32>::const_iterator it = m_FilenameToId.find(sOutputFileName);
361 uint32 dwAssetId;
363 if (it != m_FilenameToId.end())
364 dwAssetId = it->second;
365 else
367 dwAssetId = m_FilenameToId.size();
368 m_FilenameToId[sOutputFileName] = dwAssetId;
370 SAssetEntry NewAsset;
372 NewAsset.m_sFileName = sOutputFileName;
374 // if(dwSize==0xffffffff)
376 CCryFile file;
378 if (file.Open(sOutputFileName.c_str(), "rb"))
379 NewAsset.m_dwFileSize = file.GetLength();
382 dwNewAssetIdOrInvalid = dwAssetId;
383 m_Assets.push_back(NewAsset);
386 SAssetEntry& rAsset = m_Assets[dwAssetId];
388 if (dwSize != 0xffffffff) // if size was specified
390 if (rAsset.m_dwMemSize == 0xffffffff)
392 rAsset.m_dwMemSize = dwSize; // store size
394 else
395 assert(rAsset.m_dwMemSize == dwSize); // size should always be the same
398 // rAsset.m_dwInstanceCnt+=dwInstanceCount;
400 // debugging
401 // char str[1204];
402 // cry_sprintf(str,"_AddResource %s(size=%d cnt=%d)\n",_szFileName,rAsset.m_dwInstanceCnt,rAsset.m_dwMemSize);
403 // OutputDebugString(str);
405 SInstanceEntry instance;
407 instance.m_dwFileNameId = dwAssetId;
409 AddDependencies(dwAssetId);
411 m_ResourceEntries.push_back(instance);
412 return dwNewAssetIdOrInvalid;
415 void AddDependencies(const uint32 dwPushedAssetId)
417 std::vector<uint32>::const_iterator it, end = m_OpenedAssetId.end();
419 for (it = m_OpenedAssetId.begin(); it != end; ++it)
421 uint32 dwOpendedAssetId = *it;
423 if (dwOpendedAssetId == 0xffffffff)
424 continue; // asset wasn't registered yet AddResource() missing
426 m_Dependencies.insert(SDependencyPair(dwOpendedAssetId, dwPushedAssetId));
430 void PrintDependencySet(ILog& rLog, const std::set<uint32>& Dep)
432 rLog.Log(" {");
433 std::set<uint32>::const_iterator it, end = Dep.end();
434 uint32 dwSumFile = 0;
436 // iteration could be optimized
437 for (it = Dep.begin(); it != end; ++it)
439 uint32 idAsset = *it;
441 uint32 dwFileSize = m_Assets[idAsset].m_dwFileSize;
443 if (dwFileSize != 0xffffffff)
444 dwSumFile += dwFileSize;
446 rLog.Log(" A%u file:%9u dep:%u '%s'", idAsset, m_Assets[idAsset].m_dwFileSize, m_Assets[idAsset].m_dwDependencyCnt, m_Assets[idAsset].m_sFileName.c_str());
448 rLog.Log(" } ---> sum file: %u KB", (dwSumFile + 1023) / 1024);
451 // find all dependencies to it and move to localDependencies
452 void RecursiveMove(const uint32 dwCurrentAssetID, std::set<uint32>& localDependencies)
454 bool bProcess = true;
456 // iteration could be optimized
457 while (bProcess)
459 bProcess = false;
461 std::set<SDependencyPair>::iterator it;
463 for (it = m_Dependencies.begin(); it != m_Dependencies.end(); ++it)
465 SDependencyPair Pair = *it;
467 if (Pair.m_idAsset == dwCurrentAssetID || Pair.m_idDependsOnAsset == dwCurrentAssetID)
469 uint32 idAsset = (Pair.m_idAsset == dwCurrentAssetID) ? Pair.m_idDependsOnAsset : Pair.m_idAsset;
471 localDependencies.insert(idAsset);
473 m_Dependencies.erase(it);
475 RecursiveMove(idAsset, localDependencies);
476 bProcess = true;
477 break;
483 friend class CStatsToExcelExporter;
486 #define MAX_LODS 6
488 //////////////////////////////////////////////////////////////////////////
489 // Statistics about currently loaded level.
490 //////////////////////////////////////////////////////////////////////////
491 struct SCryEngineStats
493 struct StatObjInfo
495 int nVertices;
496 int nIndices;
497 int nIndicesPerLod[MAX_LODS];
498 int nMeshSize;
499 int nMeshSizeLoaded;
500 int nTextureSize;
501 int nPhysProxySize;
502 int nPhysProxySizeMax;
503 int nPhysPrimitives;
504 int nDrawCalls;
505 int nLods;
506 int nSubMeshCount;
507 int nNumRefs;
508 bool bSplitLods;
509 IStatObj* pStatObj;
511 struct CharacterInfo
513 CharacterInfo()
514 : nVertices(0)
515 , nIndices(0)
516 , nMeshSize(0)
517 , nTextureSize(0)
518 , nLods(0)
519 , nInstances(0)
520 , nPhysProxySize(0)
521 , pIDefaultSkeleton(nullptr)
523 ZeroArray(nVerticesPerLod);
524 ZeroArray(nIndicesPerLod);
527 int nVertices;
528 int nIndices;
529 int nVerticesPerLod[MAX_LODS];
530 int nIndicesPerLod[MAX_LODS];
531 int nMeshSize;
532 int nTextureSize;
533 int nLods;
534 int nInstances;
535 int nPhysProxySize;
536 IDefaultSkeleton* pIDefaultSkeleton;
538 struct MeshInfo
540 int nVerticesSum;
541 int nIndicesSum;
542 int nCount;
543 int nMeshSizeDev;
544 int nMeshSizeSys;
545 int nTextureSize;
546 const char* name;
548 struct MemInfo : public SCryEngineStatsGlobalMemInfo
550 MemInfo() : m_pSizer(0), m_pStats(0) {}
551 ~MemInfo() { SAFE_DELETE(m_pSizer); SAFE_DELETE(m_pStats); }
553 //int totalUsedInModules;
554 //int totalCodeAndStatic;
555 //int countedMemoryModules;
556 //uint64 totalAllocatedInModules;
557 //int totalNumAllocsInModules;
558 CrySizerImpl* m_pSizer;
559 CrySizerStats* m_pStats;
561 //std::vector<SCryEngineStatsModuleInfo> modules;
564 struct SBrushMemInfo
566 string brushName;
567 int usedTextureMemory;
568 int lodNum;
571 struct ProfilerInfo
573 string m_name;
574 string m_module;
576 //! Total time spent in this counter including time of child profilers in current frame.
577 float m_totalTime;
578 //! How many times this profiler counter was executed.
579 int m_count;
580 //! Displayed quantity (interpolated or average).
581 float m_displayedValue;
582 //! How variant this value.
583 float m_variance;
584 // min value
585 float m_min;
586 // max value
587 float m_max;
589 int m_mincount;
591 int m_maxcount;
595 struct SPeakProfilerInfo
597 ProfilerInfo profiler;
598 float peakValue;
599 float averageValue;
600 float variance;
601 int pageFaults; // Number of page faults at this frame.
602 int count; // Number of times called for peak.
603 float when; // when it added.
606 struct SModuleProfilerInfo
608 string name;
609 float overBugetRatio;
612 struct SEntityInfo
614 string name, models;
615 bool bInvisible, bHidden;
618 SCryEngineStats()
619 : nSummary_CodeAndStaticSize(0)
621 , nSummaryCharactersSize(0)
623 , nSummary_TextureSize(0)
624 , nSummary_UserTextureSize(0)
625 , nSummary_EngineTextureSize(0)
626 , nSummary_TexturesStreamingThroughput(0.0f)
627 , nSummaryEntityCount(0)
629 , nStatObj_SummaryTextureSize(0)
630 , nStatObj_SummaryMeshSize(0)
631 , nStatObj_TotalCount(0)
633 , nChar_SummaryMeshSize(0)
634 , nChar_SummaryTextureSize(0)
635 , nChar_NumInstances(0)
637 , fLevelLoadTime(0.0f)
638 , nSummary_TexturesPoolSize(0)
640 ISystem* pSystem = GetISystem();
641 I3DEngine* p3DEngine = pSystem->GetI3DEngine();
642 IRenderer* pRenderer = pSystem->GetIRenderer();
644 nTotalAllocatedMemory = CryMemoryGetAllocatedSize();
645 nSummaryMeshSize = 0;
646 nSummaryMeshCount = 0;
647 nAPI_MeshSize = 0;
649 if (pRenderer)
651 pRenderer->EF_Query(EFQ_Alloc_Mesh_SysMem, nSummaryMeshSize);
652 pRenderer->EF_Query(EFQ_Mesh_Count, nSummaryMeshCount);
653 pRenderer->EF_Query(EFQ_Alloc_APIMesh, nAPI_MeshSize);
656 nSummaryScriptSize = pSystem->GetIScriptSystem()->GetScriptAllocSize();
658 IMemoryManager::SProcessMemInfo procMeminfo;
659 GetISystem()->GetIMemoryManager()->GetProcessMemInfo(procMeminfo);
661 nWin32_WorkingSet = procMeminfo.WorkingSetSize;
662 nWin32_PeakWorkingSet = procMeminfo.PeakWorkingSetSize;
663 nWin32_PagefileUsage = procMeminfo.PagefileUsage;
664 nWin32_PeakPagefileUsage = procMeminfo.PeakPagefileUsage;
665 nWin32_PageFaultCount = procMeminfo.PageFaultCount;
667 fLevelLoadTime = gEnv->pSystem->GetIResourceManager()->GetLastLevelLoadTime().GetSeconds();
669 if (p3DEngine)
671 p3DEngine->FillDebugFPSInfo(infoFPS);
675 uint64 nWin32_WorkingSet;
676 uint64 nWin32_PeakWorkingSet;
677 uint64 nWin32_PagefileUsage;
678 uint64 nWin32_PeakPagefileUsage;
679 uint64 nWin32_PageFaultCount;
681 uint32 nTotalAllocatedMemory;
682 uint32 nSummary_CodeAndStaticSize; // Total size of all code plus static data
684 uint32 nSummaryScriptSize;
685 uint32 nSummaryCharactersSize;
686 uint32 nSummaryMeshCount;
687 uint32 nSummaryMeshSize;
688 uint32 nSummaryEntityCount;
690 uint32 nAPI_MeshSize; // Allocated by DirectX
692 size_t nSummary_TextureSize; // Total size of all textures
693 size_t nSummary_UserTextureSize; // Size of user textures, (from files...)
694 size_t nSummary_EngineTextureSize; // Dynamic Textures
695 size_t nSummary_TexturesPoolSize; // Dynamic Textures
696 float nSummary_TexturesStreamingThroughput; // in KB/sec
698 uint32 nStatObj_SummaryTextureSize;
699 uint32 nStatObj_SummaryMeshSize;
700 uint32 nStatObj_TotalCount; // Including sub-objects.
702 uint32 nChar_SummaryMeshSize;
703 uint32 nChar_SummaryTextureSize;
704 uint32 nChar_NumInstances;
705 SAnimMemoryTracker m_AnimMemoryTracking;
707 float fLevelLoadTime;
708 SDebugFPSInfo infoFPS;
710 std::vector<StatObjInfo> objects;
711 std::vector<CharacterInfo> characters;
712 std::vector<ITexture*> textures;
713 std::vector<MeshInfo> meshes;
714 std::vector<SBrushMemInfo> brushes;
715 std::vector<IMaterial*> materials;
716 std::vector<ProfilerInfo> profilers;
717 std::vector<SPeakProfilerInfo> peaks;
718 std::vector<SAnimationStatistics> animations;
719 std::vector<SEntityInfo> entities;
721 MemInfo memInfo;
724 inline bool CompareFrameProfilersValueStats(const SCryEngineStats::ProfilerInfo& p1, const SCryEngineStats::ProfilerInfo& p2)
726 return p1.m_displayedValue > p2.m_displayedValue;
729 class CEngineStats
731 CEngineStats(bool bDepends)
733 m_ResourceCollector.Enable(bDepends);
734 Collect();
737 private: // ----------------------------------------------------------------------------
739 // Collect all stats.
740 void Collect();
742 void CollectGeometry();
743 void CollectCharacters();
744 void CollectMaterialDependencies();
745 void CollectTextures();
746 void CollectMaterials();
747 void CollectVoxels();
748 void CollectRenderMeshes();
749 void CollectBrushes();
750 void CollectEntityDependencies();
751 void CollectEntities();
752 void CollectMemInfo();
753 void CollectProfileStatistics();
754 void CollectAnimations();
756 // Arguments:
757 // pObj - 0 is ignored
758 // pMat - 0 if IStatObjet Material should be used
759 void AddResource_StatObjWithLODs(IStatObj* pObj, CrySizerImpl& statObjTextureSizer, IMaterial* pMat = 0);
760 // If the object was not previously registered, returns true. If the object was already registered, returns false.
761 bool AddResource_SingleStatObj(IStatObj& rData);
763 void AddResource_CharInstance(ICharacterInstance& rData);
765 void AddResource_Material(IMaterial& rData, const bool bSubMaterial = false);
767 CResourceCollector m_ResourceCollector; // dependencies between assets
768 SCryEngineStats m_stats; //
770 friend void SaveLevelStats(IConsoleCmdArgs* pArgs);
773 //////////////////////////////////////////////////////////////////////////
774 void CEngineStats::Collect()
776 //////////////////////////////////////////////////////////////////////////
777 // Collect CGFs
778 //////////////////////////////////////////////////////////////////////////
779 CollectMemInfo(); // First of all collect memory info for modules (must be first).
780 CollectGeometry();
781 CollectCharacters();
782 CollectTextures();
783 CollectMaterials();
784 CollectRenderMeshes();
785 CollectBrushes();
786 CollectMaterialDependencies();
787 CollectEntityDependencies();
788 CollectEntities();
789 CollectProfileStatistics();
790 CollectAnimations();
793 inline bool CompareMaterialsByName(IMaterial* pMat1, IMaterial* pMat2)
795 return pMat1->GetName() > pMat2->GetName();
798 inline bool CompareTexturesBySizeFunc(ITexture* pTex1, ITexture* pTex2)
800 return pTex1->GetDataSize() > pTex2->GetDataSize();
802 inline bool CompareStatObjBySizeFunc(const SCryEngineStats::StatObjInfo& s1, const SCryEngineStats::StatObjInfo& s2)
804 return (s1.nMeshSize + s1.nTextureSize) > (s2.nMeshSize + s2.nTextureSize);
806 inline bool CompareCharactersBySizeFunc(const SCryEngineStats::CharacterInfo& s1, const SCryEngineStats::CharacterInfo& s2)
808 return (s1.nMeshSize + s1.nTextureSize) > (s2.nMeshSize + s2.nTextureSize);
810 inline bool CompareRenderMeshByTypeName(IRenderMesh* pRM1, IRenderMesh* pRM2)
812 return strcmp(pRM1->GetTypeName(), pRM2->GetTypeName()) < 0;
815 bool CEngineStats::AddResource_SingleStatObj(IStatObj& rData)
817 if (!m_ResourceCollector.AddResource(rData.GetFilePath()))
818 return false; // was already registered
820 // dependencies
822 if (rData.GetMaterial())
824 m_ResourceCollector.OpenDependencies(rData.GetFilePath());
826 AddResource_Material(*rData.GetMaterial());
828 m_ResourceCollector.CloseDependencies();
830 return true;
833 void CEngineStats::AddResource_CharInstance(ICharacterInstance& rData)
835 if (!m_ResourceCollector.AddResource(rData.GetFilePath()))
836 return; // was already registered
838 // dependencies
840 if (rData.GetIMaterial())
842 m_ResourceCollector.OpenDependencies(rData.GetFilePath());
844 AddResource_Material(*rData.GetIMaterial());
846 m_ResourceCollector.CloseDependencies();
850 void CEngineStats::AddResource_Material(IMaterial& rData, const bool bSubMaterial)
852 if (!bSubMaterial)
854 string sName = string(rData.GetName()) + ".mtl";
856 if (!m_ResourceCollector.AddResource(sName))
857 return; // was already registered
859 // dependencies
861 m_ResourceCollector.OpenDependencies(sName);
865 SShaderItem& rItem = rData.GetShaderItem();
867 uint32 dwSubMatCount = rData.GetSubMtlCount();
869 for (uint32 dwSubMat = 0; dwSubMat < dwSubMatCount; ++dwSubMat)
871 IMaterial* pSub = rData.GetSubMtl(dwSubMat);
873 if (pSub)
874 AddResource_Material(*pSub, true);
877 // this material
878 if (rItem.m_pShaderResources)
879 for (uint32 dwI = 0; dwI < EFTT_MAX; ++dwI)
881 SEfResTexture* pTex = rItem.m_pShaderResources->GetTexture(dwI);
883 if (!pTex)
884 continue;
886 uint32 dwSize = 0xffffffff;
888 if(pTex->m_Sampler.m_pITex)
890 dwSize = pTex->m_Sampler.m_pITex->GetDataSize();
892 assert(pTex->m_Name);
893 assert(pTex->m_Sampler.m_pITex->GetName());
895 string sTex = PathUtil::ToUnixPath(PathUtil::ReplaceExtension(pTex->m_Name,""));
896 string sSampler = PathUtil::ToUnixPath(PathUtil::ReplaceExtension(pTex->m_Sampler.m_pITex->GetName(),""));
898 if(stricmp(sTex.c_str(),sSampler.c_str())!=0)
900 char str[1024];
902 cry_sprintf(str,"IGNORE '%s' '%s'\n",sTex.c_str(),sSampler.c_str());
903 OutputDebugString(str);
904 dwSize=0;
905 // IGNORE 'Textures/gradf' 'Editor/Objects/gradf'
906 // IGNORE 'textures/cubemaps/auto_cubemap' '$RT_CM'
907 // IGNORE '' 'Textures/Defaults/White_ddn'
908 // IGNORE '' 'textures/defaults/oceanwaves_ddn'
909 // IGNORE '' 'textures/sprites/fire_blur1_ddn'
910 // IGNORE '' 'textures/sprites/fire_blur1_ddn'
911 // IGNORE '' 'Game/Objects/Library/Barriers/Sandbags/sandbags_ddn'
912 // IGNORE '' 'objects/characters/human/us/nanosuit/nanosuit_ddn'
913 // IGNORE '' 'objects/characters/human/us/nanosuit/nanosuit_ddndif'
916 m_ResourceCollector.AddResource(pTex->m_Sampler.m_pITex->GetName(),dwSize); // used texture
918 else
920 // CryLog("AddResource ITex (%d): '%s' '%s'",dwI,pTex->m_Name.c_str(),pTex->m_Sampler.m_pITex->GetName());
922 if (pTex->m_Sampler.m_pITex)
923 m_ResourceCollector.AddResource(pTex->m_Sampler.m_pITex->GetName(), dwSize);
924 // m_ResourceCollector.AddResource(pTex->m_Name,dwSize);
926 IDynTextureSource* pDynTextureSrc = pTex->m_Sampler.m_pDynTexSource;
927 if (pDynTextureSrc)
929 const char* pStr = pDynTextureSrc->GetSourceFilePath();
930 if (pStr)
931 m_ResourceCollector.AddResource(pStr);
936 if (!bSubMaterial)
937 m_ResourceCollector.CloseDependencies();
940 PREFAST_SUPPRESS_WARNING(6262)
941 void CEngineStats::AddResource_StatObjWithLODs(IStatObj* pObj, CrySizerImpl& statObjTextureSizer, IMaterial* pMat)
943 if (!pObj)
944 return;
946 // Make sure we have not already registered this object
947 if (!AddResource_SingleStatObj(*pObj))
948 return;
950 SCryEngineStats::StatObjInfo si;
952 si.pStatObj = pObj;
954 memset(si.nIndicesPerLod, 0, sizeof(si.nIndicesPerLod));
956 CrySizerImpl localTextureSizer;
958 si.nLods = 0;
959 si.nDrawCalls = 0;
960 si.nSubMeshCount = 0;
961 si.nNumRefs = 0;
962 si.bSplitLods = false;
963 // Analyze geom object.
965 si.nMeshSize = 0;
966 si.nTextureSize = 0;
967 si.nIndices = 0;
968 si.nVertices = 0;
969 si.nPhysProxySize = 0;
970 si.nPhysProxySizeMax = 0;
971 si.nPhysPrimitives = 0;
973 m_stats.nStatObj_TotalCount++;
975 IStatObj::SStatistics stats;
976 stats.pTextureSizer = &statObjTextureSizer;
977 stats.pTextureSizer2 = &localTextureSizer;
979 si.pStatObj->GetStatistics(stats);
981 si.nVertices = stats.nVertices;
982 si.nIndices = stats.nIndices;
983 for (int i = 0; i < MAX_STATOBJ_LODS_NUM; i++)
984 si.nIndicesPerLod[i] = stats.nIndicesPerLod[i];
985 si.nMeshSize = stats.nMeshSize;
986 si.nMeshSizeLoaded = stats.nMeshSizeLoaded;
987 si.nPhysProxySize = stats.nPhysProxySize;
988 si.nPhysProxySizeMax = stats.nPhysProxySizeMax;
989 si.nPhysPrimitives = stats.nPhysPrimitives;
990 si.nLods = stats.nLods;
991 si.nDrawCalls = stats.nDrawCalls;
992 si.nSubMeshCount = stats.nSubMeshCount;
993 si.nNumRefs = stats.nNumRefs;
994 si.bSplitLods = stats.bSplitLods;
996 si.nTextureSize = localTextureSizer.GetTotalSize();
998 m_stats.nStatObj_SummaryMeshSize += si.nMeshSize;
999 m_stats.objects.push_back(si);
1002 inline bool CompareAnimations(const SAnimationStatistics& p1, const SAnimationStatistics& p2)
1004 return p1.count > p2.count;
1007 //////////////////////////////////////////////////////////////////////////
1008 void CEngineStats::CollectAnimations()
1010 // ISystem* pSystem = GetISystem();
1012 m_stats.animations.clear();
1014 size_t count = pSystem->GetIAnimationSystem()->GetIAnimEvents()->GetGlobalAnimCount();
1016 //m_stats.animations.reserve(count);
1017 for (size_t i = 0; i < count; ++i) {
1018 SAnimationStatistics stat;
1019 pSystem->GetIAnimationSystem()->GetIAnimEvents()->GetGlobalAnimStatistics(i, stat);
1020 if (stat.count)
1021 m_stats.animations.push_back(stat);
1023 std::sort( m_stats.animations.begin(),m_stats.animations.end(),CompareAnimations );
1028 void GetObjectsByType(EERType objectType, std::vector<IRenderNode*>& lstInstances)
1030 I3DEngine* p3DEngine = GetISystem()->GetI3DEngine();
1032 const uint32 dwCount = p3DEngine->GetObjectsByType(objectType);
1033 if (dwCount)
1035 const uint32 numObjects = lstInstances.size();
1036 lstInstances.resize(numObjects + dwCount);
1037 p3DEngine->GetObjectsByType(objectType, &lstInstances[numObjects]);
1041 //////////////////////////////////////////////////////////////////////////
1042 PREFAST_SUPPRESS_WARNING(6262)
1043 void CEngineStats::CollectGeometry()
1045 ISystem* pSystem = GetISystem();
1046 I3DEngine* p3DEngine = pSystem->GetI3DEngine();
1048 m_stats.nStatObj_SummaryTextureSize = 0;
1049 m_stats.nStatObj_SummaryMeshSize = 0;
1050 m_stats.nStatObj_TotalCount = 0;
1052 CrySizerImpl statObjTextureSizer;
1055 SCryEngineStats::StatObjInfo si;
1056 si.nLods = 0;
1057 si.nSubMeshCount = 0;
1058 // Analyze geom object.
1059 si.nMeshSize = 0;
1060 si.nTextureSize = 0;
1061 si.nIndices = 0;
1062 si.nVertices = 0;
1063 si.nPhysProxySize = 0;
1064 si.nPhysPrimitives = 0;
1067 // iterate through all IStatObj
1069 int nObjCount = 0;
1071 p3DEngine->GetLoadedStatObjArray(0, nObjCount);
1072 if (nObjCount > 0)
1074 #ifdef _PREFAST_
1075 const int numStatObjs = nObjCount;
1076 #endif
1078 m_stats.objects.reserve(nObjCount);
1079 IStatObj** pObjects = new IStatObj*[nObjCount];
1080 p3DEngine->GetLoadedStatObjArray(pObjects, nObjCount);
1082 PREFAST_ASSUME(numStatObjs == nObjCount);
1083 for (int nCurObj = 0; nCurObj < nObjCount; nCurObj++)
1084 AddResource_StatObjWithLODs(pObjects[nCurObj], statObjTextureSizer, 0);
1086 delete[] pObjects;
1090 // iterate through all instances
1092 std::vector<IRenderNode*> lstInstances;
1094 GetObjectsByType(eERType_Brush, lstInstances);
1095 GetObjectsByType(eERType_Vegetation, lstInstances);
1096 GetObjectsByType(eERType_Light, lstInstances);
1097 GetObjectsByType(eERType_Decal, lstInstances);
1098 GetObjectsByType(eERType_Character, lstInstances);
1099 GetObjectsByType(eERType_MovableBrush, lstInstances);
1101 std::vector<IRenderNode*>::const_iterator itEnd = lstInstances.end();
1102 for (std::vector<IRenderNode*>::iterator it = lstInstances.begin(); it != itEnd; ++it)
1104 IRenderNode* pRenderNode = *it;
1106 if (IStatObj* pEntObject = pRenderNode->GetEntityStatObj())
1108 // if the object is not backed by a file, ignore it
1109 if(pEntObject->GetFilePath()[0] == 0)
1110 continue;
1112 AddResource_StatObjWithLODs(pEntObject, statObjTextureSizer, 0); // Ensure object is registered
1113 m_ResourceCollector.AddInstance(pEntObject->GetFilePath(), pRenderNode);
1115 if (IMaterial* pMat = pRenderNode->GetMaterial()) // if this rendernode overwrites the IStatObj material
1117 m_ResourceCollector.OpenDependencies(pEntObject->GetFilePath());
1118 AddResource_Material(*pMat); // to report the dependencies of this instance to the IStatObj
1119 m_ResourceCollector.CloseDependencies();
1123 if (ICharacterInstance* pCharInst = pRenderNode->GetEntityCharacter(0))
1125 AddResource_CharInstance(*pCharInst);
1126 m_ResourceCollector.AddInstance(pCharInst->GetFilePath(), pRenderNode);
1131 m_stats.nStatObj_SummaryTextureSize += statObjTextureSizer.GetTotalSize();
1132 std::sort(m_stats.objects.begin(), m_stats.objects.end(), CompareStatObjBySizeFunc);
1135 //////////////////////////////////////////////////////////////////////////
1136 void CEngineStats::CollectCharacters() PREFAST_SUPPRESS_WARNING(6262)
1138 ISystem* pSystem = GetISystem();
1140 m_stats.nChar_SummaryTextureSize = 0;
1141 m_stats.nChar_SummaryMeshSize = 0;
1142 m_stats.nChar_NumInstances = 0;
1144 CrySizerImpl totalCharactersTextureSizer;
1146 uint32 nObjCount = 0;
1147 ICharacterManager* pICharacterManager = pSystem->GetIAnimationSystem();
1149 if (!pICharacterManager)
1150 return;
1152 m_stats.m_AnimMemoryTracking = pICharacterManager->GetAnimMemoryTracker();
1154 pICharacterManager->GetLoadedModels(0, nObjCount);
1155 if (nObjCount > 0)
1157 #ifdef _PREFAST_
1158 const int numLoadedModels = nObjCount;
1159 #endif
1161 m_stats.characters.reserve(nObjCount);
1162 IDefaultSkeleton** pObjects = new IDefaultSkeleton*[nObjCount];
1163 pICharacterManager->GetLoadedModels(pObjects, nObjCount);
1164 PREFAST_ASSUME(numLoadedModels == nObjCount);
1165 for (uint32 nCurObj = 0; nCurObj < nObjCount; nCurObj++)
1167 if (!pObjects[nCurObj])
1168 continue;
1170 // Do not consider cga files characters (they are already considered to be static geometries)
1171 //if (stricmp(PathUtil::GetExt(pObjects[nCurObj]->GetModelFilePath()),"cga") == 0)
1172 // continue;
1174 SCryEngineStats::CharacterInfo si;
1175 si.pIDefaultSkeleton = pObjects[nCurObj];
1176 if (!si.pIDefaultSkeleton)
1177 continue;
1179 // dependencies
1180 // AddResource(*si.pModel);
1182 CrySizerImpl textureSizer;
1184 si.nInstances = gEnv->pCharacterManager->GetNumInstancesPerModel(*si.pIDefaultSkeleton);
1185 si.nLods = 1; //the base-model can have only 1 LOD
1186 si.nIndices = 0;
1187 si.nVertices = 0;
1188 memset(si.nVerticesPerLod, 0, sizeof(si.nVerticesPerLod));
1189 memset(si.nIndicesPerLod, 0, sizeof(si.nIndicesPerLod));
1191 CrySizerImpl meshSizer;
1193 si.nMeshSize = si.pIDefaultSkeleton->GetMeshMemoryUsage(&meshSizer);
1194 si.pIDefaultSkeleton->GetTextureMemoryUsage2(&textureSizer);
1195 si.pIDefaultSkeleton->GetTextureMemoryUsage2(&totalCharactersTextureSizer);
1196 si.nPhysProxySize = 0;
1197 bool bLod0_Found = false;
1198 IRenderMesh* pRenderMesh = si.pIDefaultSkeleton->GetIRenderMesh();
1199 if (pRenderMesh)
1201 if (!bLod0_Found)
1203 bLod0_Found = true;
1204 si.nVertices = pRenderMesh->GetVerticesCount();
1205 si.nIndices = pRenderMesh->GetIndicesCount();
1207 si.nVerticesPerLod[0] = pRenderMesh->GetVerticesCount();
1208 si.nIndicesPerLod[0] = pRenderMesh->GetIndicesCount();
1210 const phys_geometry* pgeom;
1212 for (int i = si.pIDefaultSkeleton->GetJointCount() - 1; i >= 0; i--)
1213 if (pgeom = si.pIDefaultSkeleton->GetJointPhysGeom((uint32)i))
1215 CrySizerImpl physMeshSizer;
1216 pgeom->pGeom->GetMemoryStatistics(&physMeshSizer);
1217 si.nPhysProxySize += physMeshSizer.GetTotalSize();
1220 si.nTextureSize = textureSizer.GetTotalSize();
1222 m_stats.nChar_SummaryMeshSize += si.nMeshSize;
1223 m_stats.characters.push_back(si);
1225 m_stats.nChar_NumInstances += si.nInstances;
1227 delete[]pObjects;
1229 m_stats.nChar_SummaryTextureSize = totalCharactersTextureSizer.GetTotalSize();
1230 std::sort(m_stats.characters.begin(), m_stats.characters.end(), CompareCharactersBySizeFunc);
1233 //////////////////////////////////////////////////////////////////////////
1234 void CEngineStats::CollectEntityDependencies()
1236 ISystem* pSystem = GetISystem();
1238 IEntitySystem* pEntitySystem = pSystem->GetIEntitySystem();
1240 IEntityItPtr it = pEntitySystem->GetEntityIterator();
1241 while (!it->IsEnd())
1243 IEntity* pEntity = it->Next();
1245 IMaterial* pMat = pEntity->GetMaterial();
1247 if (pMat)
1248 AddResource_Material(*pMat);
1250 uint32 dwSlotCount = pEntity->GetSlotCount();
1252 for (uint32 dwI = 0; dwI < dwSlotCount; ++dwI)
1254 SEntitySlotInfo slotInfo;
1256 if (pEntity->GetSlotInfo(dwI, slotInfo))
1258 if (slotInfo.pMaterial)
1259 AddResource_Material(*slotInfo.pMaterial);
1261 if (slotInfo.pCharacter)
1262 AddResource_CharInstance(*slotInfo.pCharacter);
1268 //////////////////////////////////////////////////////////////////////////
1269 void CEngineStats::CollectEntities()
1271 ISystem* pSystem = GetISystem();
1272 IEntitySystem* pEntitySystem = pSystem->GetIEntitySystem();
1273 IEntityItPtr it = pEntitySystem->GetEntityIterator();
1275 m_stats.entities.clear();
1277 while (!it->IsEnd())
1279 IEntity* pEntity = it->Next();
1280 SCryEngineStats::SEntityInfo entityInfo;
1282 entityInfo.name = pEntity->GetName();
1283 entityInfo.bInvisible = !pEntity->IsInvisible();
1284 entityInfo.bHidden = pEntity->IsHidden();
1286 for (size_t j = 0, jCount = pEntity->GetSlotCount(); j < jCount; ++j)
1288 if (pEntity->GetStatObj(j))
1290 entityInfo.models += string(pEntity->GetStatObj(j)->GetFilePath()) + string(";");
1294 m_stats.entities.push_back(entityInfo);
1297 m_stats.nSummaryEntityCount = m_stats.entities.size();
1299 //////////////////////////////////////////////////////////////////////////
1300 void CEngineStats::CollectBrushes()
1302 std::vector<IRenderNode*> lstInstances;
1303 GetObjectsByType(eERType_Brush, lstInstances);
1305 std::vector<IRenderNode*>::const_iterator itEnd = lstInstances.end();
1306 for (std::vector<IRenderNode*>::iterator it = lstInstances.begin(); it != itEnd; ++it)
1308 IRenderNode* pRenderNode = *it;
1310 if (IStatObj* pEntObject = pRenderNode->GetEntityStatObj())
1312 IMaterial* pMat = NULL;
1313 pMat = pRenderNode->GetMaterial();
1314 if (!pMat)
1316 pMat = pEntObject->GetMaterial();
1319 if (pMat)
1321 for (int idx = 0; idx < 8; idx++)
1323 if (IRenderMesh* pMesh = pRenderNode->GetRenderMesh(idx))
1325 SCryEngineStats::SBrushMemInfo brushInfo;
1326 brushInfo.brushName = string(pRenderNode->GetName());
1327 brushInfo.usedTextureMemory = pMesh->GetTextureMemoryUsage(pMat);
1328 brushInfo.lodNum = idx;
1329 m_stats.brushes.push_back(brushInfo);
1337 //////////////////////////////////////////////////////////////////////////
1338 void CEngineStats::CollectMaterialDependencies()
1340 ISystem* pSystem = GetISystem();
1341 I3DEngine* p3DEngine = pSystem->GetI3DEngine();
1343 IMaterialManager* pManager = p3DEngine->GetMaterialManager();
1345 uint32 nObjCount = 0;
1346 pManager->GetLoadedMaterials(0, nObjCount);
1348 if (nObjCount > 0)
1350 std::vector<IMaterial*> Materials;
1352 Materials.resize(nObjCount);
1354 pManager->GetLoadedMaterials(&Materials[0], nObjCount);
1356 std::vector<IMaterial*>::const_iterator it, end = Materials.end();
1358 for (it = Materials.begin(); it != end; ++it)
1360 IMaterial* pMat = *it;
1362 AddResource_Material(*pMat);
1367 //////////////////////////////////////////////////////////////////////////
1368 void CEngineStats::CollectTextures()
1370 ISystem* pSystem = GetISystem();
1371 IRenderer* pRenderer = pSystem->GetIRenderer();
1372 if (!pRenderer)
1374 return;
1377 m_stats.nSummary_TextureSize = 0;
1378 m_stats.nSummary_UserTextureSize = 0;
1379 m_stats.nSummary_EngineTextureSize = 0;
1380 m_stats.nSummary_TexturesStreamingThroughput = 0;
1382 pRenderer->EF_Query(EFQ_TexturesPoolSize, m_stats.nSummary_TexturesPoolSize);
1384 m_stats.textures.clear();
1385 SRendererQueryGetAllTexturesParam query;
1386 pRenderer->EF_Query(EFQ_GetAllTextures, query);
1387 if (query.pTextures)
1389 m_stats.textures.reserve(query.numTextures);
1391 for (uint32 i = 0; i < query.numTextures; i++)
1393 ITexture* pTexture = query.pTextures[i];
1394 uint32 nTexSize = pTexture->GetDataSize();
1395 if (nTexSize > 0)
1397 m_stats.textures.push_back(pTexture);
1398 m_stats.nSummary_TextureSize += nTexSize;
1400 if (pTexture->GetFlags() & (FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL | FT_USAGE_UNORDERED_ACCESS))
1402 int numCopies = 1;
1404 numCopies += (pTexture->GetFlags() & FT_STAGE_UPLOAD ) ? 1 : 0;
1405 numCopies += (pTexture->GetFlags() & FT_STAGE_READBACK) ? 1 : 0;
1407 m_stats.nSummary_EngineTextureSize += size_t(nTexSize) * numCopies;
1409 else
1411 m_stats.nSummary_UserTextureSize += nTexSize;
1416 std::sort(m_stats.textures.begin(), m_stats.textures.end(), CompareTexturesBySizeFunc);
1419 pRenderer->EF_Query(EFQ_GetAllTexturesRelease, query);
1421 STextureStreamingStats stats(false);
1422 m_stats.nSummary_TexturesStreamingThroughput = 0;
1423 pRenderer->EF_Query(EFQ_GetTexStreamingInfo, stats);
1424 m_stats.nSummary_TexturesStreamingThroughput = (float)stats.nThroughput;
1427 //////////////////////////////////////////////////////////////////////////
1428 void CEngineStats::CollectMaterials()
1430 ISystem* pSystem = GetISystem();
1431 I3DEngine* p3DEngine = pSystem->GetI3DEngine();
1433 IMaterialManager* pManager = p3DEngine->GetMaterialManager();
1435 uint32 nObjCount = 0;
1436 pManager->GetLoadedMaterials(0, nObjCount);
1438 m_stats.materials.resize(nObjCount);
1440 if (nObjCount > 0)
1442 pManager->GetLoadedMaterials(&m_stats.materials[0], nObjCount);
1444 std::sort(m_stats.materials.begin(), m_stats.materials.end(), CompareMaterialsByName);
1448 //////////////////////////////////////////////////////////////////////////
1449 void CEngineStats::CollectRenderMeshes()
1451 ISystem* pSystem = GetISystem();
1452 IRenderer* pRenderer = pSystem->GetIRenderer();
1453 if (!pRenderer)
1455 return;
1458 m_stats.meshes.clear();
1459 m_stats.meshes.reserve(100);
1461 int nVertices = 0;
1462 int nIndices = 0;
1464 IRenderMesh** pMeshes = NULL;
1465 uint32 nCount = 0;
1466 pRenderer->EF_Query(EFQ_GetAllMeshes, pMeshes, nCount);
1467 if (nCount > 0 && pMeshes)
1469 // Sort meshes by name.
1470 std::sort(pMeshes, pMeshes + nCount, CompareRenderMeshByTypeName);
1472 CrySizerImpl* pTextureSizer = new CrySizerImpl();
1474 int nInstances = 0;
1475 int nMeshSizeSys = 0;
1476 int nMeshSizeDev = 0;
1477 const char* sMeshName = 0;
1478 const char* sLastMeshName = "";
1479 for (size_t i = 0; i < nCount; i++)
1481 IRenderMesh* pMesh = pMeshes[i];
1482 sMeshName = pMesh->GetTypeName();
1484 if ((strcmp(sMeshName, sLastMeshName) != 0 && i != 0))
1486 SCryEngineStats::MeshInfo mi;
1487 mi.nCount = nInstances;
1488 mi.nVerticesSum = nVertices;
1489 mi.nIndicesSum = nIndices;
1490 mi.nMeshSizeDev = nMeshSizeDev;
1491 mi.nMeshSizeSys = nMeshSizeSys;
1492 mi.nTextureSize = (int)pTextureSizer->GetTotalSize();
1493 mi.name = sLastMeshName;
1494 m_stats.meshes.push_back(mi);
1496 delete pTextureSizer;
1497 pTextureSizer = new CrySizerImpl();
1498 nInstances = 0;
1499 nMeshSizeSys = 0;
1500 nMeshSizeDev = 0;
1501 nVertices = 0;
1502 nIndices = 0;
1504 sLastMeshName = sMeshName;
1505 nMeshSizeSys += pMesh->GetMemoryUsage(0, IRenderMesh::MEM_USAGE_ONLY_SYSTEM); // Collect System+Video memory usage.
1506 nMeshSizeDev += pMesh->GetMemoryUsage(0, IRenderMesh::MEM_USAGE_ONLY_VIDEO); // Collect System+Video memory usage.
1508 // Vlad: checking default material in render mesh makes little sense, meshes can be used with any material
1509 //pMesh->GetTextureMemoryUsage(pMesh->GetMaterial(), pTextureSizer);
1511 nVertices += pMesh->GetVerticesCount();
1512 nIndices += pMesh->GetIndicesCount();
1514 nInstances++;
1516 if (nCount > 0 && sMeshName)
1518 SCryEngineStats::MeshInfo mi;
1519 mi.nCount = nInstances;
1520 mi.nVerticesSum = nVertices;
1521 mi.nIndicesSum = nIndices;
1522 mi.nMeshSizeSys = nMeshSizeSys;
1523 mi.nMeshSizeDev = nMeshSizeDev;
1524 mi.nTextureSize = (int)pTextureSizer->GetTotalSize();
1525 mi.name = sMeshName;
1526 m_stats.meshes.push_back(mi);
1529 delete pTextureSizer;
1531 delete[]pMeshes;
1535 //////////////////////////////////////////////////////////////////////////
1536 void CEngineStats::CollectVoxels()
1540 //////////////////////////////////////////////////////////////////////////
1541 void CEngineStats::CollectProfileStatistics()
1543 ISystem* pSystem = GetISystem();
1544 auto pProfiler = pSystem->GetLegacyProfilerInterface();
1545 if (pProfiler == nullptr)
1546 return;
1548 pProfiler->AcquireReadAccess();
1550 m_stats.profilers.clear();
1552 int need = 0;
1553 for (auto pTracker : *pProfiler->GetActiveTrackers())
1555 if (pTracker->count.Average() > 0 && pTracker->totalValue.Average() > 0.0f)
1556 ++need;
1559 m_stats.profilers.resize(need);
1560 int i = 0;
1561 for (auto pTracker : *pProfiler->GetActiveTrackers())
1563 if (pTracker->count.Average() > 0 && pTracker->totalValue.Average() > 0.0f)
1565 m_stats.profilers[i].m_count = pos_round(pTracker->count.Average());
1566 m_stats.profilers[i].m_displayedValue = pTracker->selfValue.Average();
1567 m_stats.profilers[i].m_name = pTracker->pDescription->szEventname;
1568 m_stats.profilers[i].m_module = pProfiler->GetModuleName(pTracker);
1569 m_stats.profilers[i].m_totalTime = pTracker->totalValue.Average();
1570 m_stats.profilers[i].m_variance = pTracker->selfValue.Variance();
1571 m_stats.profilers[i].m_min = pTracker->selfValue.Min();
1572 m_stats.profilers[i].m_max = pTracker->selfValue.Max();
1573 m_stats.profilers[i].m_mincount = pos_round(pTracker->count.Min());
1574 m_stats.profilers[i].m_maxcount = pos_round(pTracker->count.Max());
1575 ++i;
1579 std::sort(m_stats.profilers.begin(), m_stats.profilers.end(), CompareFrameProfilersValueStats);
1581 // fill peaks
1582 auto& peaks = *pProfiler->GetPeakRecords();
1583 const uint32 peakCount = peaks.size();
1584 m_stats.peaks.resize(peakCount);
1585 for (uint32 i = 0; i < peakCount; ++i)
1587 const SPeakRecord* pPeak = &peaks[i];
1588 SProfilingSectionTracker* pTracker = pPeak->pTracker;
1590 m_stats.peaks[i].peakValue = pPeak->peakValue;
1591 m_stats.peaks[i].averageValue = pPeak->averageValue;
1592 m_stats.peaks[i].variance = pPeak->variance;
1593 m_stats.peaks[i].pageFaults = pPeak->pageFaults; // Number of page faults at this frame.
1594 m_stats.peaks[i].count = pPeak->count; // Number of times called for peak.
1595 m_stats.peaks[i].when = pPeak->timeSeconds; // when it added.
1597 m_stats.peaks[i].profiler.m_count = pos_round(pTracker->count.Average());
1598 m_stats.peaks[i].profiler.m_displayedValue = pTracker->selfValue.Average();
1599 m_stats.peaks[i].profiler.m_name = pTracker->pDescription->szEventname;
1600 m_stats.peaks[i].profiler.m_module = pProfiler->GetModuleName(pTracker);
1601 m_stats.peaks[i].profiler.m_totalTime = pTracker->totalValue.Average();
1602 m_stats.peaks[i].profiler.m_variance = pTracker->selfValue.Variance();
1603 m_stats.peaks[i].profiler.m_min = pTracker->selfValue.Min();
1604 m_stats.peaks[i].profiler.m_max = pTracker->selfValue.Max();
1605 m_stats.peaks[i].profiler.m_mincount = pos_round(pTracker->count.Min());
1606 m_stats.peaks[i].profiler.m_maxcount = pos_round(pTracker->count.Max());
1609 pProfiler->ReleaseReadAccess();
1612 //////////////////////////////////////////////////////////////////////////
1613 #if CRY_PLATFORM_WINDOWS
1615 /*static*/ bool QueryModuleMemoryInfo(SCryEngineStatsModuleInfo& moduleInfo, int index)
1617 HMODULE hModule = GetModuleHandle(moduleInfo.name);
1618 if (!hModule)
1619 return false;
1621 typedef void (* PFN_MODULEMEMORY)(CryModuleMemoryInfo*);
1622 PFN_MODULEMEMORY fpCryModuleGetAllocatedMemory = (PFN_MODULEMEMORY)::GetProcAddress(hModule, "CryModuleGetMemoryInfo");
1623 if (!fpCryModuleGetAllocatedMemory)
1624 return false;
1626 PEHeader_DLL pe_header;
1627 PEHeader_DLL* header = &pe_header;
1629 const IMAGE_DOS_HEADER* dos_head = (IMAGE_DOS_HEADER*)hModule;
1630 if (dos_head->e_magic != IMAGE_DOS_SIGNATURE)
1632 // Wrong pointer, not to PE header.
1633 return false;
1635 header = (PEHeader_DLL*)(const void*)((char*)dos_head + dos_head->e_lfanew);
1636 moduleInfo.moduleStaticSize = header->opt_head.SizeOfInitializedData + header->opt_head.SizeOfUninitializedData + header->opt_head.SizeOfCode + header->opt_head.SizeOfHeaders;
1637 moduleInfo.SizeOfCode = header->opt_head.SizeOfCode;
1638 moduleInfo.SizeOfInitializedData = header->opt_head.SizeOfInitializedData;
1639 moduleInfo.SizeOfUninitializedData = header->opt_head.SizeOfUninitializedData;
1641 fpCryModuleGetAllocatedMemory(&moduleInfo.memInfo);
1643 moduleInfo.usedInModule = (int)(moduleInfo.memInfo.allocated - moduleInfo.memInfo.freed);
1644 return true;
1647 #else //Another platform
1649 /*static */ bool QueryModuleMemoryInfo(SCryEngineStatsModuleInfo& moduleInfo, int index)
1651 //CryModuleGetMemoryInfo( &moduleInfo.memInfo, (ECryModule)index );
1652 CryModuleGetMemoryInfo(&moduleInfo.memInfo);
1653 moduleInfo.usedInModule = (int)(moduleInfo.memInfo.allocated - moduleInfo.memInfo.freed);
1654 return true;
1657 #endif
1659 //////////////////////////////////////////////////////////////////////////
1660 void CEngineStats::CollectMemInfo()
1662 m_stats.memInfo.totalUsedInModules = 0;
1663 m_stats.memInfo.totalCodeAndStatic = 0;
1664 m_stats.memInfo.countedMemoryModules = 0;
1665 m_stats.memInfo.totalAllocatedInModules = 0;
1666 m_stats.memInfo.totalNumAllocsInModules = 0;
1668 const std::vector<string>& moduleNames = GetModuleNames();
1669 const int numModules = moduleNames.size();
1671 //////////////////////////////////////////////////////////////////////////
1672 // Hardcoded value for the OS memory allocation.
1673 //////////////////////////////////////////////////////////////////////////
1674 for (int i = 0; i < numModules; i++)
1676 const char* szModule = moduleNames[i].c_str();
1678 SCryEngineStatsModuleInfo moduleInfo;
1679 ZeroStruct(moduleInfo.memInfo);
1680 moduleInfo.moduleStaticSize = moduleInfo.SizeOfCode = moduleInfo.SizeOfInitializedData = moduleInfo.SizeOfUninitializedData = moduleInfo.usedInModule = 0;
1681 moduleInfo.name = szModule;
1683 if (!QueryModuleMemoryInfo(moduleInfo, i))
1684 continue;
1686 m_stats.memInfo.totalNumAllocsInModules += moduleInfo.memInfo.num_allocations;
1687 m_stats.memInfo.totalAllocatedInModules += moduleInfo.memInfo.allocated;
1688 m_stats.memInfo.totalUsedInModules += moduleInfo.usedInModule;
1689 m_stats.memInfo.countedMemoryModules++;
1690 m_stats.memInfo.totalCodeAndStatic += moduleInfo.moduleStaticSize;
1692 m_stats.memInfo.modules.push_back(moduleInfo);
1695 m_stats.memInfo.m_pSizer = new CrySizerImpl();
1696 ((CSystem*)GetISystem())->CollectMemStats(m_stats.memInfo.m_pSizer, CSystem::nMSP_ForDump);
1697 m_stats.memInfo.m_pStats = new CrySizerStats(m_stats.memInfo.m_pSizer);
1701 // Exports engine stats to the Excel.
1702 class CStatsToExcelExporter
1704 public:
1705 enum CellFlags
1707 CELL_BOLD = 0x0001,
1708 CELL_CENTERED = 0x0002,
1710 void ExportToFile(SCryEngineStats& stats, const char* filename);
1711 void ExportDependenciesToFile(CResourceCollector& stats, const char* filename);
1712 void Export(XmlNodeRef Workbook, SCryEngineStats& stats);
1714 private:
1715 void ExportSummary(SCryEngineStats& stats);
1716 void ExportStatObjects(SCryEngineStats& stats);
1717 void ExportCharacters(SCryEngineStats& stats);
1718 void ExportRenderMeshes(SCryEngineStats& stats);
1719 void ExportBrushes(SCryEngineStats& stats);
1720 void ExportTextures(SCryEngineStats& stats);
1721 void ExportMaterials(SCryEngineStats& stats);
1722 void ExportMemStats(SCryEngineStats& stats);
1723 void ExportMemInfo(SCryEngineStats& stats);
1724 void ExportTimeDemoInfo();
1725 void ExportStreamingInfo(SStreamEngineStatistics& stats);
1726 void ExportAnimationInfo(SCryEngineStats& stats);
1727 void ExportDependencies(CResourceCollector& stats);
1728 void ExportProfilerStatistics(SCryEngineStats& stats);
1729 void ExportAnimationStatistics(SCryEngineStats& stats);
1730 void ExportFPSBuckets();
1731 void ExportPhysEntStatistics(SCryEngineStats& stats);
1732 void ExportEntitiesStatistics(SCryEngineStats& stats);
1734 void InitExcelWorkbook(XmlNodeRef Workbook);
1736 XmlNodeRef NewWorksheet(const char* name);
1737 void FreezeFirstRow();
1738 void AutoFilter(int nRow, int nNumColumns);
1739 void AddCell(float number);
1740 void AddCell(int number);
1741 void AddCell(uint32 number);
1742 void AddCell(uint64 number) { AddCell((uint32)number); };
1743 void AddCell(int64 number) { AddCell((int)number); };
1744 void AddCell(const char* str, int flags = 0);
1745 void AddCellAtIndex(int nIndex, const char* str, int flags = 0);
1746 void SetCellFlags(XmlNodeRef cell, int flags);
1747 void AddRow();
1748 void AddCell_SumOfRows(int nRows);
1749 string GetXmlHeader();
1751 private:
1752 XmlNodeRef m_Workbook;
1753 XmlNodeRef m_CurrTable;
1754 XmlNodeRef m_CurrWorksheet;
1755 XmlNodeRef m_CurrRow;
1756 XmlNodeRef m_CurrCell;
1759 //////////////////////////////////////////////////////////////////////////
1760 string CStatsToExcelExporter::GetXmlHeader()
1762 return "<?xml version=\"1.0\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n";
1765 //////////////////////////////////////////////////////////////////////////
1766 void CStatsToExcelExporter::InitExcelWorkbook(XmlNodeRef Workbook)
1768 m_Workbook = Workbook;
1769 m_Workbook->setTag("Workbook");
1770 m_Workbook->setAttr("xmlns", "urn:schemas-microsoft-com:office:spreadsheet");
1771 XmlNodeRef ExcelWorkbook = Workbook->newChild("ExcelWorkbook");
1772 ExcelWorkbook->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
1774 XmlNodeRef Styles = m_Workbook->newChild("Styles");
1776 // Style s25
1777 // Bold header, With Background Color.
1778 XmlNodeRef Style = Styles->newChild("Style");
1779 Style->setAttr("ss:ID", "s25");
1780 XmlNodeRef StyleFont = Style->newChild("Font");
1781 StyleFont->setAttr("x:CharSet", "204");
1782 StyleFont->setAttr("x:Family", "Swiss");
1783 StyleFont->setAttr("ss:Bold", "1");
1784 XmlNodeRef StyleInterior = Style->newChild("Interior");
1785 StyleInterior->setAttr("ss:Color", "#00FF00");
1786 StyleInterior->setAttr("ss:Pattern", "Solid");
1787 XmlNodeRef NumberFormat = Style->newChild("NumberFormat");
1788 NumberFormat->setAttr("ss:Format", "#,##0");
1791 // Style s26
1792 // Bold/Centered header.
1793 XmlNodeRef Style = Styles->newChild("Style");
1794 Style->setAttr("ss:ID", "s26");
1795 XmlNodeRef StyleFont = Style->newChild("Font");
1796 StyleFont->setAttr("x:CharSet", "204");
1797 StyleFont->setAttr("x:Family", "Swiss");
1798 StyleFont->setAttr("ss:Bold", "1");
1799 XmlNodeRef StyleInterior = Style->newChild("Interior");
1800 StyleInterior->setAttr("ss:Color", "#FFFF99");
1801 StyleInterior->setAttr("ss:Pattern", "Solid");
1802 XmlNodeRef Alignment = Style->newChild("Alignment");
1803 Alignment->setAttr("ss:Horizontal", "Center");
1804 Alignment->setAttr("ss:Vertical", "Bottom");
1807 // Style s20
1808 // Centered
1809 XmlNodeRef Style = Styles->newChild("Style");
1810 Style->setAttr("ss:ID", "s20");
1811 XmlNodeRef Alignment = Style->newChild("Alignment");
1812 Alignment->setAttr("ss:Horizontal", "Center");
1813 Alignment->setAttr("ss:Vertical", "Bottom");
1816 // Style s21
1817 // Bold
1818 XmlNodeRef Style = Styles->newChild("Style");
1819 Style->setAttr("ss:ID", "s21");
1820 XmlNodeRef StyleFont = Style->newChild("Font");
1821 StyleFont->setAttr("x:CharSet", "204");
1822 StyleFont->setAttr("x:Family", "Swiss");
1823 StyleFont->setAttr("ss:Bold", "1");
1826 // Style s22
1827 // Centered, Integer Number format
1828 XmlNodeRef Style = Styles->newChild("Style");
1829 Style->setAttr("ss:ID", "s22");
1830 XmlNodeRef Alignment = Style->newChild("Alignment");
1831 Alignment->setAttr("ss:Horizontal", "Center");
1832 Alignment->setAttr("ss:Vertical", "Bottom");
1833 XmlNodeRef NumberFormat = Style->newChild("NumberFormat");
1834 NumberFormat->setAttr("ss:Format", "#,##0");
1837 // Style s23
1838 // Centered, Float Number format
1839 XmlNodeRef Style = Styles->newChild("Style");
1840 Style->setAttr("ss:ID", "s23");
1841 XmlNodeRef Alignment = Style->newChild("Alignment");
1842 Alignment->setAttr("ss:Horizontal", "Center");
1843 Alignment->setAttr("ss:Vertical", "Bottom");
1844 //XmlNodeRef NumberFormat = Style->newChild( "NumberFormat" );
1845 //NumberFormat->setAttr( "ss:Format","#,##0" );
1849 <Style ss:ID="s25">
1850 <Font x:CharSet="204" x:Family="Swiss" ss:Bold="1"/>
1851 <Interior ss:Color="#FFFF99" ss:Pattern="Solid"/>
1852 </Style>
1856 //////////////////////////////////////////////////////////////////////////
1857 XmlNodeRef CStatsToExcelExporter::NewWorksheet(const char* name)
1859 m_CurrWorksheet = m_Workbook->newChild("Worksheet");
1860 m_CurrWorksheet->setAttr("ss:Name", name);
1861 m_CurrTable = m_CurrWorksheet->newChild("Table");
1862 return m_CurrWorksheet;
1865 //////////////////////////////////////////////////////////////////////////
1866 void CStatsToExcelExporter::FreezeFirstRow()
1868 XmlNodeRef options = m_CurrWorksheet->newChild("WorksheetOptions");
1869 options->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
1870 options->newChild("FreezePanes");
1871 options->newChild("FrozenNoSplit");
1872 options->newChild("SplitHorizontal")->setContent("1");
1873 options->newChild("TopRowBottomPane")->setContent("1");
1874 options->newChild("ActivePane")->setContent("2");
1877 //////////////////////////////////////////////////////////////////////////
1878 void CStatsToExcelExporter::AutoFilter(int nRow, int nNumColumns)
1880 XmlNodeRef options = m_CurrWorksheet->newChild("AutoFilter");
1881 options->setAttr("xmlns", "urn:schemas-microsoft-com:office:excel");
1882 string range;
1883 range.Format("R%dC1:R%dC%d", nRow, nRow, nNumColumns);
1884 options->setAttr("x:Range", range); // x:Range="R1C1:R1C8"
1887 //////////////////////////////////////////////////////////////////////////
1888 void CStatsToExcelExporter::AddRow()
1890 m_CurrRow = m_CurrTable->newChild("Row");
1893 //////////////////////////////////////////////////////////////////////////
1894 void CStatsToExcelExporter::AddCell_SumOfRows(int nRows)
1896 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1897 XmlNodeRef data = cell->newChild("Data");
1898 data->setAttr("ss:Type", "Number");
1899 data->setContent("0");
1900 m_CurrCell = cell;
1902 if (nRows > 0)
1904 char buf[128];
1905 cry_sprintf(buf, "=SUM(R[-%d]C:R[-1]C)", nRows);
1906 m_CurrCell->setAttr("ss:Formula", buf);
1910 //////////////////////////////////////////////////////////////////////////
1911 void CStatsToExcelExporter::AddCell(float number)
1913 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1914 cell->setAttr("ss:StyleID", "s23"); // Centered
1915 XmlNodeRef data = cell->newChild("Data");
1916 data->setAttr("ss:Type", "Number");
1917 char str[128];
1918 cry_sprintf(str, "%.3f", number);
1919 data->setContent(str);
1920 m_CurrCell = cell;
1923 //////////////////////////////////////////////////////////////////////////
1924 void CStatsToExcelExporter::AddCell(int number)
1926 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1927 cell->setAttr("ss:StyleID", "s22"); // Centered
1928 XmlNodeRef data = cell->newChild("Data");
1929 data->setAttr("ss:Type", "Number");
1930 char str[128];
1931 cry_sprintf(str, "%d", number);
1932 data->setContent(str);
1933 m_CurrCell = cell;
1936 //////////////////////////////////////////////////////////////////////////
1937 void CStatsToExcelExporter::AddCell(uint32 number)
1939 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1940 cell->setAttr("ss:StyleID", "s22"); // Centered
1941 XmlNodeRef data = cell->newChild("Data");
1942 data->setAttr("ss:Type", "Number");
1943 char str[128];
1944 cry_sprintf(str, "%u", number);
1945 data->setContent(str);
1946 m_CurrCell = cell;
1949 //////////////////////////////////////////////////////////////////////////
1950 void CStatsToExcelExporter::AddCell(const char* str, int nFlags)
1952 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1953 XmlNodeRef data = cell->newChild("Data");
1954 data->setAttr("ss:Type", "String");
1955 data->setContent(str);
1956 SetCellFlags(cell, nFlags);
1957 m_CurrCell = cell;
1960 //////////////////////////////////////////////////////////////////////////
1961 void CStatsToExcelExporter::AddCellAtIndex(int nIndex, const char* str, int nFlags)
1963 XmlNodeRef cell = m_CurrRow->newChild("Cell");
1964 cell->setAttr("ss:Index", nIndex);
1965 XmlNodeRef data = cell->newChild("Data");
1966 data->setAttr("ss:Type", "String");
1967 data->setContent(str);
1968 SetCellFlags(cell, nFlags);
1969 m_CurrCell = cell;
1972 //////////////////////////////////////////////////////////////////////////
1973 void CStatsToExcelExporter::SetCellFlags(XmlNodeRef cell, int flags)
1975 if (flags & CELL_BOLD)
1977 if (flags & CELL_CENTERED)
1978 cell->setAttr("ss:StyleID", "s26");
1979 else
1980 cell->setAttr("ss:StyleID", "s21");
1982 else
1984 if (flags & CELL_CENTERED)
1985 cell->setAttr("ss:StyleID", "s20");
1989 static FILE* HandleFileExport(const char* filename)
1991 CryPathString directory;
1992 gEnv->pCryPak->AdjustFileName(g_szTestResults, directory, ICryPak::FLAGS_PATH_REAL | ICryPak::FLAGS_FOR_WRITING | ICryPak::FLAGS_ADD_TRAILING_SLASH);
1993 gEnv->pCryPak->MakeDir(directory);
1994 CryPathString path;
1995 gEnv->pCryPak->AdjustFileName(directory + filename, path, ICryPak::FLAGS_PATH_REAL | ICryPak::FLAGS_FOR_WRITING);
1997 return fopen(path, "wb");
2000 //////////////////////////////////////////////////////////////////////////
2001 void CStatsToExcelExporter::ExportToFile(SCryEngineStats& stats, const char* filename)
2003 XmlNodeRef Workbook = GetISystem()->CreateXmlNode("Workbook");
2004 Export(Workbook, stats);
2005 string xml = GetXmlHeader();
2006 // xml = xml + Workbook->getXML();
2007 FILE* file = HandleFileExport(filename);
2008 if (file)
2010 fprintf(file, "%s", xml.c_str());
2011 Workbook->saveToFile(filename, 8 * 1024 /*chunksize*/, file);
2012 fclose(file);
2016 //////////////////////////////////////////////////////////////////////////
2017 void CStatsToExcelExporter::ExportDependenciesToFile(CResourceCollector& stats, const char* filename)
2019 XmlNodeRef Workbook = GetISystem()->CreateXmlNode("Workbook");
2022 InitExcelWorkbook(Workbook);
2023 ExportDependencies(stats);
2026 string xml = GetXmlHeader();
2027 // xml = xml + Workbook->getXML();
2029 FILE* file = HandleFileExport(filename);
2030 if (file)
2032 fprintf(file, "%s", xml.c_str());
2033 Workbook->saveToFile(filename, 8 * 1024 /*chunksize*/, file);
2034 fclose(file);
2038 //////////////////////////////////////////////////////////////////////////
2039 void CStatsToExcelExporter::Export(XmlNodeRef Workbook, SCryEngineStats& stats)
2041 bool bPhysWasActive = gEnv->pSystem->SetThreadState(ESubsys_Physics, false) != 0;
2042 InitExcelWorkbook(Workbook);
2043 ExportSummary(stats);
2044 ExportMemInfo(stats);
2045 ExportMemStats(stats);
2046 ExportStatObjects(stats);
2047 ExportCharacters(stats);
2048 ExportRenderMeshes(stats);
2049 ExportBrushes(stats);
2050 ExportTextures(stats);
2051 ExportMaterials(stats);
2052 ExportTimeDemoInfo();
2053 ExportProfilerStatistics(stats);
2054 ExportAnimationStatistics(stats);
2055 ExportPhysEntStatistics(stats);
2056 ExportEntitiesStatistics(stats);
2057 ExportAnimationInfo(stats);
2059 SStreamEngineStatistics& streamingStats = gEnv->pSystem->GetStreamEngine()->GetStreamingStatistics();
2060 ExportStreamingInfo(streamingStats);
2061 gEnv->pSystem->SetThreadState(ESubsys_Physics, bPhysWasActive);
2064 //////////////////////////////////////////////////////////////////////////
2065 void CStatsToExcelExporter::ExportSummary(SCryEngineStats& stats)
2067 // Make summary sheet.en
2068 NewWorksheet("Summary");
2070 XmlNodeRef Column;
2071 Column = m_CurrTable->newChild("Column");
2072 Column->setAttr("ss:Width", 200);
2073 Column = m_CurrTable->newChild("Column");
2074 Column->setAttr("ss:Width", 100);
2075 Column = m_CurrTable->newChild("Column");
2076 Column->setAttr("ss:Width", 100);
2077 Column = m_CurrTable->newChild("Column");
2078 Column->setAttr("ss:Width", 100);
2079 Column = m_CurrTable->newChild("Column");
2080 Column->setAttr("ss:Width", 100);
2081 Column = m_CurrTable->newChild("Column");
2082 Column->setAttr("ss:Width", 100);
2083 Column = m_CurrTable->newChild("Column");
2084 Column->setAttr("ss:Width", 100);
2086 // get version
2087 const SFileVersion& ver = GetISystem()->GetFileVersion();
2088 char sVersion[128];
2089 ver.ToString(sVersion);
2090 string levelName = "no_level";
2091 ICVar* sv_map = gEnv->pConsole->GetCVar("sv_map");
2092 if (sv_map)
2093 levelName = sv_map->GetString();
2095 AddRow();
2096 AddCell(string("CryEngine Version ") + sVersion);
2097 AddRow();
2098 AddCell(string("Level ") + levelName);
2099 AddRow();
2100 #if CRY_PLATFORM_WINDOWS
2101 AddCell("Running in 64bit version");
2102 #endif
2103 AddRow();
2104 AddCell("Level Load Time (sec):");
2105 AddCell((int)stats.fLevelLoadTime);
2106 AddRow();
2107 AddRow();
2108 AddCell("Average\\Min\\Max (fps):");
2109 AddCell((int)stats.infoFPS.fAverageFPS);
2110 AddCell((int)stats.infoFPS.fMinFPS);
2111 AddCell((int)stats.infoFPS.fMaxFPS);
2112 AddRow();
2114 AddRow();
2115 m_CurrRow->setAttr("ss:StyleID", "s25");
2116 AddCell("Resource Type (MB)");
2117 AddCell("Count");
2118 AddCell("Memory Size");
2119 AddCell("Only Mesh Size");
2120 AddCell("Only Texture Size");
2122 AddRow();
2123 AddCell("CGF Objects", CELL_BOLD);
2124 AddCell((uint32)stats.objects.size());
2125 AddCell((stats.nStatObj_SummaryTextureSize + stats.nStatObj_SummaryMeshSize) / (1024 * 1024));
2126 AddCell((stats.nStatObj_SummaryMeshSize) / (1024 * 1024));
2127 AddCell((stats.nStatObj_SummaryTextureSize) / (1024 * 1024));
2128 AddRow();
2129 AddCell("Character Models", CELL_BOLD);
2130 AddCell((uint32)stats.characters.size());
2131 AddCell((stats.nChar_SummaryTextureSize + stats.nChar_SummaryMeshSize) / (1024 * 1024));
2132 AddCell((stats.nChar_SummaryMeshSize) / (1024 * 1024));
2133 AddCell((stats.nChar_SummaryTextureSize) / (1024 * 1024));
2135 AddRow();
2136 AddCell("Character Instances", CELL_BOLD);
2137 AddCell(stats.nChar_NumInstances);
2139 AddRow();
2140 AddCell("Entities", CELL_BOLD);
2141 AddCell(stats.nSummaryEntityCount);
2143 //AddCell( stats.nMemCharactersTotalSize );
2144 AddRow();
2146 AddRow();
2147 m_CurrRow->setAttr("ss:StyleID", "s25");
2148 AddCell("Textures");
2149 AddRow();
2150 AddCell("Count", CELL_BOLD);
2151 AddCell((uint32)stats.textures.size());
2152 AddCell("Total count of textures");
2153 AddRow();
2155 AddCell("Textures Overall Size", CELL_BOLD);
2156 AddCell((uint32)(stats.nSummary_TextureSize / (1024 * 1024)));
2157 AddCell("Total amount of textures memory usage");
2159 AddRow();
2160 AddCell("Pool Size", CELL_BOLD);
2161 AddCell((uint32)(stats.nSummary_TexturesPoolSize / 1024 / 1024));
2162 AddCell("Size of textures pool");
2164 AddRow();
2165 AddCell("Textures Memory Usage", CELL_BOLD);
2166 AddCell(((uint32)(stats.nSummary_TexturesPoolSize + stats.nSummary_UserTextureSize + stats.nSummary_EngineTextureSize) / (1024 * 1024)));
2167 AddCell("Total memory of textures in RAM");
2169 AddRow();
2170 AddCell("Textures Engine Only", CELL_BOLD);
2171 AddCell(((uint32)(stats.nSummary_EngineTextureSize) / (1024 * 1024)));
2172 AddCell("Textures for internal Engine usage ");
2174 AddRow();
2175 AddCell("User Textures", CELL_BOLD);
2176 AddCell(((uint32)(stats.nSummary_UserTextureSize) / (1024 * 1024)));
2177 AddCell("User textures not stored in the textures pool");
2179 AddRow();
2180 AddCell("Textures streaming throughput(KB/s)", CELL_BOLD);
2181 AddCell((uint32)((stats.nSummary_TexturesStreamingThroughput) / 1024));
2182 AddRow();
2184 //AddRow();
2185 //m_CurrRow->setAttr( "ss:StyleID","s25" );
2186 //AddCell( "Resource Type (MB)" );
2187 //AddCell( "Count" );
2188 //AddCell( "Total Size" );
2189 //AddCell( "System Memory" );
2190 //AddCell( "Video Memory" );
2191 //AddCell( "Engine Textures" );
2192 //AddCell( "User Textures" );
2193 //if(stats.nSummary_TexturesStreamingThroughput > 0)
2194 // AddCell( "Textures streaming throughput(KB/s)" );
2196 //AddRow();
2197 //AddCell( "Textures",CELL_BOLD );
2198 //AddCell( stats.textures.size() );
2199 //AddCell( (stats.nSummary_TextureSize)/(1024*1024) );
2200 //AddCell( (stats.nSummary_TextureSize)/(1024*1024) );
2201 //AddCell( (stats.nSummary_TextureSize)/(1024*1024) );
2202 //AddCell( (stats.nSummary_EngineTextureSize)/(1024*1024) );
2203 //AddCell( (stats.nSummary_UserTextureSize)/(1024*1024) );
2204 //if(stats.nSummary_TexturesStreamingThroughput > 0)
2205 // AddCell( (stats.nSummary_TexturesStreamingThroughput) / 1024 );
2207 AddRow();
2208 m_CurrRow->setAttr("ss:StyleID", "s25");
2209 AddCell("Meshes");
2210 AddRow();
2211 AddCell("Count", CELL_BOLD);
2212 AddCell(stats.nSummaryMeshCount);
2213 AddRow();
2214 AddCell("Total Size", CELL_BOLD);
2215 AddCell((stats.nAPI_MeshSize + stats.nSummaryMeshSize) / (1024 * 1024));
2216 AddRow();
2217 AddCell("System Memory", CELL_BOLD);
2218 AddCell((stats.nSummaryMeshSize) / (1024 * 1024));
2219 AddRow();
2220 AddCell("Video Memory", CELL_BOLD);
2221 AddCell((stats.nAPI_MeshSize) / (1024 * 1024));
2222 AddRow();
2223 AddRow();
2224 m_CurrRow->setAttr("ss:StyleID", "s25");
2225 AddRow();
2227 AddRow();
2228 AddCell("Lua Memory Usage (MB)");
2229 AddCell(stats.nSummaryScriptSize / (1024 * 1024));
2231 AddRow();
2232 AddCell("Game Memory Usage (MB)");
2233 AddCell(stats.nTotalAllocatedMemory / (1024 * 1024));
2234 uint64 totalAll = stats.memInfo.totalUsedInModules;
2235 totalAll += stats.nAPI_MeshSize;
2236 totalAll += stats.nSummary_UserTextureSize;
2237 totalAll += stats.nSummary_EngineTextureSize;
2238 totalAll += stats.memInfo.totalCodeAndStatic;
2239 AddRow();
2240 AddCell("Total Allocated (With Code/Textures/Mesh) (MB)");
2241 AddCell(totalAll / (1024 * 1024));
2242 AddRow();
2243 AddRow();
2244 AddCell("Virtual Memory Usage (MB)");
2245 AddCell(stats.nWin32_PagefileUsage / (1024 * 1024));
2246 AddRow();
2248 AddCell("Peak Virtual Memory Usage (MB)");
2249 AddCell(stats.nWin32_PeakPagefileUsage / (1024 * 1024));
2251 //FPS buckets
2252 ExportFPSBuckets();
2255 //////////////////////////////////////////////////////////////////////////
2256 void CStatsToExcelExporter::ExportStatObjects(SCryEngineStats& stats)
2258 NewWorksheet("Static Geometry");
2259 FreezeFirstRow();
2260 AutoFilter(1, 12);
2262 XmlNodeRef Column;
2263 Column = m_CurrTable->newChild("Column");
2264 Column->setAttr("ss:Width", 350);
2265 Column = m_CurrTable->newChild("Column");
2266 Column->setAttr("ss:Width", 50);
2267 Column = m_CurrTable->newChild("Column");
2268 Column->setAttr("ss:Width", 90);
2269 Column = m_CurrTable->newChild("Column");
2270 Column->setAttr("ss:Width", 100);
2271 Column = m_CurrTable->newChild("Column");
2272 Column->setAttr("ss:Width", 50);
2273 Column = m_CurrTable->newChild("Column");
2274 Column->setAttr("ss:Width", 50);
2275 Column = m_CurrTable->newChild("Column");
2276 Column->setAttr("ss:Width", 80);
2277 Column = m_CurrTable->newChild("Column");
2278 Column->setAttr("ss:Width", 60);
2279 Column = m_CurrTable->newChild("Column");
2280 Column->setAttr("ss:Width", 60);
2281 Column = m_CurrTable->newChild("Column");
2282 Column->setAttr("ss:Width", 100);
2283 Column = m_CurrTable->newChild("Column");
2284 Column->setAttr("ss:Width", 100);
2285 Column = m_CurrTable->newChild("Column");
2286 Column->setAttr("ss:Width", 120);
2287 Column = m_CurrTable->newChild("Column");
2288 Column->setAttr("ss:Width", 90);
2289 Column = m_CurrTable->newChild("Column");
2290 Column->setAttr("ss:Width", 80);
2292 AddRow();
2293 m_CurrRow->setAttr("ss:StyleID", "s25");
2294 AddCell("Filename");
2295 AddCell("Refs");
2296 AddCell("Mesh Size (KB)");
2297 AddCell("Texture Size (KB)");
2298 AddCell("DrawCalls");
2299 AddCell("LODs");
2300 AddCell("Sub Meshes");
2301 AddCell("Vertices");
2302 AddCell("Tris");
2303 AddCell("Physics Tris");
2304 AddCell("Physics Size (KB)");
2305 AddCell("LODs Tris");
2306 AddCell("Mesh Size Loaded (KB)");
2307 AddCell("Split LODs");
2309 int nRows = (int)stats.objects.size();
2310 for (int i = 0; i < nRows; i++)
2312 SCryEngineStats::StatObjInfo& si = stats.objects[i];
2314 AddRow();
2315 AddCell((si.pStatObj) ? si.pStatObj->GetFilePath() : "");
2316 AddCell(si.nNumRefs);
2317 AddCell(si.nMeshSize / 1024);
2318 AddCell(si.nTextureSize / 1024);
2319 AddCell(si.nDrawCalls);
2320 AddCell(si.nLods);
2321 AddCell(si.nSubMeshCount);
2322 AddCell(si.nVertices);
2323 AddCell(si.nIndices / 3);
2324 AddCell(si.nPhysPrimitives);
2325 AddCell((si.nPhysProxySize + 512) / 1024);
2327 if (si.nLods > 1)
2329 // Print lod1/lod2/lod3 ...
2330 char tempstr[256];
2331 char numstr[32];
2332 tempstr[0] = 0;
2333 int numlods = 0;
2334 for (int lod = 0; lod < MAX_LODS; lod++)
2336 if (si.nIndicesPerLod[lod] != 0)
2338 cry_sprintf(numstr, "%d", (si.nIndicesPerLod[lod] / 3));
2339 if (numlods > 0)
2340 cry_strcat(tempstr, " / ");
2341 cry_strcat(tempstr, numstr);
2342 numlods++;
2345 if (numlods > 1)
2346 AddCell(tempstr);
2348 else
2350 AddCell("");
2353 AddCell(si.nMeshSizeLoaded / 1024);
2354 if (si.bSplitLods)
2356 AddCell("Yes");
2358 else
2360 AddCell("");
2366 AddRow(); m_CurrRow->setAttr( "ss:StyleID","s25" );
2367 AddCell( "" );
2368 AddCell_SumOfRows( nRows ); // Mesh size
2369 AddCell_SumOfRows( nRows ); // Texture size
2370 AddCell( "" ); // LODs
2371 AddCell( "" ); // Sub Meshes
2372 AddCell_SumOfRows( nRows ); // Vertices
2373 AddCell_SumOfRows( nRows ); // Tris
2374 AddCell_SumOfRows( nRows ); // Physics Tris
2375 AddCell_SumOfRows( nRows ); // Physics Size
2376 AddCell( "" ); // LODs Tris
2377 AddCell_SumOfRows( nRows ); // Mesh Size Loaded
2381 //////////////////////////////////////////////////////////////////////////
2382 struct CrySizerNaive : ICrySizer
2384 CrySizerNaive() : m_count(0), m_size(0) {}
2385 virtual void Release() {}
2386 virtual void End() {}
2387 virtual size_t GetTotalSize() { return m_size; }
2388 virtual size_t GetObjectCount() { return m_count; }
2389 virtual IResourceCollector* GetResourceCollector()
2391 assert(0);
2392 return (IResourceCollector*)0;
2394 virtual void Push(const char*) {}
2395 virtual void PushSubcomponent(const char*) {}
2396 virtual void Pop() {}
2397 virtual bool AddObject(const void* id, size_t size, int count = 1) { m_size += size * count; m_count++; return true; }
2398 virtual void Reset() { m_size = 0; m_count = 0; }
2399 virtual void SetResourceCollector(IResourceCollector* pColl) {};
2400 size_t m_count, m_size;
2403 //////////////////////////////////////////////////////////////////////////
2404 void CStatsToExcelExporter::ExportPhysEntStatistics(SCryEngineStats& stats)
2406 NewWorksheet("Physical Entities");
2408 FreezeFirstRow();
2409 AutoFilter(1, 6);
2411 XmlNodeRef Column;
2412 Column = m_CurrTable->newChild("Column");
2413 Column->setAttr("ss:Width", 300);
2414 Column = m_CurrTable->newChild("Column");
2415 Column->setAttr("ss:Width", 50);
2416 Column = m_CurrTable->newChild("Column");
2417 Column->setAttr("ss:Width", 50);
2418 Column = m_CurrTable->newChild("Column");
2419 Column->setAttr("ss:Width", 50);
2420 Column = m_CurrTable->newChild("Column");
2421 Column->setAttr("ss:Width", 50);
2422 Column = m_CurrTable->newChild("Column");
2423 Column->setAttr("ss:Width", 50);
2424 Column = m_CurrTable->newChild("Column");
2425 Column->setAttr("ss:Width", 150);
2426 Column = m_CurrTable->newChild("Column");
2427 Column->setAttr("ss:Width", 150);
2428 Column = m_CurrTable->newChild("Column");
2429 Column->setAttr("ss:Width", 150);
2430 Column = m_CurrTable->newChild("Column");
2431 Column->setAttr("ss:Width", 150);
2433 AddRow();
2434 m_CurrRow->setAttr("ss:StyleID", "s25");
2435 AddCell("Name");
2436 AddCell("Type");
2437 AddCell("SimClass");
2438 AddCell("Total Size");
2439 AddCell("Instanced Geom Size");
2440 AddCell("Grid Footprint");
2441 AddCell("RB_Intersect Unfriendly");
2442 AddCell("Cloth Unfriendly");
2443 AddCell("Rope Unfriendly");
2444 AddCell("Featherstone Unfriendly");
2446 IPhysicalEntityIt* iter = gEnv->pPhysicalWorld->GetEntitiesIterator();
2447 IPhysicalEntity* pent;
2448 PhysicsVars* pVars = gEnv->pPhysicalWorld->GetPhysVars();
2450 for (iter->MoveFirst(); pent = iter->Next(); )
2452 AddRow();
2453 pe_params_foreign_data pfd;
2454 pent->GetParams(&pfd);
2455 AddCell(CPhysRenderer::GetPhysForeignName(pfd.pForeignData, pfd.iForeignData, pfd.iForeignFlags));
2457 pe_status_pos sp;
2458 pent->GetStatus(&sp);
2459 const char* entypes[] = { "none", "static", "rigidbody", "vehicle", "living", "particle", "character", "rope", "cloth", "area" };
2460 AddCell(entypes[pent->GetType()]);
2461 const char* simclass[] = { "hidden", "0-static", "1-sleeping", "2-active", "3-actor", "4-independent", "5-area", "6-trigger", "7-deleted" };
2462 AddCell(simclass[sp.iSimClass + 1]);
2464 CrySizerNaive sizer;
2465 pVars->iDrawHelpers |= 1 << 31;
2466 pent->GetMemoryStatistics(&sizer);
2467 int sizeTot = sizer.m_size;
2468 pVars->iDrawHelpers &= ~(1 << 31);
2469 sizer.Reset();
2470 pent->GetMemoryStatistics(&sizer);
2471 int sizeGrid = sizeTot - sizer.m_size;
2473 pe_params_part pp;
2474 sizer.Reset();
2476 char szFallbackReason[2048];
2477 size_t len = sizeof(szFallbackReason);
2478 memset(szFallbackReason, 0, sizeof(szFallbackReason));
2479 for (pp.ipart = 0; pent->GetParams(&pp); pp.ipart++)
2481 size_t old_len = len;
2482 if (old_len != len)
2484 char token[64];
2485 cry_sprintf(token, "[part %d]", pp.ipart);
2486 cry_strcat(szFallbackReason, token);
2487 len -= strlen(token);
2490 if (pp.flagsAND & geom_can_modify)
2492 pp.pPhysGeom->pGeom->GetMemoryStatistics(&sizer);
2493 if (pp.pPhysGeomProxy != pp.pPhysGeom)
2495 pp.pPhysGeomProxy->pGeom->GetMemoryStatistics(&sizer);
2498 MARK_UNUSED pp.partid;
2500 AddCell(sizeTot + (int)sizer.m_size);
2501 AddCell((uint32)sizer.m_size);
2502 AddCell(sizeGrid);
2504 szFallbackReason[sizeof(szFallbackReason) - 1] = 0;
2505 AddCell(strlen(szFallbackReason) ? szFallbackReason : " ");
2506 AddCell(pent->GetType() == PE_SOFT && sizeTot + sizer.m_size - sizeGrid > 90 << 10 ? "too big" : " ");
2507 AddCell(pent->GetType() == PE_ROPE && sizeTot + sizer.m_size - sizeGrid > 70 << 10 ? "too big" : " ");
2508 AddCell(pent->GetType() == PE_ARTICULATED && sizeTot + sizer.m_size - sizeGrid > 60 << 10 ? "too big" : " ");
2512 //////////////////////////////////////////////////////////////////////////
2513 void CStatsToExcelExporter::ExportEntitiesStatistics(SCryEngineStats& stats)
2515 NewWorksheet("Entities");
2517 FreezeFirstRow();
2518 AutoFilter(1, 3);
2520 XmlNodeRef Column;
2521 Column = m_CurrTable->newChild("Column");
2522 Column->setAttr("ss:Width", 300);
2523 Column = m_CurrTable->newChild("Column");
2524 Column->setAttr("ss:Width", 300);
2525 Column = m_CurrTable->newChild("Column");
2526 Column->setAttr("ss:Width", 100);
2527 Column = m_CurrTable->newChild("Column");
2528 Column->setAttr("ss:Width", 100);
2529 Column = m_CurrTable->newChild("Column");
2530 Column->setAttr("ss:Width", 100);
2531 Column = m_CurrTable->newChild("Column");
2532 Column->setAttr("ss:Width", 300);
2534 AddRow();
2535 m_CurrRow->setAttr("ss:StyleID", "s25");
2536 AddCell("Name");
2537 AddCell("Models");
2538 AddCell("IsInvisible(but updated)");
2539 AddCell("IsHidden(and disabled)");
2541 for (size_t i = 0, iCount = stats.entities.size(); i < iCount; ++i)
2543 AddRow();
2544 AddCell(stats.entities[i].name.c_str());
2545 AddCell(stats.entities[i].models.c_str());
2546 AddCell(stats.entities[i].bInvisible ? "Yes" : "No");
2547 AddCell(stats.entities[i].bHidden ? "Yes" : "No");
2551 //////////////////////////////////////////////////////////////////////////
2552 void CStatsToExcelExporter::ExportAnimationStatistics(SCryEngineStats& stats)
2554 if (stats.animations.empty())
2555 return;
2557 NewWorksheet("Animations");
2558 FreezeFirstRow();
2559 AutoFilter(1, 2);
2561 XmlNodeRef Column;
2562 Column = m_CurrTable->newChild("Column");
2563 Column->setAttr("ss:Width", 300);
2564 Column = m_CurrTable->newChild("Column");
2565 Column->setAttr("ss:Width", 50);
2567 AddRow();
2568 m_CurrRow->setAttr("ss:StyleID", "s25");
2569 AddCell("Name");
2570 AddCell("Count");
2572 int nRows = (int)stats.animations.size();
2573 for (int i = 0; i < nRows; i++)
2575 SAnimationStatistics& an = stats.animations[i];
2576 AddRow();
2577 AddCell(an.name);
2578 AddCell((uint32)an.count);
2582 //////////////////////////////////////////////////////////////////////////
2583 void CStatsToExcelExporter::ExportProfilerStatistics(SCryEngineStats& stats)
2585 if (stats.profilers.empty())
2586 return;
2590 NewWorksheet("Profiler");
2591 FreezeFirstRow();
2592 AutoFilter(1, 10);
2594 XmlNodeRef Column;
2595 Column = m_CurrTable->newChild("Column");
2596 Column->setAttr("ss:Width", 100);
2597 Column = m_CurrTable->newChild("Column");
2598 Column->setAttr("ss:Width", 300);
2599 Column = m_CurrTable->newChild("Column");
2600 Column->setAttr("ss:Width", 50);
2601 Column = m_CurrTable->newChild("Column");
2602 Column->setAttr("ss:Width", 50);
2603 Column = m_CurrTable->newChild("Column");
2604 Column->setAttr("ss:Width", 50);
2605 Column = m_CurrTable->newChild("Column");
2606 Column->setAttr("ss:Width", 50);
2607 Column = m_CurrTable->newChild("Column");
2608 Column->setAttr("ss:Width", 50);
2609 Column = m_CurrTable->newChild("Column");
2610 Column->setAttr("ss:Width", 50);
2611 Column = m_CurrTable->newChild("Column");
2612 Column->setAttr("ss:Width", 50);
2613 Column = m_CurrTable->newChild("Column");
2614 Column->setAttr("ss:Width", 50);
2616 // Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",40 );
2618 AddRow();
2619 m_CurrRow->setAttr("ss:StyleID", "s25");
2620 AddCell("Module");
2621 AddCell("Name");
2622 AddCell("Self time, ms");
2623 AddCell("Total time, ms");
2624 AddCell("Count");
2625 AddCell("");
2626 AddCell("Min time, ms");
2627 AddCell("Max time, ms");
2628 AddCell("Min count");
2629 AddCell("Max count");
2631 int nRows = (int)stats.profilers.size();
2632 for (int i = 0; i < nRows; i++)
2634 SCryEngineStats::ProfilerInfo& pi = stats.profilers[i];
2635 AddRow();
2636 AddCell(pi.m_module);
2637 AddCell(pi.m_name);
2638 AddCell(pi.m_displayedValue);
2639 AddCell(pi.m_totalTime);
2640 AddCell(pi.m_count);
2641 AddCell("");
2642 AddCell(pi.m_min);
2643 AddCell(pi.m_max);
2644 AddCell(pi.m_mincount);
2645 AddCell(pi.m_maxcount);
2649 AddRow();
2650 m_CurrRow->setAttr("ss:StyleID", "s25");
2651 AddCell("");
2652 AddCell("");
2653 AddCell_SumOfRows(nRows);
2654 AddCell_SumOfRows(nRows);
2655 AddCell_SumOfRows(nRows);
2656 // AddCell("");
2657 AddCell("");
2658 AddCell("");
2661 // Peaks
2663 NewWorksheet("Peaks");
2665 XmlNodeRef Column;
2666 Column = m_CurrTable->newChild("Column");
2667 Column->setAttr("ss:Width", 100);
2668 Column = m_CurrTable->newChild("Column");
2669 Column->setAttr("ss:Width", 300);
2670 Column = m_CurrTable->newChild("Column");
2671 Column->setAttr("ss:Width", 50);
2672 Column = m_CurrTable->newChild("Column");
2673 Column->setAttr("ss:Width", 50);
2674 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2675 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2676 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2677 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2678 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2679 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2680 //Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",50 );
2682 // Column = m_CurrTable->newChild("Column"); Column->setAttr( "ss:Width",40 );
2684 AddRow();
2685 m_CurrRow->setAttr("ss:StyleID", "s25");
2686 AddCell("Module");
2687 AddCell("Name");
2688 AddCell("Peak, ms");
2689 //AddCell( "Self time, ms" );
2690 //AddCell( "Total time, ms" );
2691 AddCell("Count");
2692 //AddCell( "" );
2693 //AddCell( "Min time, ms" );
2694 //AddCell( "Max time, ms" );
2695 //AddCell( "Min count" );
2696 //AddCell( "Max count" );
2698 int nRows = (int)stats.peaks.size();
2699 for (int i = 0; i < nRows; i++)
2701 SCryEngineStats::SPeakProfilerInfo& peak = stats.peaks[i];
2702 SCryEngineStats::ProfilerInfo& pi = stats.peaks[i].profiler;
2703 AddRow();
2704 AddCell(pi.m_module);
2705 AddCell(pi.m_name);
2706 AddCell(peak.peakValue);
2707 //AddCell( pi.m_displayedValue );
2708 //AddCell( pi.m_totalTime );
2709 AddCell(peak.count);
2710 //AddCell( "");
2711 //AddCell( pi.m_min );
2712 //AddCell( pi.m_max );
2713 //AddCell( pi.m_mincount );
2714 //AddCell( pi.m_maxcount );
2717 //AddRow(); m_CurrRow->setAttr( "ss:StyleID","s25" );
2718 //AddCell("");
2719 //AddCell("");
2720 //AddCell("");
2721 //AddCell_SumOfRows( nRows );
2722 //AddCell_SumOfRows( nRows );
2723 //AddCell_SumOfRows( nRows );
2724 //// AddCell("");
2725 //AddCell("");
2726 //AddCell("");
2728 NewWorksheet("Budget");
2730 Column = m_CurrTable->newChild("Column");
2731 Column->setAttr("ss:Width", 100);
2732 Column = m_CurrTable->newChild("Column");
2733 Column->setAttr("ss:Width", 300);
2734 Column = m_CurrTable->newChild("Column");
2735 Column->setAttr("ss:Width", 50);
2736 Column = m_CurrTable->newChild("Column");
2737 Column->setAttr("ss:Width", 50);
2742 //////////////////////////////////////////////////////////////////////////
2743 void CStatsToExcelExporter::ExportCharacters(SCryEngineStats& stats)
2745 NewWorksheet("Characters");
2746 FreezeFirstRow();
2747 AutoFilter(1, 10);
2749 XmlNodeRef Column;
2750 Column = m_CurrTable->newChild("Column");
2751 Column->setAttr("ss:Width", 300);
2752 Column = m_CurrTable->newChild("Column");
2753 Column->setAttr("ss:Width", 40);
2754 Column = m_CurrTable->newChild("Column");
2755 Column->setAttr("ss:Width", 90);
2756 Column = m_CurrTable->newChild("Column");
2757 Column->setAttr("ss:Width", 90);
2758 Column = m_CurrTable->newChild("Column");
2759 Column->setAttr("ss:Width", 90);
2760 Column = m_CurrTable->newChild("Column");
2761 Column->setAttr("ss:Width", 40);
2762 Column = m_CurrTable->newChild("Column");
2763 Column->setAttr("ss:Width", 90);
2764 Column = m_CurrTable->newChild("Column");
2765 Column->setAttr("ss:Width", 90);
2766 Column = m_CurrTable->newChild("Column");
2767 Column->setAttr("ss:Width", 90);
2768 Column = m_CurrTable->newChild("Column");
2769 Column->setAttr("ss:Width", 90);
2770 Column = m_CurrTable->newChild("Column");
2771 Column->setAttr("ss:Width", 150);
2773 AddRow();
2774 m_CurrRow->setAttr("ss:StyleID", "s25");
2775 AddCell("Filename");
2776 AddCell("Num Instances");
2777 AddCell("Mesh Size (KB)");
2778 AddCell("Texture Size (KB)");
2779 AddCell("PhysProxy Size (KB)");
2780 AddCell("LODs");
2781 AddCell("Vertices Lod0");
2782 AddCell("Tris Lod0");
2783 AddCell("All Vertices");
2784 AddCell("All Tris");
2785 AddCell("LOD Tris");
2787 int nRows = (int)stats.characters.size();
2788 for (int i = 0; i < nRows; i++)
2790 SCryEngineStats::CharacterInfo& si = stats.characters[i];
2791 AddRow();
2792 AddCell(si.pIDefaultSkeleton->GetModelFilePath());
2793 AddCell(si.nInstances);
2794 AddCell(si.nMeshSize / 1024);
2795 AddCell(si.nTextureSize / 1024);
2796 AddCell((si.nPhysProxySize + 512) >> 10);
2797 AddCell(si.nLods);
2798 AddCell(si.nVertices);
2799 AddCell(si.nIndices / 3);
2801 int nAllVerts = 0;
2802 for (int k = 0; k < MAX_LODS; k++)
2803 nAllVerts += si.nVerticesPerLod[k];
2804 AddCell(nAllVerts);
2806 int nAllIndices = 0;
2807 for (int k = 0; k < MAX_LODS; k++)
2808 nAllIndices += si.nIndicesPerLod[k];
2809 AddCell(nAllIndices / 3);
2811 if (si.nLods > 1)
2813 // Print lod1/lod2/lod3 ...
2814 char tempstr[256];
2815 char numstr[32];
2816 tempstr[0] = 0;
2817 int numlods = 0;
2818 for (int lod = 0; lod < MAX_LODS; lod++)
2820 if (si.nIndicesPerLod[lod] != 0)
2822 cry_sprintf(numstr, "%d", (si.nIndicesPerLod[lod] / 3));
2823 if (numlods > 0)
2824 cry_strcat(tempstr, " / ");
2825 cry_strcat(tempstr, numstr);
2826 numlods++;
2829 if (numlods > 1)
2830 AddCell(tempstr);
2833 AddRow();
2834 m_CurrRow->setAttr("ss:StyleID", "s25");
2835 AddCell("");
2836 AddCell_SumOfRows(nRows);
2837 AddCell_SumOfRows(nRows);
2838 AddCell_SumOfRows(nRows);
2839 AddCell("");
2840 AddCell_SumOfRows(nRows);
2841 AddCell_SumOfRows(nRows);
2844 //////////////////////////////////////////////////////////////////////////
2845 void CStatsToExcelExporter::ExportDependencies(CResourceCollector& stats)
2848 NewWorksheet("Assets");
2849 FreezeFirstRow();
2851 XmlNodeRef Column;
2852 Column = m_CurrTable->newChild("Column");
2853 Column->setAttr("ss:Width", 72);
2854 Column = m_CurrTable->newChild("Column");
2855 Column->setAttr("ss:Width", 108);
2856 Column = m_CurrTable->newChild("Column");
2857 Column->setAttr("ss:Width", 73);
2858 Column = m_CurrTable->newChild("Column");
2859 Column->setAttr("ss:Width", 60);
2860 Column = m_CurrTable->newChild("Column");
2861 Column->setAttr("ss:Width", 1000);
2863 AddRow();
2864 m_CurrRow->setAttr("ss:StyleID", "s25");
2865 AddCell("Instances");
2866 AddCell("Dependencies");
2867 AddCell("FileMem (KB)");
2868 AddCell("Extension");
2869 AddCell("FileName");
2871 std::vector<CResourceCollector::SAssetEntry>::const_iterator it, end = stats.m_Assets.end();
2872 uint32 dwAssetID = 0;
2874 for (it = stats.m_Assets.begin(); it != end; ++it, ++dwAssetID)
2876 const CResourceCollector::SAssetEntry& rRef = *it;
2878 AddRow();
2880 char szAName1[1024];
2881 cry_sprintf(szAName1, "A%u %s", dwAssetID, rRef.m_sFileName.c_str());
2883 AddCell(rRef.m_dwInstanceCnt);
2884 AddCell(rRef.m_dwDependencyCnt);
2885 AddCell(rRef.m_dwFileSize != 0xffffffff ? rRef.m_dwFileSize / 1024 : 0);
2886 AddCell(PathUtil::GetExt(rRef.m_sFileName));
2887 AddCell(szAName1);
2890 AddRow();
2891 m_CurrRow->setAttr("ss:StyleID", "s25");
2892 AddCell_SumOfRows(dwAssetID);
2893 AddCell("");
2894 AddCell_SumOfRows(dwAssetID);
2898 NewWorksheet("Dependencies");
2899 FreezeFirstRow();
2901 XmlNodeRef Column;
2902 Column = m_CurrTable->newChild("Column");
2903 Column->setAttr("ss:Width", 600);
2904 Column = m_CurrTable->newChild("Column");
2905 Column->setAttr("ss:Width", 90);
2906 Column = m_CurrTable->newChild("Column");
2907 Column->setAttr("ss:Width", 60);
2909 AddRow();
2910 m_CurrRow->setAttr("ss:StyleID", "s25");
2911 AddCell("Asset Filename");
2912 AddCell("Requires Sum (KB)");
2913 AddCell("Requires Count");
2915 std::set<CResourceCollector::SDependencyPair>::const_iterator it, end = stats.m_Dependencies.end();
2917 uint32 dwCurrentAssetID = 0xffffffff;
2918 uint32 dwSumFile = 0, dwSum = 0;
2920 for (it = stats.m_Dependencies.begin();; ++it)
2922 uint32 dwAssetsSize = stats.m_Assets.size();
2924 if (it == end || (*it).m_idAsset != dwCurrentAssetID)
2926 if (dwSum != 0 && dwSumFile != 0xffffffff)
2928 assert(dwCurrentAssetID < dwAssetsSize);
2930 char szAName0[1024];
2931 cry_sprintf(szAName0, "A%u %s", dwCurrentAssetID, stats.m_Assets[dwCurrentAssetID].m_sFileName.c_str());
2933 AddRow();
2934 AddCell(szAName0);
2935 AddCell(dwSumFile / 1024);
2936 AddCell(dwSum);
2939 dwSumFile = 0;
2940 dwSum = 0;
2942 if (it == end)
2943 break;
2946 const CResourceCollector::SDependencyPair& rRef = *it;
2948 assert(rRef.m_idDependsOnAsset < dwAssetsSize);
2950 CResourceCollector::SAssetEntry& rDepAsset = stats.m_Assets[rRef.m_idDependsOnAsset];
2952 if (rDepAsset.m_dwFileSize != 0xffffffff)
2953 dwSumFile += rDepAsset.m_dwFileSize;
2955 ++dwSum;
2957 dwCurrentAssetID = rRef.m_idAsset;
2962 NewWorksheet("Detailed Dependencies");
2963 FreezeFirstRow();
2965 XmlNodeRef Column;
2966 Column = m_CurrTable->newChild("Column");
2967 Column->setAttr("ss:Width", 600);
2968 Column = m_CurrTable->newChild("Column");
2969 Column->setAttr("ss:Width", 1000);
2970 Column = m_CurrTable->newChild("Column");
2971 Column->setAttr("ss:Width", 70);
2973 AddRow();
2974 m_CurrRow->setAttr("ss:StyleID", "s25");
2975 AddCell("Asset Filename");
2976 AddCell("Requires Filename");
2977 AddCell("Requires (KB)");
2979 std::set<CResourceCollector::SDependencyPair>::const_iterator it, end = stats.m_Dependencies.end();
2981 uint32 dwCurrentAssetID = 0xffffffff;
2982 uint32 dwSumFile = 0, dwSum = 0;
2984 for (it = stats.m_Dependencies.begin();; ++it)
2986 if (it == end || (*it).m_idAsset != dwCurrentAssetID)
2988 if (dwSum != 0 && dwSumFile != 0xffffffff)
2990 // AddRow(); m_CurrRow->setAttr( "ss:StyleID","s21" );
2991 // AddCell("");
2992 // AddCell_SumOfRows( dwSum );
2993 AddRow();
2994 AddCell("");
2997 dwSumFile = 0;
2998 dwSum = 0;
3000 if (it == end)
3001 break;
3003 const CResourceCollector::SDependencyPair &rRef = *it;
3005 char szAName0[20];
3006 cry_sprintf(szAName0,"A%d",rRef.m_idAsset);
3008 AddRow(); m_CurrRow->setAttr( "ss:StyleID","s21" );
3009 AddCell( szAName0 );
3010 AddCell( stats.m_Assets[rRef.m_idAsset].m_sFileName.c_str() );
3014 const CResourceCollector::SDependencyPair& rRef = *it;
3016 CResourceCollector::SAssetEntry& rDepAsset = stats.m_Assets[rRef.m_idDependsOnAsset];
3018 AddRow();
3020 char szAName0[1024];
3021 cry_sprintf(szAName0, "A%u %s", rRef.m_idAsset, stats.m_Assets[rRef.m_idAsset].m_sFileName.c_str());
3022 char szAName1[1024];
3023 cry_sprintf(szAName1, "A%u %s", rRef.m_idDependsOnAsset, rDepAsset.m_sFileName.c_str());
3025 AddCell(szAName0);
3026 AddCell(szAName1);
3027 AddCell(rDepAsset.m_dwFileSize != 0xffffffff ? rDepAsset.m_dwFileSize / 1024 : 0);
3029 if (rDepAsset.m_dwFileSize != 0xffffffff)
3030 dwSumFile += rDepAsset.m_dwFileSize;
3032 ++dwSum;
3034 dwCurrentAssetID = rRef.m_idAsset;
3039 //////////////////////////////////////////////////////////////////////////
3040 void CStatsToExcelExporter::ExportRenderMeshes(SCryEngineStats& stats)
3042 NewWorksheet("Meshes");
3043 FreezeFirstRow();
3044 AutoFilter(1, 8);
3046 XmlNodeRef Column;
3047 Column = m_CurrTable->newChild("Column");
3048 Column->setAttr("ss:Width", 300);
3049 Column = m_CurrTable->newChild("Column");
3050 Column->setAttr("ss:Width", 40);
3051 Column = m_CurrTable->newChild("Column");
3052 Column->setAttr("ss:Width", 90);
3053 Column = m_CurrTable->newChild("Column");
3054 Column->setAttr("ss:Width", 100);
3055 Column = m_CurrTable->newChild("Column");
3056 Column->setAttr("ss:Width", 100);
3057 Column = m_CurrTable->newChild("Column");
3058 Column->setAttr("ss:Width", 90);
3059 Column = m_CurrTable->newChild("Column");
3060 Column->setAttr("ss:Width", 90);
3062 AddRow();
3063 m_CurrRow->setAttr("ss:StyleID", "s25");
3064 AddCell("Mesh Type");
3065 AddCell("Num Instances");
3066 AddCell("Mesh Size Sys (KB)");
3067 AddCell("Mesh Size Dev (KB)");
3068 AddCell("Texture Size (KB)");
3069 AddCell("Total Vertices");
3070 AddCell("Total Tris");
3071 int nRows = (int)stats.meshes.size();
3072 for (int i = 0; i < nRows; i++)
3074 SCryEngineStats::MeshInfo& mi = stats.meshes[i];
3075 AddRow();
3076 AddCell(mi.name);
3077 AddCell(mi.nCount);
3078 AddCell(mi.nMeshSizeSys / 1024);
3079 AddCell(mi.nMeshSizeDev / 1024);
3080 AddCell(mi.nTextureSize / 1024);
3081 AddCell(mi.nVerticesSum);
3082 AddCell(mi.nIndicesSum / 3);
3084 AddRow();
3085 m_CurrRow->setAttr("ss:StyleID", "s25");
3086 AddCell("");
3087 AddCell_SumOfRows(nRows);
3088 AddCell_SumOfRows(nRows);
3089 AddCell_SumOfRows(nRows);
3090 AddCell_SumOfRows(nRows);
3091 AddCell_SumOfRows(nRows);
3094 //////////////////////////////////////////////////////////////////////////
3095 bool SortBrushes(SCryEngineStats::SBrushMemInfo a, SCryEngineStats::SBrushMemInfo b)
3097 return a.usedTextureMemory > b.usedTextureMemory;
3100 void CStatsToExcelExporter::ExportBrushes(SCryEngineStats& stats)
3102 NewWorksheet("Brushes");
3103 FreezeFirstRow();
3104 AutoFilter(1, 8);
3106 XmlNodeRef Column;
3107 Column = m_CurrTable->newChild("Column");
3108 Column->setAttr("ss:Width", 700);
3109 Column = m_CurrTable->newChild("Column");
3110 Column->setAttr("ss:Width", 100);
3111 Column = m_CurrTable->newChild("Column");
3112 Column->setAttr("ss:Width", 100);
3114 AddRow();
3115 m_CurrRow->setAttr("ss:StyleID", "s25");
3116 AddCell("Brush Name");
3117 AddCell("Lod Num");
3118 AddCell("Used Texture Mem(KB)");
3120 std::sort(stats.brushes.begin(), stats.brushes.end(), SortBrushes);
3122 int nRows = (int)stats.brushes.size();
3123 for (int i = 0; i < nRows; i++)
3125 SCryEngineStats::SBrushMemInfo& mi = stats.brushes[i];
3126 AddRow();
3127 AddCell(mi.brushName);
3128 AddCell(mi.lodNum);
3129 AddCell(mi.usedTextureMemory / 1024);
3131 AddRow();
3132 m_CurrRow->setAttr("ss:StyleID", "s25");
3133 AddCell("");
3134 AddCell("");
3135 AddCell_SumOfRows(nRows);
3138 //////////////////////////////////////////////////////////////////////////
3139 void CStatsToExcelExporter::ExportMaterials(SCryEngineStats& stats)
3142 NewWorksheet("Materials");
3143 FreezeFirstRow();
3144 AutoFilter(1, 5);
3146 XmlNodeRef Column;
3147 Column = m_CurrTable->newChild("Column");
3148 Column->setAttr("ss:Width", 400);
3150 AddRow();
3151 m_CurrRow->setAttr("ss:StyleID", "s25");
3153 AddCell("Name");
3154 AddCell("IsSystem");
3155 AddCell("IsConsoleMtl");
3156 AddCell("RefCount");
3157 AddCell("NumSubMtls");
3159 int nRows = (int)stats.materials.size();
3160 for (int i = 0; i < nRows; i++)
3162 IMaterial* pMat = stats.materials[i];
3163 AddRow();
3164 AddCell(pMat->GetName());
3166 const bool isSysMtl = pMat->GetShaderItem().m_pShader && (pMat->GetShaderItem().m_pShader->GetFlags() & EF_SYSTEM) != 0;
3167 AddCell(isSysMtl ? "Yes" : "No");
3169 const bool isConsoleMtl = (pMat->GetFlags() & MTL_FLAG_CONSOLE_MAT) != 0;
3170 AddCell(isConsoleMtl ? "Yes" : "No");
3172 AddCell(pMat->GetNumRefs());
3174 AddCell(pMat->GetSubMtlCount());
3179 NewWorksheet("Materials Unused Textures");
3180 FreezeFirstRow();
3182 XmlNodeRef Column;
3183 Column = m_CurrTable->newChild("Column");
3184 Column->setAttr("ss:Width", 60);
3186 AddRow();
3187 AddCell("This is an estimate of which materials have slots filled with textures that are unused but will still stream.");
3188 AddRow();
3189 AddCell("Please use caution when removing these textures, and double check that it's valid.");
3190 AddRow();
3191 AddCell("");
3193 int nRows = (int)stats.materials.size();
3194 for (int i = 0; i < nRows; i++)
3196 IMaterial* pMat = stats.materials[i];
3198 for (int sub = 0; pMat && sub < pMat->GetSubMtlCount(); sub++)
3200 IMaterial* pSubMat = pMat->GetSubMtl(sub);
3202 if (!pSubMat)
3203 return;
3205 bool isMaterialRowAdded = false;
3207 IShader* pShader = pSubMat->GetShaderItem().m_pShader;
3208 int nTech = max(0, pSubMat->GetShaderItem().m_nTechnique);
3210 if (!pShader)
3211 continue;
3213 IRenderShaderResources* pShaderResources = pSubMat->GetShaderItem().m_pShaderResources;
3215 if (!pShaderResources)
3216 continue;
3218 SShaderTexSlots* pShaderSlots = pShader->GetUsedTextureSlots(nTech);
3220 if (!pShaderSlots)
3221 continue;
3223 for (int t = 0; t < EFTT_MAX; ++t)
3225 SShaderTextureSlot* pSlot = pShaderSlots->m_UsedSlots[t];
3227 const string textureName = (pShaderResources->GetTexture(t) != nullptr) ? pShaderResources->GetTexture(t)->m_Name.c_str() : "";
3229 if (!pSlot && !textureName.empty())
3231 // found unused texture.
3233 if (!isMaterialRowAdded)
3235 // first texture in this material, add material name row
3237 AddRow();
3238 m_CurrRow->setAttr("ss:StyleID", "s25");
3240 AddCell(string(pMat->GetName()) + "/" + pSubMat->GetName());
3242 isMaterialRowAdded = true;
3245 AddRow();
3246 AddCell(pMat->GetMaterialHelpers().LookupTexName((EEfResTextures)t));
3247 AddCell(textureName);
3255 //////////////////////////////////////////////////////////////////////////
3256 void CStatsToExcelExporter::ExportTextures(SCryEngineStats& stats)
3258 NewWorksheet("Textures");
3259 FreezeFirstRow();
3260 AutoFilter(1, 10);
3262 XmlNodeRef Column;
3263 Column = m_CurrTable->newChild("Column");
3264 Column->setAttr("ss:Width", 400);
3265 Column = m_CurrTable->newChild("Column");
3266 Column->setAttr("ss:Width", 40);
3267 Column = m_CurrTable->newChild("Column");
3268 Column->setAttr("ss:Width", 80);
3269 Column = m_CurrTable->newChild("Column");
3270 Column->setAttr("ss:Width", 80);
3271 Column = m_CurrTable->newChild("Column");
3272 Column->setAttr("ss:Width", 40);
3273 Column = m_CurrTable->newChild("Column");
3274 Column->setAttr("ss:Width", 40);
3275 Column = m_CurrTable->newChild("Column");
3276 Column->setAttr("ss:Width", 80);
3277 Column = m_CurrTable->newChild("Column");
3278 Column->setAttr("ss:Width", 80);
3279 Column = m_CurrTable->newChild("Column");
3280 Column->setAttr("ss:Width", 80);
3281 Column = m_CurrTable->newChild("Column");
3282 Column->setAttr("ss:Width", 80);
3284 AddRow();
3285 m_CurrRow->setAttr("ss:StyleID", "s25");
3287 AddCell("Filename");
3288 AddCell("Refs");
3289 AddCell("Texture Size (KB)");
3290 AddCell("Resolution");
3291 AddCell("Mip Levels");
3292 AddCell("Type");
3293 AddCell("Format");
3294 AddCell("Usage");
3295 AddCell("Actual current size (KB)");
3296 AddCell("Last frame used");
3298 int nRows = (int)stats.textures.size();
3299 for (int i = 0; i < nRows; i++)
3301 ITexture* pTexture = stats.textures[i];
3302 AddRow();
3303 // Filename
3304 AddCell(pTexture->GetName());
3305 // Refs
3306 AddCell(pTexture->AddRef() - 1);
3307 pTexture->Release();
3308 // Texture Size
3309 AddCell(pTexture->GetDataSize() / 1024);
3311 char texres[128];
3312 cry_sprintf(texres, "%d x %d", pTexture->GetWidth(), pTexture->GetHeight());
3313 AddCell(texres, CELL_CENTERED);
3315 AddCell(pTexture->GetNumMips());
3316 AddCell(pTexture->GetTypeName(), CELL_CENTERED);
3317 AddCell(pTexture->GetFormatName(), CELL_CENTERED);
3318 int numCopies = 1;
3319 if (pTexture->IsStreamedVirtual())
3320 AddCell("Streamed", CELL_CENTERED);
3321 else
3323 const char* pTexDesc = "Static";
3324 uint32 texFlags = pTexture->GetFlags();
3325 if (texFlags & (FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL | FT_USAGE_UNORDERED_ACCESS))
3326 pTexDesc = "Render Target";
3327 else if (texFlags & (FT_STAGE_UPLOAD | FT_STAGE_READBACK))
3329 pTexDesc = "Dynamic";
3330 numCopies += (texFlags & FT_STAGE_UPLOAD) ? 1 : 0;
3331 numCopies += (texFlags & FT_STAGE_READBACK) ? 1 : 0;
3333 else if (texFlags & FT_USAGE_ATLAS)
3334 pTexDesc = "Atlas";
3335 AddCell(pTexDesc, CELL_CENTERED);
3337 AddCell(numCopies * pTexture->GetDeviceDataSize() / 1024);
3339 char pTexDesc[16];
3340 const uint32 nFrameId = pTexture->GetAccessFrameId();
3341 if (nFrameId == -1)
3343 cry_sprintf(pTexDesc, "Not used");
3345 else
3347 cry_sprintf(pTexDesc, "%u", nFrameId);
3349 AddCell(pTexDesc, CELL_CENTERED);
3353 AddRow();
3354 m_CurrRow->setAttr("ss:StyleID", "s25");
3355 AddCell("");
3358 //////////////////////////////////////////////////////////////////////////
3359 void CStatsToExcelExporter::ExportMemStats(SCryEngineStats& stats)
3361 if (!stats.memInfo.m_pStats)
3362 return;
3364 NewWorksheet("Memory Stats");
3365 FreezeFirstRow();
3367 XmlNodeRef Column;
3368 Column = m_CurrTable->newChild("Column");
3369 Column->setAttr("ss:Width", 300);
3370 Column = m_CurrTable->newChild("Column");
3371 Column->setAttr("ss:Width", 90);
3372 Column = m_CurrTable->newChild("Column");
3373 Column->setAttr("ss:Width", 90);
3374 Column = m_CurrTable->newChild("Column");
3375 Column->setAttr("ss:Width", 90);
3376 Column = m_CurrTable->newChild("Column");
3377 Column->setAttr("ss:Width", 90);
3379 AddRow();
3380 m_CurrRow->setAttr("ss:StyleID", "s25");
3382 AddCell("Section");
3383 AddCell("Size (KB)");
3384 AddCell("Total Size (KB)");
3385 AddCell("Object Count");
3387 AddRow();
3389 for (unsigned i = 0; i < stats.memInfo.m_pStats->size(); ++i)
3391 AddRow();
3392 const CrySizerStats::Component& rComp = (*stats.memInfo.m_pStats)[i];
3394 if (rComp.nDepth < 2)
3396 AddRow(); // Skip one row if primary component.
3397 m_CurrRow->setAttr("ss:StyleID", "s25");
3400 char szDepth[64] = " ";
3401 if (rComp.nDepth < sizeof(szDepth))
3402 szDepth[rComp.nDepth * 2] = '\0';
3404 string sCompDisplayName = szDepth;
3405 sCompDisplayName += rComp.strName;
3407 AddCell(sCompDisplayName.c_str());
3408 //char szSize[32];
3409 //cry_sprintf(szSize, "%s%7.3f", szDepth,rComp.getSizeMBytes() );
3410 //AddCell( szSize );
3411 //cry_sprintf(szSize, "%s%7.3f", szDepth,rComp.getTotalSizeMBytes() );
3412 //AddCell( szSize );
3414 if (rComp.sizeBytes > 0)
3415 AddCell((unsigned int)(rComp.sizeBytes / 1024));
3416 else
3417 AddCell("");
3418 AddCell((unsigned int)(rComp.sizeBytesTotal / 1024));
3420 if (rComp.numObjects > 0)
3422 AddCell((unsigned int)(rComp.numObjects));
3425 //if (rComp.sizeBytesTotal <= m_nMinSubcomponentBytes || rComp.nDepth > m_nMaxSubcomponentDepth)
3426 //continue;
3429 char szDepth[32] = " ..............................";
3430 if (rComp.nDepth < sizeof(szDepth))
3431 szDepth[rComp.nDepth] = '\0';
3433 char szSize[32];
3434 if (rComp.sizeBytes > 0)
3436 if (rComp.sizeBytesTotal > rComp.sizeBytes)
3437 cry_sprintf (szSize, "%7.3f %7.3f", rComp.getTotalSizeMBytes(), rComp.getSizeMBytes());
3438 else
3439 cry_sprintf (szSize, " %7.3f", rComp.getSizeMBytes());
3441 else
3443 assert (rComp.sizeBytesTotal > 0);
3444 cry_sprintf (szSize, "%7.3f ", rComp.getTotalSizeMBytes());
3446 char szCount[16];
3448 if (rComp.numObjects)
3449 cry_sprintf (szCount, "%8u", rComp.numObjects);
3450 else
3451 szCount[0] = '\0';
3453 m_pLog->LogToFile ("%s%-*s:%s%s",szDepth, nNameWidth-rComp.nDepth,rComp.strName.c_str(), szSize, szCount);
3457 //delete m_pStats;
3458 //delete m_pSizer;
3461 //////////////////////////////////////////////////////////////////////////
3463 void CStatsToExcelExporter::ExportStreamingInfo(
3464 SStreamEngineStatistics& stats)
3466 NewWorksheet("Streaming Info");
3468 XmlNodeRef Column;
3469 Column = m_CurrTable->newChild("Column");
3470 Column->setAttr("ss:Width", 400);
3471 Column = m_CurrTable->newChild("Column");
3472 Column->setAttr("ss:Width", 80);
3473 Column = m_CurrTable->newChild("Column");
3474 Column->setAttr("ss:Width", 80);
3476 // overal stats
3477 AddRow();
3478 AddCell("Average Completion Time (ms):", CELL_BOLD);
3479 AddCell(stats.fAverageCompletionTime);
3480 AddRow();
3481 AddCell("Session Read Bandwidth (KB):", CELL_BOLD);
3482 AddCell(stats.nTotalSessionReadBandwidth / (1024.f));
3483 AddRow();
3484 AddCell("Average Decompression Bandwidth (MB):", CELL_BOLD);
3485 AddCell(stats.nDecompressBandwidthAverage / (1024.f * 1024.f));
3486 AddRow();
3487 AddCell("Average Decryption Bandwidth (MB):", CELL_BOLD);
3488 AddCell(stats.nDecryptBandwidthAverage / (1024.f * 1024.f));
3489 AddRow();
3490 AddCell("Average Verification Bandwidth (MB):", CELL_BOLD);
3491 AddCell(stats.nVerifyBandwidthAverage / (1024.f * 1024.f));
3492 AddRow();
3493 AddCell("Bytes Read (MB):", CELL_BOLD);
3494 AddCell(stats.nTotalBytesRead / (1024.f * 1024.f));
3495 AddRow();
3496 AddCell("Request Count:", CELL_BOLD);
3497 AddCell(stats.nTotalRequestCount);
3499 AddRow();
3501 // HDD stats
3502 AddRow();
3503 AddCell("HDD - Average Active Time (%):", CELL_BOLD);
3504 AddCell(stats.hddInfo.fAverageActiveTime);
3505 AddRow();
3506 AddCell("HDD - Session Read Bandwidth (KB):", CELL_BOLD);
3507 AddCell(stats.hddInfo.nSessionReadBandwidth / (1024.f));
3508 AddRow();
3509 AddCell("HDD - Effective Read Bandwidth (KB):", CELL_BOLD);
3510 AddCell(stats.hddInfo.nAverageActualReadBandwidth / (1024.f));
3511 AddRow();
3512 AddCell("HDD - Average Seek Offset (MB):", CELL_BOLD);
3513 AddCell(stats.hddInfo.nAverageSeekOffset / (1024.f * 1024.f));
3514 AddRow();
3515 AddCell("HDD - Bytes Read (MB):", CELL_BOLD);
3516 AddCell(stats.hddInfo.nTotalBytesRead / (1024.f * 1024.f));
3518 AddRow();
3520 // texture stats
3521 AddRow();
3522 AddCell("Texture - Average Completion Time (ms):", CELL_BOLD);
3523 AddCell(stats.typeInfo[eStreamTaskTypeTexture].fAverageCompletionTime);
3524 AddRow();
3525 AddCell("Texture - Session Read Bandwidth (KB):", CELL_BOLD);
3526 AddCell(stats.typeInfo[eStreamTaskTypeTexture].nSessionReadBandwidth / (1024.f));
3527 AddRow();
3528 AddCell("Texture - Request Count:", CELL_BOLD);
3529 AddCell(stats.typeInfo[eStreamTaskTypeTexture].nTotalRequestCount);
3530 AddRow();
3531 AddCell("Texture - Streaming Requests:", CELL_BOLD);
3532 AddCell(stats.typeInfo[eStreamTaskTypeTexture].nTotalStreamingRequestCount);
3533 AddRow();
3534 AddCell("Texture - Total Read Bytes (MB):", CELL_BOLD);
3535 AddCell(stats.typeInfo[eStreamTaskTypeTexture].nTotalReadBytes / (1024.f * 1024.f));
3536 AddRow();
3537 AddCell("Texture - Average Read Size (KB):", CELL_BOLD);
3538 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeTexture].nTotalReadBytes /
3539 max((uint32)1, stats.typeInfo[eStreamTaskTypeTexture].nTotalStreamingRequestCount) / 1024));
3540 AddRow();
3541 AddCell("Texture - Average Request Size (KB):", CELL_BOLD);
3542 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeTexture].nTotalRequestDataSize /
3543 max((uint32)1, stats.typeInfo[eStreamTaskTypeTexture].nTotalStreamingRequestCount) / 1024));
3545 AddRow();
3547 // geometry stats
3548 AddRow();
3549 AddCell("Geometry - Average Completion Time (ms):", CELL_BOLD);
3550 AddCell(stats.typeInfo[eStreamTaskTypeGeometry].fAverageCompletionTime);
3551 AddRow();
3552 AddCell("Geometry - Session Read Bandwidth (KB):", CELL_BOLD);
3553 AddCell(stats.typeInfo[eStreamTaskTypeGeometry].nSessionReadBandwidth / (1024.f));
3554 AddRow();
3555 AddCell("Geometry - Request Count:", CELL_BOLD);
3556 AddCell(stats.typeInfo[eStreamTaskTypeGeometry].nTotalRequestCount);
3557 AddRow();
3558 AddCell("Geometry - Streaming Requests:", CELL_BOLD);
3559 AddCell(stats.typeInfo[eStreamTaskTypeGeometry].nTotalStreamingRequestCount);
3560 AddRow();
3561 AddCell("Geometry - Total Read Bytes (MB):", CELL_BOLD);
3562 AddCell(stats.typeInfo[eStreamTaskTypeGeometry].nTotalReadBytes / (1024.f * 1024.f));
3563 AddRow();
3564 AddCell("Geometry - Average Read Size (KB):", CELL_BOLD);
3565 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeGeometry].nTotalReadBytes /
3566 max((uint32)1, stats.typeInfo[eStreamTaskTypeGeometry].nTotalStreamingRequestCount) / 1024));
3567 AddRow();
3568 AddCell("Geometry - Average Request Size (KB):", CELL_BOLD);
3569 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeGeometry].nTotalRequestDataSize /
3570 max((uint32)1, stats.typeInfo[eStreamTaskTypeGeometry].nTotalStreamingRequestCount) / 1024));
3572 AddRow();
3574 // terrain stats
3575 AddRow();
3576 AddCell("Terrain - Average Completion Time (ms):", CELL_BOLD);
3577 AddCell(stats.typeInfo[eStreamTaskTypeTerrain].fAverageCompletionTime);
3578 AddRow();
3579 AddCell("Terrain - Session Read Bandwidth (KB):", CELL_BOLD);
3580 AddCell(stats.typeInfo[eStreamTaskTypeTerrain].nSessionReadBandwidth / (1024.f));
3581 AddRow();
3582 AddCell("Terrain - Request Count:", CELL_BOLD);
3583 AddCell(stats.typeInfo[eStreamTaskTypeTerrain].nTotalRequestCount);
3584 AddRow();
3585 AddCell("Terrain - Streaming Requests:", CELL_BOLD);
3586 AddCell(stats.typeInfo[eStreamTaskTypeTerrain].nTotalStreamingRequestCount);
3587 AddRow();
3588 AddCell("Terrain - Total Read Bytes (MB):", CELL_BOLD);
3589 AddCell(stats.typeInfo[eStreamTaskTypeTerrain].nTotalReadBytes / (1024.f * 1024.f));
3590 AddRow();
3591 AddCell("Terrain - Average Read Size (KB):", CELL_BOLD);
3592 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeTerrain].nTotalReadBytes /
3593 max((uint32)1, stats.typeInfo[eStreamTaskTypeTerrain].nTotalStreamingRequestCount) / 1024));
3594 AddRow();
3595 AddCell("Terrain - Average Request Size (KB):", CELL_BOLD);
3596 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeTerrain].nTotalRequestDataSize /
3597 max((uint32)1, stats.typeInfo[eStreamTaskTypeTerrain].nTotalStreamingRequestCount) / 1024));
3599 AddRow();
3601 // Animation stats
3602 AddRow();
3603 AddCell("Animation - Average Completion Time (ms):", CELL_BOLD);
3604 AddCell(stats.typeInfo[eStreamTaskTypeAnimation].fAverageCompletionTime);
3605 AddRow();
3606 AddCell("Animation - Session Read Bandwidth (KB):", CELL_BOLD);
3607 AddCell(stats.typeInfo[eStreamTaskTypeAnimation].nSessionReadBandwidth / (1024.f));
3608 AddRow();
3609 AddCell("Animation - Request Count:", CELL_BOLD);
3610 AddCell(stats.typeInfo[eStreamTaskTypeAnimation].nTotalRequestCount);
3611 AddRow();
3612 AddCell("Animation - Streaming Requests:", CELL_BOLD);
3613 AddCell(stats.typeInfo[eStreamTaskTypeAnimation].nTotalStreamingRequestCount);
3614 AddRow();
3615 AddCell("Animation - Total Read Bytes (MB):", CELL_BOLD);
3616 AddCell(stats.typeInfo[eStreamTaskTypeAnimation].nTotalReadBytes / (1024.f * 1024.f));
3617 AddRow();
3618 AddCell("Animation - Average Read Size (KB):", CELL_BOLD);
3619 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeAnimation].nTotalReadBytes /
3620 max((uint32)1, stats.typeInfo[eStreamTaskTypeAnimation].nTotalStreamingRequestCount) / 1024));
3621 AddRow();
3622 AddCell("Animation - Average Request Size (KB):", CELL_BOLD);
3623 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeAnimation].nTotalRequestDataSize /
3624 max((uint32)1, stats.typeInfo[eStreamTaskTypeAnimation].nTotalStreamingRequestCount) / 1024));
3626 AddRow();
3628 // Sound stats
3629 AddRow();
3630 AddCell("Sound - Average Completion Time (ms):", CELL_BOLD);
3631 AddCell(stats.typeInfo[eStreamTaskTypeSound].fAverageCompletionTime);
3632 AddRow();
3633 AddCell("Sound - Session Read Bandwidth (KB):", CELL_BOLD);
3634 AddCell(stats.typeInfo[eStreamTaskTypeSound].nSessionReadBandwidth / (1024.f));
3635 AddRow();
3636 AddCell("Sound - Request Count:", CELL_BOLD);
3637 AddCell(stats.typeInfo[eStreamTaskTypeSound].nTotalRequestCount);
3638 AddRow();
3639 AddCell("Sound - Streaming Requests:", CELL_BOLD);
3640 AddCell(stats.typeInfo[eStreamTaskTypeSound].nTotalStreamingRequestCount);
3641 AddRow();
3642 AddCell("Sound - Total Read Bytes (MB):", CELL_BOLD);
3643 AddCell(stats.typeInfo[eStreamTaskTypeSound].nTotalReadBytes / (1024.f * 1024.f));
3644 AddRow();
3645 AddCell("Sound - Average Read Size (KB):", CELL_BOLD);
3646 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeSound].nTotalReadBytes /
3647 max((uint32)1, stats.typeInfo[eStreamTaskTypeSound].nTotalStreamingRequestCount) / 1024));
3648 AddRow();
3649 AddCell("Sound - Average Request Size (KB):", CELL_BOLD);
3650 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeSound].nTotalRequestDataSize /
3651 max((uint32)1, stats.typeInfo[eStreamTaskTypeSound].nTotalStreamingRequestCount) / 1024));
3653 AddRow();
3655 // Shader stats
3656 AddRow();
3657 AddCell("Shader - Average Completion Time (ms):", CELL_BOLD);
3658 AddCell(stats.typeInfo[eStreamTaskTypeShader].fAverageCompletionTime);
3659 AddRow();
3660 AddCell("Shader - Session Read Bandwidth (KB):", CELL_BOLD);
3661 AddCell(stats.typeInfo[eStreamTaskTypeShader].nSessionReadBandwidth / (1024.f));
3662 AddRow();
3663 AddCell("Shader - Request Count:", CELL_BOLD);
3664 AddCell(stats.typeInfo[eStreamTaskTypeShader].nTotalRequestCount);
3665 AddRow();
3666 AddCell("Shader - Streaming Requests:", CELL_BOLD);
3667 AddCell(stats.typeInfo[eStreamTaskTypeShader].nTotalStreamingRequestCount);
3668 AddRow();
3669 AddCell("Shader - Total Read Bytes (MB):", CELL_BOLD);
3670 AddCell(stats.typeInfo[eStreamTaskTypeShader].nTotalReadBytes / (1024.f * 1024.f));
3671 AddRow();
3672 AddCell("Shader - Average Read Size (KB):", CELL_BOLD);
3673 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeShader].nTotalReadBytes /
3674 max((uint32)1, stats.typeInfo[eStreamTaskTypeShader].nTotalStreamingRequestCount) / 1024));
3675 AddRow();
3676 AddCell("Shader - Average Request Size (KB):", CELL_BOLD);
3677 AddCell((uint32)(stats.typeInfo[eStreamTaskTypeShader].nTotalRequestDataSize /
3678 max((uint32)1, stats.typeInfo[eStreamTaskTypeShader].nTotalStreamingRequestCount) / 1024));
3681 void CStatsToExcelExporter::ExportAnimationInfo(SCryEngineStats& stats)
3683 NewWorksheet("AnimationKeys Info");
3685 XmlNodeRef Column;
3686 Column = m_CurrTable->newChild("Column");
3687 Column->setAttr("ss:Width", 400);
3688 Column = m_CurrTable->newChild("Column");
3689 Column->setAttr("ss:Width", 80);
3690 Column = m_CurrTable->newChild("Column");
3691 Column->setAttr("ss:Width", 80);
3693 // overal stats
3694 AddRow();
3695 AddCell("Animation Keys Current KB:", CELL_BOLD);
3696 AddCell(stats.m_AnimMemoryTracking.m_nAnimsCurrent / 1024);
3697 AddRow();
3698 AddCell("Animation Keys Maximum KB::", CELL_BOLD);
3699 AddCell(stats.m_AnimMemoryTracking.m_nAnimsMax / 1024);
3701 uint64 average = 0;
3702 if (stats.m_AnimMemoryTracking.m_nAnimsCounter)
3703 average = stats.m_AnimMemoryTracking.m_nAnimsAdd / stats.m_AnimMemoryTracking.m_nAnimsCounter;
3704 AddRow();
3705 AddCell("Animation Keys Average KB::", CELL_BOLD);
3706 AddCell(average / 1024);
3707 AddRow();
3708 AddCell("Animation Global Counter::", CELL_BOLD);
3709 AddCell(stats.m_AnimMemoryTracking.m_nGlobalCAFs);
3710 AddRow();
3711 AddCell("Animation Used Global Headers::", CELL_BOLD);
3712 AddCell(stats.m_AnimMemoryTracking.m_nUsedGlobalCAFs);
3714 AddRow();
3715 AddCell("Animation Char Instances Counter::", CELL_BOLD);
3716 AddCell(stats.m_AnimMemoryTracking.m_numTCharInstances);
3717 AddRow();
3718 AddCell("Animation Char Instances Memory::", CELL_BOLD);
3719 AddCell(stats.m_AnimMemoryTracking.m_nTotalCharMemory);
3720 AddRow();
3721 AddCell("Animation Skin Instances Counter::", CELL_BOLD);
3722 AddCell(stats.m_AnimMemoryTracking.m_numTSkinInstances);
3723 AddRow();
3724 AddCell("Animation Skin Instances Memory::", CELL_BOLD);
3725 AddCell(stats.m_AnimMemoryTracking.m_nTotalSkinMemory);
3726 AddRow();
3727 AddCell("Animation Model Counter::", CELL_BOLD);
3728 AddCell(stats.m_AnimMemoryTracking.m_numModels);
3729 AddRow();
3730 AddCell("Animation Model Memory::", CELL_BOLD);
3731 AddCell(stats.m_AnimMemoryTracking.m_nTotalMMemory);
3735 //////////////////////////////////////////////////////////////////////////
3736 void CStatsToExcelExporter::ExportMemInfo(SCryEngineStats& stats)
3738 NewWorksheet("Modules Memory Info");
3739 FreezeFirstRow();
3741 XmlNodeRef Column;
3742 Column = m_CurrTable->newChild("Column");
3743 Column->setAttr("ss:Width", 300);
3744 Column = m_CurrTable->newChild("Column");
3745 Column->setAttr("ss:Width", 90);
3746 Column = m_CurrTable->newChild("Column");
3747 Column->setAttr("ss:Width", 90);
3748 Column = m_CurrTable->newChild("Column");
3749 Column->setAttr("ss:Width", 90);
3750 Column = m_CurrTable->newChild("Column");
3751 Column->setAttr("ss:Width", 20);
3752 Column = m_CurrTable->newChild("Column");
3753 Column->setAttr("ss:Width", 90);
3754 Column = m_CurrTable->newChild("Column");
3755 Column->setAttr("ss:Width", 90);
3756 Column = m_CurrTable->newChild("Column");
3757 Column->setAttr("ss:Width", 90);
3758 Column = m_CurrTable->newChild("Column");
3759 Column->setAttr("ss:Width", 90);
3760 Column = m_CurrTable->newChild("Column");
3761 Column->setAttr("ss:Width", 90);
3762 Column = m_CurrTable->newChild("Column");
3763 Column->setAttr("ss:Width", 90);
3764 Column = m_CurrTable->newChild("Column");
3765 Column->setAttr("ss:Width", 90);
3766 AddRow();
3767 m_CurrRow->setAttr("ss:StyleID", "s25");
3768 AddCell("Module");
3769 AddCell("Dynamic(KB)");
3770 AddCell("Num Allocs");
3771 AddCell("Sum Of Allocs (KB)");
3772 AddCell("");
3773 AddCell("Static Total (KB)");
3774 AddCell("Static Code (KB)");
3775 AddCell("Static Init. Data (KB)");
3776 AddCell("Static Uninit. Data (KB)");
3777 AddCell("Strings (KB)");
3778 AddCell("STL (KB)");
3779 AddCell("STL Wasted (KB)");
3780 AddCell("Dynamic - Wasted (KB)");
3782 AddRow();
3784 //////////////////////////////////////////////////////////////////////////
3785 int nRows = 0;
3787 for (uint32 i = 0; i < stats.memInfo.modules.size(); i++)
3789 SCryEngineStatsModuleInfo& moduleInfo = stats.memInfo.modules[i];
3790 const char* szModule = moduleInfo.name;
3792 AddRow();
3793 nRows++;
3794 AddCell(szModule, CELL_BOLD);
3795 AddCell(moduleInfo.usedInModule / 1024);
3796 AddCell(moduleInfo.memInfo.num_allocations);
3797 AddCell(moduleInfo.memInfo.allocated / 1024);
3798 AddCell("");
3799 AddCell(moduleInfo.moduleStaticSize / 1024);
3800 AddCell((uint32)moduleInfo.SizeOfCode / 1024);
3801 AddCell((uint32)moduleInfo.SizeOfInitializedData / 1024);
3802 AddCell((uint32)moduleInfo.SizeOfUninitializedData / 1024);
3803 AddCell((uint32)(moduleInfo.memInfo.CryString_allocated / 1024));
3804 AddCell((uint32)(moduleInfo.memInfo.STL_allocated / 1024));
3805 AddCell((uint32)(moduleInfo.memInfo.STL_wasted / 1024));
3806 AddCell((uint32)((moduleInfo.memInfo.allocated - moduleInfo.memInfo.requested) / 1024));
3809 AddRow();
3810 AddCell("");
3811 m_CurrRow->setAttr("ss:StyleID", "s25");
3812 AddCell_SumOfRows(nRows);
3813 AddCell_SumOfRows(nRows);
3814 AddCell_SumOfRows(nRows);
3815 AddCell("");
3816 AddCell_SumOfRows(nRows);
3817 AddCell_SumOfRows(nRows);
3818 AddCell_SumOfRows(nRows);
3820 AddRow();
3822 AddRow();
3823 AddCell("Lua Memory Usage (KB)", CELL_BOLD);
3824 AddCell(stats.nSummaryScriptSize / (1024));
3825 AddRow();
3826 AddCell("Total Num Allocs", CELL_BOLD);
3827 AddCell(stats.memInfo.totalNumAllocsInModules);
3828 AddRow();
3829 AddCell("Total Allocated (KB)", CELL_BOLD);
3830 AddCell(stats.memInfo.totalUsedInModules / 1024);
3831 AddRow();
3832 AddCell("Total Code and Static (KB)", CELL_BOLD);
3833 AddCell(stats.memInfo.totalCodeAndStatic / 1024);
3834 AddRow();
3835 AddRow();
3836 AddRow();
3837 AddCell("API Textures (KB)", CELL_BOLD);
3838 AddCell((uint32)((stats.nSummary_TexturesPoolSize + stats.nSummary_UserTextureSize + stats.nSummary_EngineTextureSize) / (1024 * 1024)));
3839 AddRow();
3840 AddCell("API Meshes (KB)", CELL_BOLD);
3841 AddCell(stats.nAPI_MeshSize / 1024);
3844 //////////////////////////////////////////////////////////////////////////
3845 void CStatsToExcelExporter::ExportTimeDemoInfo()
3847 STimeDemoInfo* pTD = gEnv->pGameFramework->GetITimeDemoRecorder()->GetLastPlayedTimeDemo();
3848 if (!pTD)
3849 return;
3851 NewWorksheet("TimeDemo");
3852 FreezeFirstRow();
3854 XmlNodeRef Column;
3855 Column = m_CurrTable->newChild("Column");
3856 Column->setAttr("ss:Width", 400);
3857 Column = m_CurrTable->newChild("Column");
3858 Column->setAttr("ss:Width", 80);
3859 Column = m_CurrTable->newChild("Column");
3860 Column->setAttr("ss:Width", 80);
3862 AddRow();
3863 AddCell("Play Time:", CELL_BOLD);
3864 AddCell(pTD->lastPlayedTotalTime);
3865 AddRow();
3866 AddCell("Num Frames:", CELL_BOLD);
3867 AddCell((int)pTD->frames.size());
3868 AddRow();
3869 AddCell("Average FPS:", CELL_BOLD);
3870 AddCell(pTD->lastAveFrameRate);
3871 AddRow();
3872 AddCell("Min FPS:", CELL_BOLD);
3873 AddCell(pTD->minFPS);
3874 AddCell("At Frame:");
3875 AddCell(pTD->minFPS_Frame);
3876 AddRow();
3877 AddCell("Max FPS:", CELL_BOLD);
3878 AddCell(pTD->maxFPS);
3879 AddCell("At Frame:");
3880 AddCell(pTD->maxFPS_Frame);
3881 AddRow();
3882 AddCell("Average Tri/Sec:", CELL_BOLD);
3883 AddCell((uint32)((float)pTD->nTotalPolysPlayed / pTD->lastPlayedTotalTime));
3884 AddRow();
3885 AddCell("Average Tri/Frame:", CELL_BOLD);
3886 AddCell((uint32)((float)pTD->nTotalPolysPlayed / pTD->frames.size()));
3887 AddRow();
3888 AddCell("Played/Recorded Tris ratio:", CELL_BOLD);
3889 AddCell(pTD->nTotalPolysRecorded ? (float)pTD->nTotalPolysPlayed / pTD->nTotalPolysRecorded : 0.f);
3891 //////////////////////////////////////////////////////////////////////////
3892 NewWorksheet("TimeDemoFrames");
3893 FreezeFirstRow();
3895 Column = m_CurrTable->newChild("Column");
3896 Column->setAttr("ss:Width", 80);
3897 Column = m_CurrTable->newChild("Column");
3898 Column->setAttr("ss:Width", 80);
3899 Column = m_CurrTable->newChild("Column");
3900 Column->setAttr("ss:Width", 80);
3901 AddRow();
3902 m_CurrRow->setAttr("ss:StyleID", "s25");
3903 AddCell("Frame Number");
3904 AddCell("Frame Rate");
3905 AddCell("Rendered Polygons");
3906 AddCell("Draw Calls");
3908 AddRow();
3910 for (int i = 0; i < pTD->frames.size(); i++)
3912 AddRow();
3913 AddCell(i);
3914 AddCell(pTD->frames[i].fFrameRate);
3915 AddCell(pTD->frames[i].nPolysRendered);
3916 AddCell(pTD->frames[i].nDrawCalls);
3920 void CStatsToExcelExporter::ExportFPSBuckets()
3922 //get perfHUD Export stats
3923 ICryPerfHUD* perfHUD = GetISystem()->GetPerfHUD();
3925 if (perfHUD)
3927 float totalTime = 0;
3928 const std::vector<ICryPerfHUD::PerfBucket>* fpsBuckets = perfHUD->GetFpsBuckets(totalTime);
3930 if (fpsBuckets && totalTime > 0.f)
3932 int numBuckets = fpsBuckets->size();
3934 AddRow();
3935 AddRow();
3936 m_CurrRow->setAttr("ss:StyleID", "s25");
3938 AddCell("Frame Rate Bucket");
3939 AddCell("Time Spent%");
3941 for (int i = 0; i < numBuckets; i++)
3943 AddRow();
3945 char buf[32];
3946 cry_sprintf(buf, ">=%.1f FPS", fpsBuckets->at(i).target);
3947 AddCell(buf);
3949 float percentAtTarget = 100.f * (fpsBuckets->at(i).timeAtTarget / totalTime);
3950 AddCell(percentAtTarget);
3956 //////////////////////////////////////////////////////////////////////////
3957 static void SaveLevelStats(IConsoleCmdArgs* pArgs)
3959 #if !defined(_RELEASE)
3961 auto levelName = gEnv->pGameFramework->GetLevelName();
3962 if (!levelName || !*levelName)
3964 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Cannot save level statistics because level is not loaded.");
3965 return;
3968 CryLog("Execute SaveLevelStats");
3970 SCOPED_ALLOW_FILE_ACCESS_FROM_THIS_THREAD();
3973 string levelName = "no_level";
3975 ICVar* sv_map = gEnv->pConsole->GetCVar("sv_map");
3976 if (sv_map)
3977 levelName = sv_map->GetString();
3979 levelName = PathUtil::GetFileName(levelName);
3981 bool bDepends = true;
3982 if (pArgs->GetArgCount() > 1)
3983 bDepends = true;
3985 CEngineStats engineStats(bDepends);
3987 // level.xml
3989 CStatsToExcelExporter excelExporter;
3991 string filename = PathUtil::ReplaceExtension(levelName, "xml");
3993 excelExporter.ExportToFile(engineStats.m_stats, filename);
3995 CryLog("SaveLevelStats exported '%s'", filename.c_str());
3998 // level_dependencies.xml
3999 if (bDepends)
4001 CStatsToExcelExporter excelExporter;
4003 engineStats.m_ResourceCollector.ComputeDependencyCnt();
4005 string filename = PathUtil::ReplaceExtension(string("depends_") + levelName, "xml");
4007 excelExporter.ExportDependenciesToFile(engineStats.m_ResourceCollector, filename);
4009 // log to log file - modifies engineStats.m_ResourceCollector data
4010 // engineStats.m_ResourceCollector.LogData(*gEnv->pLog);
4011 CryLog("SaveLevelStats exported '%s'", filename.c_str());
4015 #endif
4018 #else // (!defined (_RELEASE) || defined(ENABLE_PROFILING_CODE))
4020 bool QueryModuleMemoryInfo(SCryEngineStatsModuleInfo& moduleInfo, int index)
4022 return false;
4025 #endif // (!defined (_RELEASE) || defined(ENABLE_PROFILING_CODE))
4027 void RegisterEngineStatistics()
4029 #if (!defined (_RELEASE) || defined(ENABLE_PROFILING_CODE))
4030 REGISTER_COMMAND("SaveLevelStats", SaveLevelStats, 0,
4031 "Calling this command creates multiple XML files with level statistics.\n"
4032 "The data includes file usage, dependencies, size in more/disk.\n"
4033 "The files can be loaded in Excel.");
4034 #endif