2991 lines
95 KiB
C++
2991 lines
95 KiB
C++
![]() |
#include "AutoGPUCapture.h"
|
||
|
|
||
|
#include "grcore/device.h"
|
||
|
#include "grprofile/timebars.h"
|
||
|
#include "parser/manager.h"
|
||
|
#include "parser/visitorxml.h"
|
||
|
#include "system/param.h"
|
||
|
#include "system/memory.h"
|
||
|
#include "system/simpleallocator.h"
|
||
|
|
||
|
|
||
|
#include "fwdrawlist/drawlistmgr.h"
|
||
|
#include "fwsys/timer.h"
|
||
|
|
||
|
#include "debug/Debug.h"
|
||
|
#include "debug/DebugLocation.h"
|
||
|
#include "peds/ped.h"
|
||
|
#include "peds/pedpopulation.h"
|
||
|
#include "system/controlmgr.h"
|
||
|
#include "system/FileMgr.h"
|
||
|
#include "scene/world/GameWorld.h"
|
||
|
#include "streaming/streamingdebuggraph.h"
|
||
|
#include "text/text.h"
|
||
|
#include "text/textconversion.h"
|
||
|
#include "script/script.h"
|
||
|
#include "vehicles/vehiclepopulation.h"
|
||
|
|
||
|
#include "grmodel/setup.h"
|
||
|
#include <limits>
|
||
|
|
||
|
#if !__FINAL
|
||
|
#include "Network/Live/NetworkDebugTelemetry.h"
|
||
|
#endif
|
||
|
|
||
|
#if ENABLE_STATS_CAPTURE
|
||
|
|
||
|
|
||
|
//OPTIMISATIONS_OFF()
|
||
|
|
||
|
|
||
|
#include "AutoGPUCapture_parser.h"
|
||
|
|
||
|
extern void GetLoadedSizesSafe(strStreamingModule &module, strLocalIndex objIndex, int &outVirtSize, int &outPhysSize);
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
namespace MetricsCapture
|
||
|
{
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
PARAM(startAutoMetricsCapture,"start automated metrics capture");
|
||
|
PARAM(startAutoGPUCapture,"start automated metrics capture"); // deprecated
|
||
|
PARAM(autocapturepath,"[system] Specify a path for the files stored by the automatic metrics capture");
|
||
|
PARAM(autocaptureCL, "Specify the CL used to generate this build");
|
||
|
|
||
|
#if __WIN32PC
|
||
|
PARAM(fpsCaptureUseUserFolder, "Force the output folder for the metrics xml files to be the user one");
|
||
|
PARAM(fpsCaptureExtraPath, "extra path to be appenned after the user folder");
|
||
|
#endif
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
#define DEBUG_METRICS_CAPTURES 0
|
||
|
|
||
|
//MUST match those values used in SmokeTest tools project (C#), which are based on RSG.Platform.RagebuilderPlatform
|
||
|
#define PLATFORM_STRING __XENON == 1 ? "xbox360" : (__PS3 == 1 ? "ps3" : (RSG_DURANGO == 1 ? "durango" : (RSG_ORBIS == 1 ? "orbis" : (RSG_CPU_X64 == 1 ? "win64" : (__WIN32 == 1 ? "win32" : "??")))))
|
||
|
|
||
|
// yuck
|
||
|
const int MEMBUCKET_SLOSH = MEMBUCKET_DEBUG + 1;
|
||
|
|
||
|
|
||
|
enum MemoryHeapIds
|
||
|
{
|
||
|
MEMHEAP_INVALID = -1,
|
||
|
MEMHEAP_GAME_VIRTUAL = 0,
|
||
|
MEMHEAP_RESOURCE_VIRTUAL,
|
||
|
MEMHEAP_DEBUG_VIRTUAL,
|
||
|
MEMHEAP_STREAMING_VIRTUAL,
|
||
|
MEMHEAP_EXTERNAL_VIRTUAL,
|
||
|
MEMHEAP_SLOSH_VIRTUAL,
|
||
|
MEMHEAP_SMALL_ALLOCATOR
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static const int NOT_SAMPLING = -1;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
class MutexHelper
|
||
|
{
|
||
|
public:
|
||
|
MutexHelper()
|
||
|
{
|
||
|
rage::sysIpcLockMutex(sm_Mutex);
|
||
|
}
|
||
|
~MutexHelper()
|
||
|
{
|
||
|
rage::sysIpcUnlockMutex(sm_Mutex);
|
||
|
}
|
||
|
public:
|
||
|
static rage::sysIpcMutex sm_Mutex;
|
||
|
};
|
||
|
|
||
|
rage::sysIpcMutex MutexHelper::sm_Mutex = NULL;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
class CMetricsCaptureWindow
|
||
|
{
|
||
|
public:
|
||
|
CMetricsCaptureWindow(const debugLocationMetricsList & data)
|
||
|
: m_Data(data)
|
||
|
, m_Left(0.5f)
|
||
|
, m_Right(0.95f)
|
||
|
, m_Bottom(0.75f)
|
||
|
, m_Top(0.5f)
|
||
|
, m_Split(0.7f)
|
||
|
, m_SplitPadding(0.01f)
|
||
|
, m_ZoneTextSize(0.4f, 0.4f)
|
||
|
, m_MetricTextSize(0.28f, 0.28f)
|
||
|
, m_ScreenWidth(0.0f)
|
||
|
, m_ScreenHeight(0.0f)
|
||
|
, m_ZoneTextHeight(0.0f)
|
||
|
, m_MetricTextHeight(0.0f)
|
||
|
, m_PaddingBetweenZones(0.0f)
|
||
|
, m_ScrollOffset(0.0f)
|
||
|
, m_YPos(0.0f)
|
||
|
, m_LastLength(0.0f)
|
||
|
{
|
||
|
m_LabelTextLayout.SetColor(Color32(255, 255, 255, 255));
|
||
|
m_LabelTextLayout.SetOrientation(FONT_RIGHT);
|
||
|
|
||
|
m_DataTextLayout.SetColor(Color32(255, 255, 255, 255));
|
||
|
m_DataTextLayout.SetOrientation(FONT_LEFT);
|
||
|
|
||
|
Move(0.5f, 0.5f);
|
||
|
}
|
||
|
|
||
|
void Draw()
|
||
|
{
|
||
|
m_ScrollOffset += CControlMgr::GetKeyboard().GetKeyDown(KEY_UP) ? 0.01f : 0.0f;
|
||
|
m_ScrollOffset -= CControlMgr::GetKeyboard().GetKeyDown(KEY_DOWN) ? 0.01f : 0.0f;
|
||
|
m_ScrollOffset = Clamp(m_ScrollOffset, -(m_LastLength-(m_Bottom-m_Top)), 0.0f);
|
||
|
m_YPos = m_Top + m_ScrollOffset;
|
||
|
|
||
|
m_ScreenWidth = (float)grcViewport::GetDefaultScreen()->GetWidth();
|
||
|
m_ScreenHeight = (float)grcViewport::GetDefaultScreen()->GetHeight();
|
||
|
m_ZoneTextHeight = 24.0f / m_ScreenHeight;
|
||
|
m_MetricTextHeight = 16.0f / m_ScreenHeight;
|
||
|
m_PaddingBetweenZones = 16.0f / m_ScreenHeight;
|
||
|
|
||
|
DrawBackground();
|
||
|
|
||
|
const debugLocationMetricsList * resultList = &m_Data;
|
||
|
|
||
|
for(int zoneIndex = 0; zoneIndex < resultList->results.size(); ++zoneIndex)
|
||
|
{
|
||
|
metricsList * metrics = resultList->results[zoneIndex];
|
||
|
|
||
|
BeginZone(metrics->name);
|
||
|
|
||
|
if(metrics->fpsResult)
|
||
|
{
|
||
|
framesPerSecondResult * fpsResult = metrics->fpsResult;
|
||
|
BeginMetric("Frames Per Second");
|
||
|
DrawAverageMinMax("", fpsResult->average, fpsResult->min, fpsResult->max);
|
||
|
EndMetric();
|
||
|
}
|
||
|
|
||
|
if(metrics->msPFResult)
|
||
|
{
|
||
|
msPerFrameResult *msPFResult = metrics->msPFResult;
|
||
|
BeginMetric("Millseconds per Frame");
|
||
|
DrawAverageMinMax("", msPFResult->average, msPFResult->min, msPFResult->max);
|
||
|
EndMetric();
|
||
|
}
|
||
|
|
||
|
for(int threadResultIndex = 0; threadResultIndex < metrics->threadResults.size(); ++threadResultIndex)
|
||
|
{
|
||
|
threadTimingResult *threadResult = metrics->threadResults[threadResultIndex];
|
||
|
snprintf(m_Text, MAX_TEXT_LENGTH, "%s", threadResult->name.c_str());
|
||
|
BeginMetric(m_Text);
|
||
|
DrawAverageMinMax("ms", threadResult->average, threadResult->min, threadResult->max);
|
||
|
EndMetric();
|
||
|
}
|
||
|
|
||
|
for(int cpuResultIndex = 0; cpuResultIndex < metrics->cpuResults.size(); ++cpuResultIndex)
|
||
|
{
|
||
|
cpuTimingResult * cpuResult = metrics->cpuResults[cpuResultIndex];
|
||
|
snprintf(m_Text, MAX_TEXT_LENGTH, "%s - %s", cpuResult->set.c_str(), cpuResult->name.c_str());
|
||
|
BeginMetric(m_Text);
|
||
|
DrawAverageMinMax("ms", cpuResult->average, cpuResult->min, cpuResult->max);
|
||
|
EndMetric();
|
||
|
}
|
||
|
|
||
|
EndZone();
|
||
|
}
|
||
|
|
||
|
m_LastLength = m_YPos - (m_Top + m_ScrollOffset);
|
||
|
}
|
||
|
|
||
|
void Move(float x, float y)
|
||
|
{
|
||
|
m_LabelTextLayout.SetWrap(Vector2(0.0f, m_Split - m_SplitPadding));
|
||
|
m_DataTextLayout.SetWrap(Vector2(m_Split + m_SplitPadding, m_Right));
|
||
|
|
||
|
float width = m_Right - m_Left;
|
||
|
float height = m_Bottom - m_Top;
|
||
|
float splitDistance = m_Split - m_Left;
|
||
|
|
||
|
m_Left = x;
|
||
|
m_Right = x + width;
|
||
|
m_Top = y;
|
||
|
m_Bottom = y + height;
|
||
|
m_Split = x + splitDistance;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
bool IsSpaceForRow(float rowHeight)
|
||
|
{
|
||
|
return (m_Bottom - m_YPos) >= rowHeight;
|
||
|
}
|
||
|
|
||
|
bool IsRowVisible(float rowHeight)
|
||
|
{
|
||
|
return m_YPos >= m_Top && IsSpaceForRow(rowHeight);
|
||
|
}
|
||
|
|
||
|
void DrawBackground()
|
||
|
{
|
||
|
fwRect bgRect(m_Left * m_ScreenWidth, m_Bottom * m_ScreenHeight, m_Right * m_ScreenWidth, m_Top * m_ScreenHeight);
|
||
|
Color32 bgColour(0, 0, 0, 128);
|
||
|
CSprite2d::DrawRectSlow(bgRect, bgColour);
|
||
|
}
|
||
|
|
||
|
void BeginZone(const char * name)
|
||
|
{
|
||
|
if(IsRowVisible(m_MetricTextHeight))
|
||
|
{
|
||
|
snprintf(m_Text, MAX_TEXT_LENGTH, "%s", name);
|
||
|
m_LabelTextLayout.SetScale(m_ZoneTextSize);
|
||
|
m_LabelTextLayout.Render(Vector2(m_Left, m_YPos), m_Text);
|
||
|
}
|
||
|
m_YPos += m_ZoneTextHeight;
|
||
|
}
|
||
|
|
||
|
void EndZone()
|
||
|
{
|
||
|
m_YPos += m_PaddingBetweenZones;
|
||
|
}
|
||
|
|
||
|
void BeginMetric(const char * name)
|
||
|
{
|
||
|
DrawDataLabel(name);
|
||
|
}
|
||
|
|
||
|
void EndMetric()
|
||
|
{
|
||
|
m_YPos += m_MetricTextHeight;
|
||
|
}
|
||
|
|
||
|
void DrawAverageMinMax(const char * suffix, float average, float min, float max)
|
||
|
{
|
||
|
snprintf(m_Text, MAX_TEXT_LENGTH, "%.1f%s [%.1f%s, %.1f%s]", average, suffix, min, suffix, max, suffix);
|
||
|
DrawData(m_Text);
|
||
|
}
|
||
|
|
||
|
void DrawDataLabel(const char * text)
|
||
|
{
|
||
|
if(IsRowVisible(m_MetricTextHeight))
|
||
|
{
|
||
|
m_LabelTextLayout.SetScale(m_MetricTextSize);
|
||
|
m_LabelTextLayout.Render(Vector2(m_Left, m_YPos), text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void DrawData(const char * text)
|
||
|
{
|
||
|
if(IsRowVisible(m_MetricTextHeight))
|
||
|
{
|
||
|
m_DataTextLayout.SetScale(m_MetricTextSize); //todo: why do we need to set scale here?
|
||
|
m_DataTextLayout.Render(Vector2(m_Split + m_SplitPadding, m_YPos), text );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const debugLocationMetricsList & m_Data;
|
||
|
|
||
|
float m_Left;
|
||
|
float m_Right;
|
||
|
float m_Bottom;
|
||
|
float m_Top;
|
||
|
float m_Split;
|
||
|
float m_SplitPadding;
|
||
|
Vector2 m_ZoneTextSize;
|
||
|
Vector2 m_MetricTextSize;
|
||
|
float m_ScreenWidth;
|
||
|
float m_ScreenHeight;
|
||
|
float m_ZoneTextHeight;
|
||
|
float m_MetricTextHeight;
|
||
|
float m_PaddingBetweenZones;
|
||
|
float m_ScrollOffset;
|
||
|
float m_YPos;
|
||
|
float m_LastLength;
|
||
|
|
||
|
static const int MAX_TEXT_LENGTH = 200;
|
||
|
char m_Text[MAX_TEXT_LENGTH];
|
||
|
CTextLayout m_LabelTextLayout;
|
||
|
CTextLayout m_DataTextLayout;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
struct CPUTiming
|
||
|
{
|
||
|
const char * name;
|
||
|
int timingSet;
|
||
|
bool optional;
|
||
|
SampledValue<float> value;
|
||
|
int callCountThisFrame;
|
||
|
float timeThisFrame;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
struct ThreadTiming
|
||
|
{
|
||
|
const char * name;
|
||
|
int timingSet;
|
||
|
SampledValue<float> value;
|
||
|
float timeThisFrame;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
typedef atArray<CPUTiming> TimingArray;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
typedef atArray<ThreadTiming> ThreadTimingArray;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
struct MemoryBucketUsage
|
||
|
{
|
||
|
MemoryBucketIds bucket;
|
||
|
|
||
|
SampledValue<u32> gameVirtual;
|
||
|
SampledValue<u32> gamePhysical;
|
||
|
SampledValue<u32> resourceVirtual;
|
||
|
SampledValue<u32> resourcePhysical;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
struct DrawListCount
|
||
|
{
|
||
|
int id;
|
||
|
SampledValue<u32> value;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
class ScriptMemoryUsage
|
||
|
{
|
||
|
public:
|
||
|
SampledValue<u32> physicalMem;
|
||
|
SampledValue<u32> virtualMem;
|
||
|
};
|
||
|
|
||
|
void InitScriptMemResult(ScriptMemoryUsage &result)
|
||
|
{
|
||
|
result.physicalMem.Reset();
|
||
|
result.virtualMem.Reset();
|
||
|
}
|
||
|
|
||
|
// Do I need to wrap this entire function in #if __SCRIPT_MEM_CALC
|
||
|
void UpdateScriptMemResult( ScriptMemoryUsage &result )
|
||
|
{
|
||
|
u32 phys = 0;
|
||
|
u32 virt = 0;
|
||
|
#if __SCRIPT_MEM_CALC
|
||
|
phys = CTheScripts::GetScriptHandlerMgr().GetTotalScriptPhysicalMemory();
|
||
|
virt = CTheScripts::GetScriptHandlerMgr().GetTotalScriptVirtualMemory();
|
||
|
#endif // __SCRIPT_MEM_CALC
|
||
|
result.physicalMem.AddSample(phys);
|
||
|
result.virtualMem.AddSample(virt);
|
||
|
}
|
||
|
|
||
|
void StoreScriptMemResult(debugLocationMetricsList * resultList, const ScriptMemoryUsage &result)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Script metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
scriptMemoryUsageResult * pResult = rage_new scriptMemoryUsageResult;
|
||
|
|
||
|
pResult->physicalMem.average = result.physicalMem.Mean();
|
||
|
pResult->physicalMem.min = result.physicalMem.Min();
|
||
|
pResult->physicalMem.max = result.physicalMem.Max();
|
||
|
pResult->physicalMem.std = result.physicalMem.StandardDeviation();
|
||
|
pResult->virtualMem.average = result.virtualMem.Mean();
|
||
|
pResult->virtualMem.min = result.virtualMem.Min();
|
||
|
pResult->virtualMem.max = result.virtualMem.Max();
|
||
|
pResult->virtualMem.std = result.virtualMem.StandardDeviation();
|
||
|
resultList->results.Top()->scriptMemResult = pResult;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class StreamingStats
|
||
|
{
|
||
|
public:
|
||
|
SampledValue<u32> requested;
|
||
|
SampledValue<u32> loaded;
|
||
|
};
|
||
|
|
||
|
typedef atArray<StreamingStats> StreamingStatsArray;
|
||
|
|
||
|
void InitStreamingStats(StreamingStatsArray &result)
|
||
|
{
|
||
|
result.Reset();
|
||
|
|
||
|
#if TRACK_PLACE_STATS
|
||
|
int modules = strStreamingEngine::GetInfo().GetModuleMgr().GetNumberOfModules();
|
||
|
|
||
|
for (int i=0; i<modules; ++i)
|
||
|
{
|
||
|
strStreamingModule* pModule = strStreamingEngine::GetInfo().GetModuleMgr().GetModule(i);
|
||
|
|
||
|
pModule->UpdatePlaceStats();
|
||
|
}
|
||
|
#endif // TRACK_PLACE_STATS
|
||
|
}
|
||
|
|
||
|
void UpdateStreamingStats( StreamingStatsArray &TRACK_PLACE_STATS_ONLY(result) )
|
||
|
{
|
||
|
#if TRACK_PLACE_STATS
|
||
|
int modules = strStreamingEngine::GetInfo().GetModuleMgr().GetNumberOfModules();
|
||
|
|
||
|
if (result.GetCount() == 0)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
result.Resize(modules);
|
||
|
}
|
||
|
|
||
|
for (int i=0; i<modules; ++i)
|
||
|
{
|
||
|
strStreamingModule* pModule = strStreamingEngine::GetInfo().GetModuleMgr().GetModule(i);
|
||
|
|
||
|
u32 requestedSize = (u32)pModule->GetRequestedSize();
|
||
|
u32 loadedSize = (u32)pModule->GetLoadedSize();
|
||
|
|
||
|
pModule->UpdatePlaceStats();
|
||
|
|
||
|
result[i].loaded.AddSample(loadedSize);
|
||
|
result[i].requested.AddSample(requestedSize);
|
||
|
}
|
||
|
#endif // TRACK_PLACE_STATS
|
||
|
}
|
||
|
|
||
|
void StoreStreamingStats(debugLocationMetricsList * TRACK_PLACE_STATS_ONLY(resultList), const StreamingStatsArray &TRACK_PLACE_STATS_ONLY(result))
|
||
|
{
|
||
|
#if TRACK_PLACE_STATS
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Script metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
int modules = strStreamingEngine::GetInfo().GetModuleMgr().GetNumberOfModules();
|
||
|
for (int i=0; i<modules; ++i)
|
||
|
{
|
||
|
strStreamingModule* pModule = strStreamingEngine::GetInfo().GetModuleMgr().GetModule(i);
|
||
|
streamingStatsResult* pResult = rage_new streamingStatsResult;
|
||
|
|
||
|
pResult->name = pModule->GetModuleName();
|
||
|
|
||
|
pResult->avgLoaded = result[i].loaded.Mean();
|
||
|
pResult->minLoaded = result[i].loaded.Min();
|
||
|
pResult->maxLoaded = result[i].loaded.Max();
|
||
|
pResult->stdLoaded = result[i].loaded.StandardDeviation();
|
||
|
pResult->totalLoaded = result[i].loaded.Sum();
|
||
|
|
||
|
pResult->avgRequested = result[i].requested.Mean();
|
||
|
pResult->minRequested = result[i].requested.Min();
|
||
|
pResult->maxRequested = result[i].requested.Max();
|
||
|
pResult->stdRequested = result[i].requested.StandardDeviation();
|
||
|
pResult->totalRequested = result[i].requested.Sum();
|
||
|
|
||
|
resultList->results.Top()->streamingStatsResults.Grow() = pResult;
|
||
|
}
|
||
|
}
|
||
|
#endif // TRACK_PLACE_STATS
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
|
||
|
void StoreStreamingModuleMemory(debugLocationMetricsList * resultList )
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Streaming module metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
strStreamingInfoManager &strInfoManager = strStreamingEngine::GetInfo();
|
||
|
strStreamingModuleMgr &moduleMgr = strStreamingEngine::GetInfo().GetModuleMgr();
|
||
|
|
||
|
int numModules = moduleMgr.GetNumberOfModules();
|
||
|
|
||
|
//stupidly slow
|
||
|
for(int moduleId=0;moduleId<numModules;moduleId++)
|
||
|
{
|
||
|
strStreamingModule *pModule = moduleMgr.GetModule(moduleId);
|
||
|
streamingModuleResult* pResult = rage_new streamingModuleResult;
|
||
|
|
||
|
pResult->moduleName = pModule->GetModuleName();
|
||
|
pResult->moduleId = moduleId;
|
||
|
pResult->loadedMemPhys = 0;
|
||
|
pResult->loadedMemVirt = 0;
|
||
|
pResult->requiredMemPhys = 0;
|
||
|
pResult->requiredMemVirt = 0;
|
||
|
|
||
|
// Types to track:- Loaded, Referenced/Required.
|
||
|
for(s32 objIdx = 0; objIdx < pModule->GetCount(); ++objIdx)
|
||
|
{
|
||
|
if(pModule->IsObjectInImage(strLocalIndex(objIdx)))
|
||
|
{
|
||
|
strIndex streamingIndex = pModule->GetStreamingIndex(strLocalIndex(objIdx));
|
||
|
strStreamingInfo *info = strStreamingEngine::GetInfo().GetStreamingInfo(streamingIndex);
|
||
|
bool bRequired = pModule->IsObjectRequired(strLocalIndex(objIdx) );
|
||
|
int iNumRefs = pModule->GetNumRefs(strLocalIndex(objIdx));
|
||
|
|
||
|
// only count non "cached" modules
|
||
|
if( !info->IsFlagSet(STRFLAG_INTERNAL_DUMMY) &&
|
||
|
(bRequired || iNumRefs > 0))
|
||
|
{
|
||
|
bool bLoaded = strInfoManager.HasObjectLoaded(streamingIndex);
|
||
|
bool bReferenced = bLoaded && ( iNumRefs > 0 || info->GetDependentCount() > 0 );
|
||
|
|
||
|
int virt;
|
||
|
int phys;
|
||
|
|
||
|
GetLoadedSizesSafe(*pModule, strLocalIndex(objIdx), virt, phys );
|
||
|
|
||
|
if(bLoaded)
|
||
|
{
|
||
|
pResult->loadedMemPhys += phys;
|
||
|
pResult->loadedMemVirt += virt;
|
||
|
}
|
||
|
|
||
|
if(bReferenced || bRequired)
|
||
|
{
|
||
|
pResult->requiredMemPhys += phys;
|
||
|
pResult->requiredMemVirt += virt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
resultList->results.Top()->streamingModuleResults.Grow() = pResult;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class MemoryDistributionUsage
|
||
|
{
|
||
|
public:
|
||
|
SampledValue<u32> physicalUsedBySize;
|
||
|
SampledValue<u32> physicalFreeBySize;
|
||
|
|
||
|
SampledValue<u32> virtualUsedBySize;
|
||
|
SampledValue<u32> virtualFreeBySize;
|
||
|
};
|
||
|
|
||
|
typedef atArray<MemoryDistributionUsage> MemoryDistributionArray;
|
||
|
|
||
|
void InitMemDistributionResult(MemoryDistributionArray &result)
|
||
|
{
|
||
|
result.Reset();
|
||
|
}
|
||
|
|
||
|
void UpdateMemDistributionResult( MemoryDistributionArray &result )
|
||
|
{
|
||
|
sysMemDistribution distV;
|
||
|
|
||
|
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryDistribution(distV);
|
||
|
#if __PS3 || RSG_PC
|
||
|
sysMemDistribution distP;
|
||
|
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_RESOURCE_PHYSICAL)->GetMemoryDistribution(distP);
|
||
|
#endif // __PS3
|
||
|
|
||
|
if (result.GetCount() == 0)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
result.Resize(NUM_MEMORY_DISTRIBUTION_BUCKETS);
|
||
|
}
|
||
|
|
||
|
for(int i=0;i<NUM_MEMORY_DISTRIBUTION_BUCKETS;i++)
|
||
|
{
|
||
|
result[i].virtualUsedBySize.AddSample(distV.UsedBySize[i]);
|
||
|
result[i].virtualFreeBySize.AddSample(distV.FreeBySize[i]);
|
||
|
|
||
|
#if __PS3
|
||
|
result[i].physicalUsedBySize.AddSample(distP.UsedBySize[i]);
|
||
|
result[i].physicalFreeBySize.AddSample(distP.FreeBySize[i]);
|
||
|
#endif // __PS3
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void StoreMemDistributionResult(debugLocationMetricsList * resultList, const MemoryDistributionArray &result)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Script metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
for(int i=0;i<result.GetCount();i++)
|
||
|
{
|
||
|
memoryDistributionResult * pResult = rage_new memoryDistributionResult;
|
||
|
|
||
|
pResult->idx = i;
|
||
|
|
||
|
pResult->physicalFreeBySize.average = result[i].physicalFreeBySize.Mean();
|
||
|
pResult->physicalFreeBySize.min = result[i].physicalFreeBySize.Min();
|
||
|
pResult->physicalFreeBySize.max = result[i].physicalFreeBySize.Max();
|
||
|
pResult->physicalFreeBySize.std = result[i].physicalFreeBySize.StandardDeviation();
|
||
|
|
||
|
pResult->physicalUsedBySize.average = result[i].physicalUsedBySize.Mean();
|
||
|
pResult->physicalUsedBySize.min = result[i].physicalUsedBySize.Min();
|
||
|
pResult->physicalUsedBySize.max = result[i].physicalUsedBySize.Max();
|
||
|
pResult->physicalUsedBySize.std = result[i].physicalUsedBySize.StandardDeviation();
|
||
|
|
||
|
pResult->virtualFreeBySize.average = result[i].virtualFreeBySize.Mean();
|
||
|
pResult->virtualFreeBySize.min = result[i].virtualFreeBySize.Min();
|
||
|
pResult->virtualFreeBySize.max = result[i].virtualFreeBySize.Max();
|
||
|
pResult->virtualFreeBySize.std = result[i].virtualFreeBySize.StandardDeviation();
|
||
|
|
||
|
pResult->virtualUsedBySize.average = result[i].virtualUsedBySize.Mean();
|
||
|
pResult->virtualUsedBySize.min = result[i].virtualUsedBySize.Min();
|
||
|
pResult->virtualUsedBySize.max = result[i].virtualUsedBySize.Max();
|
||
|
pResult->virtualUsedBySize.std = result[i].virtualUsedBySize.StandardDeviation();
|
||
|
|
||
|
resultList->results.Top()->memDistributionResults.Grow() = pResult;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class pedAndVehicleStatUsage
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
SampledValue<u32> numPeds;
|
||
|
SampledValue<u32> numActivePeds;
|
||
|
SampledValue<u32> numInactivePeds;
|
||
|
SampledValue<u32> numEventScanHiPeds;
|
||
|
SampledValue<u32> numEventScanLoPeds;
|
||
|
SampledValue<u32> numMotionTaskHiPeds;
|
||
|
SampledValue<u32> numMotionTaskLoPeds;
|
||
|
SampledValue<u32> numPhysicsHiPeds;
|
||
|
SampledValue<u32> numPhysicsLoPeds;
|
||
|
SampledValue<u32> numEntityScanHiPeds;
|
||
|
SampledValue<u32> numEntityScanLoPeds;
|
||
|
|
||
|
SampledValue<u32> numVehicles;
|
||
|
SampledValue<u32> numActiveVehicles;
|
||
|
SampledValue<u32> numInactiveVehicles;
|
||
|
SampledValue<u32> numRealVehicles;
|
||
|
SampledValue<u32> numDummyVehicles;
|
||
|
SampledValue<u32> numSuperDummyVehicles;
|
||
|
};
|
||
|
|
||
|
|
||
|
void InitPedAndVehicleStatResult(pedAndVehicleStatUsage &result)
|
||
|
{
|
||
|
result.numPeds.Reset();
|
||
|
result.numActivePeds.Reset();
|
||
|
result.numInactivePeds.Reset();
|
||
|
result.numEventScanHiPeds.Reset();
|
||
|
result.numEventScanLoPeds.Reset();
|
||
|
result.numMotionTaskHiPeds.Reset();
|
||
|
result.numMotionTaskLoPeds.Reset();
|
||
|
result.numPhysicsHiPeds.Reset();
|
||
|
result.numPhysicsLoPeds.Reset();
|
||
|
result.numEntityScanHiPeds.Reset();
|
||
|
result.numEntityScanLoPeds.Reset();
|
||
|
|
||
|
result.numVehicles.Reset();
|
||
|
result.numActiveVehicles.Reset();
|
||
|
result.numInactiveVehicles.Reset();
|
||
|
result.numRealVehicles.Reset();
|
||
|
result.numDummyVehicles.Reset();
|
||
|
result.numSuperDummyVehicles.Reset();
|
||
|
}
|
||
|
|
||
|
void UpdatePedAndVehicleStatResult( pedAndVehicleStatUsage &result )
|
||
|
{
|
||
|
// Peds
|
||
|
int iNumPeds = 0;
|
||
|
int iNumEventScanHi = 0;
|
||
|
int iNumEventScanLo = 0;
|
||
|
int iNumMotionTaskHi = 0;
|
||
|
int iNumMotionTaskLo = 0;
|
||
|
int iNumPhysicsHi = 0;
|
||
|
int iNumPhysicsLo = 0;
|
||
|
int iNumEntityScanHi = 0;
|
||
|
int iNumEntityScanLo = 0;
|
||
|
int iNumActive = 0;
|
||
|
int iNumInactive = 0;
|
||
|
#if DEBUG_DRAW
|
||
|
int iNumTimeslicedHiPeds = 0;
|
||
|
int iNumTimeslicedLoPeds = 0;
|
||
|
CPedPopulation::GetPedLODCounts(iNumPeds, iNumEventScanHi, iNumEventScanLo, iNumMotionTaskHi, iNumMotionTaskLo, iNumPhysicsHi, iNumPhysicsLo, iNumEntityScanHi, iNumEntityScanLo, iNumActive, iNumInactive, iNumTimeslicedHiPeds, iNumTimeslicedLoPeds );
|
||
|
#endif //DEBUG_DRAW
|
||
|
|
||
|
result.numPeds.AddSample(iNumPeds);
|
||
|
result.numActivePeds.AddSample(iNumActive);
|
||
|
result.numInactivePeds.AddSample(iNumInactive);
|
||
|
result.numEventScanHiPeds.AddSample(iNumEventScanHi);
|
||
|
result.numEventScanLoPeds.AddSample(iNumEventScanLo);
|
||
|
result.numMotionTaskHiPeds.AddSample(iNumMotionTaskHi);
|
||
|
result.numMotionTaskLoPeds.AddSample(iNumMotionTaskLo);
|
||
|
result.numPhysicsHiPeds.AddSample(iNumPhysicsHi);
|
||
|
result.numPhysicsLoPeds.AddSample(iNumPhysicsLo);
|
||
|
result.numEntityScanHiPeds.AddSample(iNumEntityScanHi);
|
||
|
result.numEntityScanLoPeds.AddSample(iNumEntityScanLo);
|
||
|
|
||
|
// Vehicles
|
||
|
int iTotalNumVehicles = 0;
|
||
|
int iNumRealVehicles = 0;
|
||
|
int iNumDummyVehicles = 0;
|
||
|
int iNumSuperDummyVehicles = 0;
|
||
|
int iNumActiveVehicles = 0;
|
||
|
int iNumInactiveVehicles = 0;
|
||
|
#if DEBUG_DRAW
|
||
|
int iNumTimeslicedVehicles = 0;
|
||
|
CVehiclePopulation::GetVehicleLODCounts(iTotalNumVehicles, iNumRealVehicles, iNumDummyVehicles, iNumSuperDummyVehicles, iNumActiveVehicles, iNumInactiveVehicles, iNumTimeslicedVehicles );
|
||
|
#endif //DEBUG_DRAW
|
||
|
|
||
|
result.numVehicles.AddSample(iTotalNumVehicles);
|
||
|
result.numActiveVehicles.AddSample(iNumActiveVehicles);
|
||
|
result.numInactiveVehicles.AddSample(iNumInactiveVehicles);
|
||
|
result.numRealVehicles.AddSample(iNumRealVehicles);
|
||
|
result.numDummyVehicles.AddSample(iNumDummyVehicles);
|
||
|
result.numSuperDummyVehicles.AddSample(iNumSuperDummyVehicles);
|
||
|
}
|
||
|
|
||
|
|
||
|
void StorePedAndVehicleStatResult(debugLocationMetricsList * resultList, const pedAndVehicleStatUsage &result )
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "PedAndVehicleStat doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
pedAndVehicleStatResults *pResult = rage_new pedAndVehicleStatResults;
|
||
|
|
||
|
// Peds
|
||
|
pResult->numPeds.min = result.numPeds.Min();
|
||
|
pResult->numPeds.max = result.numPeds.Max();
|
||
|
pResult->numPeds.average = result.numPeds.Mean();
|
||
|
|
||
|
pResult->numActivePeds.min = result.numActivePeds.Min();
|
||
|
pResult->numActivePeds.max = result.numActivePeds.Max();
|
||
|
pResult->numActivePeds.average = result.numActivePeds.Mean();
|
||
|
|
||
|
pResult->numInactivePeds.min = result.numInactivePeds.Min();
|
||
|
pResult->numInactivePeds.max = result.numInactivePeds.Max();
|
||
|
pResult->numInactivePeds.average = result.numInactivePeds.Mean();
|
||
|
|
||
|
pResult->numEventScanHiPeds.min = result.numEventScanHiPeds.Min();
|
||
|
pResult->numEventScanHiPeds.max = result.numEventScanHiPeds.Max();
|
||
|
pResult->numEventScanHiPeds.average = result.numEventScanHiPeds.Mean();
|
||
|
|
||
|
pResult->numEventScanLoPeds.min = result.numEventScanLoPeds.Min();
|
||
|
pResult->numEventScanLoPeds.max = result.numEventScanLoPeds.Max();
|
||
|
pResult->numEventScanLoPeds.average = result.numEventScanLoPeds.Mean();
|
||
|
|
||
|
pResult->numMotionTaskHiPeds.min = result.numMotionTaskHiPeds.Min();
|
||
|
pResult->numMotionTaskHiPeds.max = result.numMotionTaskHiPeds.Max();
|
||
|
pResult->numMotionTaskHiPeds.average = result.numMotionTaskHiPeds.Mean();
|
||
|
|
||
|
pResult->numMotionTaskLoPeds.min = result.numMotionTaskLoPeds.Min();
|
||
|
pResult->numMotionTaskLoPeds.max = result.numMotionTaskLoPeds.Max();
|
||
|
pResult->numMotionTaskLoPeds.average = result.numMotionTaskLoPeds.Mean();
|
||
|
|
||
|
pResult->numPhysicsHiPeds.min = result.numPhysicsHiPeds.Min();
|
||
|
pResult->numPhysicsHiPeds.max = result.numPhysicsHiPeds.Max();
|
||
|
pResult->numPhysicsHiPeds.average = result.numPhysicsHiPeds.Mean();
|
||
|
|
||
|
pResult->numPhysicsLoPeds.min = result.numPhysicsLoPeds.Min();
|
||
|
pResult->numPhysicsLoPeds.max = result.numPhysicsLoPeds.Max();
|
||
|
pResult->numPhysicsLoPeds.average = result.numPhysicsLoPeds.Mean();
|
||
|
|
||
|
pResult->numEntityScanHiPeds.min = result.numEntityScanHiPeds.Min();
|
||
|
pResult->numEntityScanHiPeds.max = result.numEntityScanHiPeds.Max();
|
||
|
pResult->numEntityScanHiPeds.average = result.numEntityScanHiPeds.Mean();
|
||
|
|
||
|
pResult->numEntityScanLoPeds.min = result.numEntityScanLoPeds.Min();
|
||
|
pResult->numEntityScanLoPeds.max = result.numEntityScanLoPeds.Max();
|
||
|
pResult->numEntityScanLoPeds.average = result.numEntityScanLoPeds.Mean();
|
||
|
|
||
|
|
||
|
// Vehicles
|
||
|
pResult->numVehicles.min = result.numVehicles.Min();
|
||
|
pResult->numVehicles.max = result.numVehicles.Max();
|
||
|
pResult->numVehicles.average = result.numVehicles.Mean();
|
||
|
|
||
|
pResult->numActiveVehicles.min = result.numActiveVehicles.Min();
|
||
|
pResult->numActiveVehicles.max = result.numActiveVehicles.Max();
|
||
|
pResult->numActiveVehicles.average = result.numActiveVehicles.Mean();
|
||
|
|
||
|
pResult->numInactiveVehicles.min = result.numInactiveVehicles.Min();
|
||
|
pResult->numInactiveVehicles.max = result.numInactiveVehicles.Max();
|
||
|
pResult->numInactiveVehicles.average = result.numInactiveVehicles.Mean();
|
||
|
|
||
|
pResult->numRealVehicles.min = result.numRealVehicles.Min();
|
||
|
pResult->numRealVehicles.max = result.numRealVehicles.Max();
|
||
|
pResult->numRealVehicles.average = result.numRealVehicles.Mean();
|
||
|
|
||
|
pResult->numDummyVehicles.min = result.numDummyVehicles.Min();
|
||
|
pResult->numDummyVehicles.max = result.numDummyVehicles.Max();
|
||
|
pResult->numDummyVehicles.average = result.numDummyVehicles.Mean();
|
||
|
|
||
|
pResult->numSuperDummyVehicles.min = result.numSuperDummyVehicles.Min();
|
||
|
pResult->numSuperDummyVehicles.max = result.numSuperDummyVehicles.Max();
|
||
|
pResult->numSuperDummyVehicles.average = result.numSuperDummyVehicles.Mean();
|
||
|
|
||
|
resultList->results.Top()->pedAndVehicleResults = pResult;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
const char* TimingSetNameFromIndex(int timingSet)
|
||
|
{
|
||
|
#if RAGE_TIMEBARS
|
||
|
return g_pfTB.GetSetName(timingSet);
|
||
|
#else
|
||
|
UNUSED_VAR(timingSet);
|
||
|
return "";
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitFramesPerSecondResult(SampledValue<float> * fpsResult)
|
||
|
{
|
||
|
Assert(fpsResult);
|
||
|
fpsResult->Reset();
|
||
|
}
|
||
|
|
||
|
void UpdateFramesPerSecondResult(SampledValue<float> * fpsResult)
|
||
|
{
|
||
|
Assert(fpsResult);
|
||
|
float fps = 1.0f / rage::Max(0.001f, fwTimer::GetSystemTimeStep());
|
||
|
fpsResult->AddSample(fps);
|
||
|
}
|
||
|
|
||
|
void StoreFramesPerSecondResult(debugLocationMetricsList * resultList, const SampledValue<float> & fpsResult)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "FPS metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
framesPerSecondResult * result = rage_new framesPerSecondResult;
|
||
|
result->average = fpsResult.Mean();
|
||
|
result->min = fpsResult.Min();
|
||
|
result->max = fpsResult.Max();
|
||
|
result->std = fpsResult.StandardDeviation();
|
||
|
resultList->results.Top()->fpsResult = result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void InitMSPerFrameResult(SampledValue<float> * msPFResult)
|
||
|
{
|
||
|
Assert(msPFResult);
|
||
|
msPFResult->Reset();
|
||
|
}
|
||
|
|
||
|
void UpdateMSPerFrameResult(SampledValue<float> * msPFResult)
|
||
|
{
|
||
|
Assert(msPFResult);
|
||
|
float msPF = static_cast<float>(fwTimer::GetSystemTimeStepInMilliseconds());
|
||
|
msPFResult->AddSample(msPF);
|
||
|
}
|
||
|
|
||
|
void StoreMSPerFrameResult(debugLocationMetricsList * resultList, const SampledValue<float> & msPFResult)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "MS Per Frame metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
msPerFrameResult * result = rage_new msPerFrameResult;
|
||
|
result->average = msPFResult.Mean();
|
||
|
result->min = msPFResult.Min();
|
||
|
result->max = msPFResult.Max();
|
||
|
result->std = msPFResult.StandardDeviation();
|
||
|
resultList->results.Top()->msPFResult = result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool IsValidCPUTiming(const CPUTiming & cpuTiming)
|
||
|
{
|
||
|
return cpuTiming.name != NULL && cpuTiming.timingSet != -1;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitCPUTimingResults(TimingArray &cpuTimings)
|
||
|
{
|
||
|
cpuTimings.Reset();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitThreadTimingResults(ThreadTimingArray &threadTimings)
|
||
|
{
|
||
|
int count = threadTimings.GetCount();
|
||
|
|
||
|
for(int i = 0; i<count; ++i)
|
||
|
{
|
||
|
ThreadTiming & timing = threadTimings[i];
|
||
|
timing.value.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateCPUTimingResults(TimingArray& RAGE_TIMEBARS_ONLY(cpuTimings))
|
||
|
{
|
||
|
#if RAGE_TIMEBARS
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
pfTimeBars *startupBar = &g_pfTB.GetStartupBar();
|
||
|
int timingCount = cpuTimings.GetCount();
|
||
|
|
||
|
// Let's reset them all first.
|
||
|
for (int x = 0; x<timingCount; x++)
|
||
|
{
|
||
|
cpuTimings[x].timeThisFrame = 0.0f;
|
||
|
cpuTimings[x].callCountThisFrame = 0;
|
||
|
}
|
||
|
|
||
|
for (int x=0; x<g_pfTB.GetTimebarCount(); x++)
|
||
|
{
|
||
|
const pfTimeBars &timebar = g_pfTB.GetTimeBar(x);
|
||
|
int nextElement = 0;
|
||
|
|
||
|
// Exclude the startup bar.
|
||
|
if (&timebar != startupBar)
|
||
|
{
|
||
|
// Get the one timebar frame that just finished processing.
|
||
|
const pfTimeBars::sTimebarFrame &frame = timebar.GetRenderTimebarFrame();
|
||
|
|
||
|
int elements = frame.m_number;
|
||
|
|
||
|
for (int y=0; y<elements; y++)
|
||
|
{
|
||
|
const pfTimeBars::sFuncTime &time = frame.m_pTimes[y];
|
||
|
|
||
|
// Ignore all detail bars.
|
||
|
if (time.detail)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// The structure should match. Let's find the matching timing info.
|
||
|
CPUTiming *timing = NULL;
|
||
|
|
||
|
if (cpuTimings.GetCount() > nextElement)
|
||
|
{
|
||
|
for (int z=nextElement; z<timingCount; z++)
|
||
|
{
|
||
|
if (cpuTimings[z].timingSet == x && cpuTimings[z].name == time.nameptr)
|
||
|
{
|
||
|
// Found it.
|
||
|
timing = &cpuTimings[z];
|
||
|
nextElement = z;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!timing)
|
||
|
{
|
||
|
// Maybe we skipped it earlier - let's try the ones before us too.
|
||
|
for (int z=nextElement-1; z>=0; z--)
|
||
|
{
|
||
|
if (cpuTimings[z].timingSet == x && cpuTimings[z].name == time.nameptr)
|
||
|
{
|
||
|
// Found it.
|
||
|
timing = &cpuTimings[z];
|
||
|
nextElement = z;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If it's not here, then we need to create a new one.
|
||
|
if (!timing)
|
||
|
{
|
||
|
timing = &(cpuTimings.Grow(128));
|
||
|
timing->name = time.nameptr;
|
||
|
timing->optional = false;
|
||
|
timing->timingSet = x;
|
||
|
timing->timeThisFrame = 0.0f;
|
||
|
timing->callCountThisFrame = 0;
|
||
|
timingCount++;
|
||
|
}
|
||
|
|
||
|
Assert(timing->timeThisFrame >= 0.0f);
|
||
|
timing->timeThisFrame += time.endTime - time.startTime;
|
||
|
Assert(timing->timeThisFrame >= 0.0f);
|
||
|
timing->callCountThisFrame++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now that we gathered the information this frame locally, let's actually add samples.
|
||
|
for (int x=0; x<timingCount; x++)
|
||
|
{
|
||
|
CPUTiming &timing = cpuTimings[x];
|
||
|
|
||
|
if (timing.callCountThisFrame)
|
||
|
{
|
||
|
timing.value.AddSample(timing.timeThisFrame);
|
||
|
Assert(timing.value.Min() >= 0.0f);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateThreadTimingResults(ThreadTimingArray& threadTimings)
|
||
|
{
|
||
|
#if RAGE_TIMEBARS
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (threadTimings.GetCount() == 0)
|
||
|
{
|
||
|
threadTimings.Resize(3 + MULTIPLE_RENDER_THREADS);
|
||
|
|
||
|
threadTimings[0].name = "Update Thread";
|
||
|
threadTimings[1].name = "Render Thread";
|
||
|
threadTimings[2].name = "Total GPU";
|
||
|
|
||
|
#if MULTIPLE_RENDER_THREADS
|
||
|
static char renderThreadNames[MULTIPLE_RENDER_THREADS][32];
|
||
|
for(int i=0; i<MULTIPLE_RENDER_THREADS; ++i)
|
||
|
{
|
||
|
formatf(renderThreadNames[i], "Subrender Thread %d", i);
|
||
|
threadTimings[i+3].name = renderThreadNames[i];
|
||
|
}
|
||
|
#endif // MULTIPLE_RENDER_THREADS
|
||
|
}
|
||
|
|
||
|
threadTimings[0].timeThisFrame = g_pfTB.GetTimeBar(1).GetRenderTimebarFrame().ComputeFrameTime();
|
||
|
threadTimings[1].timeThisFrame = g_pfTB.GetTimeBar(2).GetRenderTimebarFrame().ComputeFrameTime();
|
||
|
threadTimings[2].timeThisFrame = g_pfTB.GetTimeBar(3).GetRenderTimebarFrame().ComputeFrameTime();
|
||
|
for(int i=0; i<MULTIPLE_RENDER_THREADS; ++i)
|
||
|
{
|
||
|
threadTimings[i+3].timeThisFrame = g_pfTB.GetTimeBar(i+4).GetRenderTimebarFrame().ComputeFrameTime();
|
||
|
}
|
||
|
|
||
|
// Now that we gathered the information this frame locally, let's actually add samples.
|
||
|
for (int x=0; x<threadTimings.GetCount(); x++)
|
||
|
{
|
||
|
ThreadTiming &timing = threadTimings[x];
|
||
|
timing.value.AddSample(timing.timeThisFrame);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (threadTimings.GetCount() == 0)
|
||
|
{
|
||
|
threadTimings.Resize(3);
|
||
|
|
||
|
threadTimings[0].name = "Update Thread";
|
||
|
threadTimings[1].name = "Render Thread";
|
||
|
threadTimings[2].name = "Total GPU";
|
||
|
}
|
||
|
|
||
|
threadTimings[0].timeThisFrame = grcSetupInstance->GetUpdateTime();
|
||
|
threadTimings[1].timeThisFrame = grcSetupInstance->GetDrawTime();
|
||
|
threadTimings[2].timeThisFrame = grcSetupInstance->GetGpuTime();
|
||
|
|
||
|
// Now that we gathered the information this frame locally, let's actually add samples.
|
||
|
for (int x=0; x<threadTimings.GetCount(); x++)
|
||
|
{
|
||
|
ThreadTiming &timing = threadTimings[x];
|
||
|
timing.value.AddSample(timing.timeThisFrame);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreCPUTimingResults(debugLocationMetricsList * resultList, const TimingArray &cpuTimings)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "CPU metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
int count = cpuTimings.GetCount();
|
||
|
for(int i = 0; i<count; ++i)
|
||
|
{
|
||
|
const CPUTiming & timing = cpuTimings[i];
|
||
|
cpuTimingResult *result = rage_new cpuTimingResult;
|
||
|
result->idx = i;
|
||
|
result->name = timing.name;
|
||
|
result->set = TimingSetNameFromIndex(timing.timingSet);
|
||
|
result->average = timing.value.Mean();
|
||
|
result->min = timing.value.Min();
|
||
|
result->max = timing.value.Max();
|
||
|
result->std = timing.value.StandardDeviation();
|
||
|
resultList->results.Top()->cpuResults.Grow() = result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreThreadTimingResults(debugLocationMetricsList * resultList, const ThreadTimingArray &threadTimings)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Thread metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
int count = threadTimings.GetCount();
|
||
|
for(int i = 0; i<count; ++i)
|
||
|
{
|
||
|
const ThreadTiming & timing = threadTimings[i];
|
||
|
threadTimingResult *result = rage_new threadTimingResult();
|
||
|
result->idx = i;
|
||
|
result->name = timing.name;
|
||
|
result->average = timing.value.Mean();
|
||
|
result->min = timing.value.Min();
|
||
|
result->max = timing.value.Max();
|
||
|
result->std = timing.value.StandardDeviation();
|
||
|
resultList->results.Top()->threadResults.Grow() = result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool IsValidMemoryBucketUsage(const MemoryBucketUsage & memoryBucketUsage)
|
||
|
{
|
||
|
return memoryBucketUsage.bucket != MEMBUCKET_INVALID;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreMemoryUsageToResult(const SampledValue<u32> & usage, memoryUsageResult & result)
|
||
|
{
|
||
|
result.average = usage.Mean();
|
||
|
result.min = usage.Min();
|
||
|
result.max = usage.Max();
|
||
|
result.std = usage.StandardDeviation();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitMemoryBucketUsageResults(MemoryBucketUsage * memoryBucketUsages)
|
||
|
{
|
||
|
for(int i = 0; IsValidMemoryBucketUsage(memoryBucketUsages[i]); ++i)
|
||
|
{
|
||
|
MemoryBucketUsage & memoryBucketUsage = memoryBucketUsages[i];
|
||
|
memoryBucketUsage.gameVirtual.Reset();
|
||
|
memoryBucketUsage.gamePhysical.Reset();
|
||
|
memoryBucketUsage.resourceVirtual.Reset();
|
||
|
memoryBucketUsage.resourcePhysical.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateMemoryBucketUsageResults(MemoryBucketUsage * memoryBucketUsages)
|
||
|
{
|
||
|
for(int i = 0; IsValidMemoryBucketUsage(memoryBucketUsages[i]); ++i)
|
||
|
{
|
||
|
MemoryBucketUsage & memoryBucketUsage = memoryBucketUsages[i];
|
||
|
sysMemAllocator & master = sysMemAllocator::GetMaster();
|
||
|
int bucket = memoryBucketUsage.bucket;
|
||
|
|
||
|
u32 gameVirtualKB;
|
||
|
u32 gamePhysicalKB;
|
||
|
u32 resourceVirtualKB;
|
||
|
u32 resourcePhysicalKB;
|
||
|
if(bucket != MEMBUCKET_SLOSH)
|
||
|
{
|
||
|
gameVirtualKB = (u32)master.GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryUsed(bucket)/1024;
|
||
|
gamePhysicalKB = (u32)master.GetAllocator(MEMTYPE_GAME_PHYSICAL)->GetMemoryUsed(bucket)/1024;
|
||
|
resourceVirtualKB = (u32)master.GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryUsed(bucket)/1024;
|
||
|
resourcePhysicalKB = (u32)master.GetAllocator(MEMTYPE_RESOURCE_PHYSICAL)->GetMemoryUsed(bucket)/1024;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gameVirtualKB = 0;
|
||
|
gamePhysicalKB = 0;
|
||
|
resourceVirtualKB = (u32)strStreamingEngine::GetAllocator().GetVirtualSlosh();
|
||
|
resourcePhysicalKB = (u32)strStreamingEngine::GetAllocator().GetPhysicalSlosh();
|
||
|
}
|
||
|
memoryBucketUsage.gameVirtual.AddSample(gameVirtualKB);
|
||
|
memoryBucketUsage.gamePhysical.AddSample(gamePhysicalKB);
|
||
|
memoryBucketUsage.resourceVirtual.AddSample(resourceVirtualKB);
|
||
|
memoryBucketUsage.resourcePhysical.AddSample(resourcePhysicalKB);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreMemoryBucketUsageResults(debugLocationMetricsList * resultList, const MemoryBucketUsage * memoryBucketUsages)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Memory bucket metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
for(int i = 0; IsValidMemoryBucketUsage(memoryBucketUsages[i]); ++i)
|
||
|
{
|
||
|
const MemoryBucketUsage & memoryBucketUsage = memoryBucketUsages[i];
|
||
|
memoryBucketUsageResult *result = rage_new memoryBucketUsageResult;
|
||
|
result->idx = i;
|
||
|
int bucket = memoryBucketUsage.bucket;
|
||
|
|
||
|
// yuck; I had something like #define MEMBUCKET_SLOSH (MEMBUCKET_DEBUG + 1) but ng doesnt like it
|
||
|
if(bucket != MEMBUCKET_SLOSH)
|
||
|
{
|
||
|
result->name = sysMemGetBucketName((MemoryBucketIds)memoryBucketUsage.bucket);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result->name = "Slosh";
|
||
|
}
|
||
|
StoreMemoryUsageToResult(memoryBucketUsage.gameVirtual, result->gameVirtual);
|
||
|
StoreMemoryUsageToResult(memoryBucketUsage.gamePhysical, result->gamePhysical);
|
||
|
StoreMemoryUsageToResult(memoryBucketUsage.resourceVirtual, result->resourceVirtual);
|
||
|
StoreMemoryUsageToResult(memoryBucketUsage.resourcePhysical, result->resourcePhysical);
|
||
|
resultList->results.Top()->memoryResults.Grow() = result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GetMemoryHeapNumbers(memoryHeapResult* pResult, int heapIndex)
|
||
|
{
|
||
|
sysMemAllocator* pAllocator = sysMemAllocator::GetMaster().GetAllocator(heapIndex);
|
||
|
if(pAllocator && pResult)
|
||
|
{
|
||
|
pResult->used = pAllocator->GetMemoryUsed();
|
||
|
pResult->free = pAllocator->GetMemoryAvailable();
|
||
|
pResult->total = pAllocator->GetHeapSize();
|
||
|
pResult->peak = pAllocator->GetHighWaterMark(false);
|
||
|
pResult->fragmentation = pAllocator->GetFragmentation();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GetStreamingHeapNumbers(size_t& used, size_t& total)
|
||
|
{
|
||
|
// Streaming Virtual
|
||
|
#if ONE_STREAMING_HEAP
|
||
|
used = (size_t) strStreamingEngine::GetAllocator().GetPhysicalMemoryUsed();
|
||
|
total = (size_t) strStreamingEngine::GetAllocator().GetPhysicalMemoryAvailable();
|
||
|
#else
|
||
|
used = (size_t) strStreamingEngine::GetAllocator().GetVirtualMemoryUsed();
|
||
|
total = (size_t) strStreamingEngine::GetAllocator().GetVirtualMemoryAvailable();
|
||
|
#endif
|
||
|
WIN32PC_ONLY(used = strStreamingEngine::GetAllocator().GetMemoryUsed());
|
||
|
WIN32PC_ONLY(total = strStreamingEngine::GetAllocator().GetMemoryAvailable());
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreMemHeapResults(debugLocationMetricsList * resultList )
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Memory heap metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
for(int i = MEMHEAP_GAME_VIRTUAL; i <= MEMHEAP_SMALL_ALLOCATOR; ++i)
|
||
|
{
|
||
|
memoryHeapResult *result = rage_new memoryHeapResult;
|
||
|
result->idx = i;
|
||
|
result->used = 0;
|
||
|
result->free = 0;
|
||
|
result->total = 0;
|
||
|
result->peak = 0;
|
||
|
result->fragmentation = 0;
|
||
|
|
||
|
switch(i)
|
||
|
{
|
||
|
case MEMHEAP_GAME_VIRTUAL:
|
||
|
{
|
||
|
GetMemoryHeapNumbers(result, MEMTYPE_GAME_VIRTUAL);
|
||
|
result->name = "GameVirtual";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MEMHEAP_RESOURCE_VIRTUAL:
|
||
|
{
|
||
|
GetMemoryHeapNumbers(result, MEMTYPE_RESOURCE_VIRTUAL);
|
||
|
result->name = "ResourceVirtual";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MEMHEAP_DEBUG_VIRTUAL:
|
||
|
{
|
||
|
GetMemoryHeapNumbers(result, MEMTYPE_DEBUG_VIRTUAL);
|
||
|
result->name = "DebugVirtual";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MEMHEAP_STREAMING_VIRTUAL:
|
||
|
{
|
||
|
GetStreamingHeapNumbers(result->used, result->total);
|
||
|
result->name = "StreamingVirtual";
|
||
|
result->free = result->total - result->used;
|
||
|
}
|
||
|
break;
|
||
|
case MEMHEAP_EXTERNAL_VIRTUAL:
|
||
|
{
|
||
|
#if ONE_STREAMING_HEAP
|
||
|
result->used = (s32) strStreamingEngine::GetAllocator().GetExternalPhysicalMemoryUsed();
|
||
|
#else
|
||
|
result->used = (s32) strStreamingEngine::GetAllocator().GetExternalVirtualMemoryUsed();
|
||
|
#endif
|
||
|
result->name = "ExternalVirtual";
|
||
|
}
|
||
|
break;
|
||
|
case MEMHEAP_SLOSH_VIRTUAL:
|
||
|
{
|
||
|
sysMemAllocator* pAllocator = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL);
|
||
|
result->name = "SloshVirtual";
|
||
|
if(pAllocator)
|
||
|
{
|
||
|
size_t streamingUsed, streamingTotal;
|
||
|
GetStreamingHeapNumbers(streamingUsed, streamingTotal);
|
||
|
size_t streamingFree = streamingTotal - streamingUsed;
|
||
|
result->used = pAllocator->GetMemoryAvailable() - streamingFree;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case MEMHEAP_SMALL_ALLOCATOR:
|
||
|
{
|
||
|
sysMemAllocator* pAllocator = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL);
|
||
|
result->name = "SmallAllocator";
|
||
|
if(pAllocator)
|
||
|
{
|
||
|
sysMemSimpleAllocator* pSimpleAllocator = reinterpret_cast<sysMemSimpleAllocator*>(pAllocator);
|
||
|
result->used = pSimpleAllocator->GetSmallocatorTotalSize();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
resultList->results.Top()->memoryHeapResults.Grow() = result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool IsValidDrawListCount(const DrawListCount & drawListCount)
|
||
|
{
|
||
|
return drawListCount.id != -1;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitDrawListResults(DrawListCount * drawListCounts)
|
||
|
{
|
||
|
for(int i = 0; IsValidDrawListCount(drawListCounts[i]); ++i)
|
||
|
{
|
||
|
DrawListCount & count = drawListCounts[i];
|
||
|
count.value.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateDrawListResults(DrawListCount * drawListCounts)
|
||
|
{
|
||
|
for(int i = 0; IsValidDrawListCount(drawListCounts[i]); ++i)
|
||
|
{
|
||
|
DrawListCount & count = drawListCounts[i];
|
||
|
int drawListCount = gDrawListMgr->GetDrawListEntityCount(count.id);
|
||
|
|
||
|
count.value.AddSample(drawListCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StoreDrawListResults(debugLocationMetricsList * resultList, const DrawListCount * drawListCounts)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if (Verifyf(resultList->results.GetCount(), "Draw list metric list doesn't have any storage for results yet - did we not call StartSampling?"))
|
||
|
{
|
||
|
for(int i = 0; IsValidDrawListCount(drawListCounts[i]); ++i)
|
||
|
{
|
||
|
const DrawListCount & count = drawListCounts[i];
|
||
|
drawListResult *result = rage_new drawListResult;
|
||
|
result->idx = i;
|
||
|
result->name = gDrawListMgr->GetDrawListName(count.id);
|
||
|
result->average = count.value.Mean();
|
||
|
result->min = count.value.Min();
|
||
|
result->max = count.value.Max();
|
||
|
result->std = count.value.StandardDeviation();
|
||
|
resultList->results.Top()->drawListResults.Grow() = result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void ClearResults(debugLocationMetricsList * resultList)
|
||
|
{
|
||
|
Assert(resultList);
|
||
|
|
||
|
for(int i = 0; i < resultList->results.size(); ++i)
|
||
|
{
|
||
|
metricsList * metrics = resultList->results[i];
|
||
|
|
||
|
if(metrics->fpsResult)
|
||
|
{
|
||
|
delete metrics->fpsResult;
|
||
|
metrics->fpsResult = NULL;
|
||
|
}
|
||
|
|
||
|
if(metrics->msPFResult)
|
||
|
{
|
||
|
delete metrics->msPFResult;
|
||
|
metrics->msPFResult = NULL;
|
||
|
}
|
||
|
|
||
|
for(int gpuResultIndex = 0; gpuResultIndex < metrics->gpuResults.size(); ++gpuResultIndex)
|
||
|
{
|
||
|
delete metrics->gpuResults[gpuResultIndex];
|
||
|
}
|
||
|
for(int cpuResultIndex = 0; cpuResultIndex < metrics->cpuResults.size(); ++cpuResultIndex)
|
||
|
{
|
||
|
delete metrics->cpuResults[cpuResultIndex];
|
||
|
}
|
||
|
for(int memoryResultIndex = 0; memoryResultIndex < metrics->memoryResults.size(); ++memoryResultIndex)
|
||
|
{
|
||
|
delete metrics->memoryResults[memoryResultIndex];
|
||
|
}
|
||
|
for(int streamingMemoryResultIndex = 0; streamingMemoryResultIndex < metrics->streamingMemoryResults.size(); ++streamingMemoryResultIndex)
|
||
|
{
|
||
|
delete metrics->streamingMemoryResults[streamingMemoryResultIndex];
|
||
|
}
|
||
|
for(int drawListResultIndex = 0; drawListResultIndex < metrics->drawListResults.size(); ++drawListResultIndex)
|
||
|
{
|
||
|
delete metrics->drawListResults[drawListResultIndex];
|
||
|
}
|
||
|
if(metrics->scriptMemResult)
|
||
|
{
|
||
|
delete metrics->scriptMemResult;
|
||
|
metrics->scriptMemResult = NULL;
|
||
|
}
|
||
|
for(int memDistributionResultIndex = 0; memDistributionResultIndex < metrics->memDistributionResults.size(); ++memDistributionResultIndex)
|
||
|
{
|
||
|
delete metrics->memDistributionResults[memDistributionResultIndex];
|
||
|
}
|
||
|
if(metrics->pedAndVehicleResults)
|
||
|
{
|
||
|
delete metrics->pedAndVehicleResults;
|
||
|
metrics->pedAndVehicleResults = NULL;
|
||
|
}
|
||
|
for(int streamStats = 0; streamStats < metrics->streamingStatsResults.size(); ++streamStats)
|
||
|
{
|
||
|
delete metrics->streamingStatsResults[streamStats];
|
||
|
}
|
||
|
delete metrics;
|
||
|
}
|
||
|
resultList->results.clear();
|
||
|
}
|
||
|
|
||
|
CaptureInstance::CaptureInstance()
|
||
|
{
|
||
|
m_ResultList.platform = PLATFORM_STRING;
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
debugLocationMetricsList * CaptureInstance::GetResults()
|
||
|
{
|
||
|
return &m_ResultList;
|
||
|
}
|
||
|
|
||
|
int CaptureInstance::GetSamplingId()
|
||
|
{
|
||
|
return m_SamplingId;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CaptureInstance::Reset()
|
||
|
{
|
||
|
ClearResults(&m_ResultList);
|
||
|
m_Running = false;
|
||
|
m_SamplingId = NOT_SAMPLING;
|
||
|
m_SamplingName = "";
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool CaptureInstance::Running()
|
||
|
{
|
||
|
return m_Running;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool CaptureInstance::Sampling()
|
||
|
{
|
||
|
return m_SamplingId != NOT_SAMPLING;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CaptureInstance::StartCapture()
|
||
|
{
|
||
|
Assert(!Running());
|
||
|
m_Running = true;
|
||
|
|
||
|
// Needs to be done here since the version number isn't available at time of captureinstance creation
|
||
|
m_ResultList.buildversion = CDebug::GetVersionNumber();
|
||
|
|
||
|
m_ResultList.exeSize = MEMMANAGER.GetExeSize();
|
||
|
|
||
|
const char *cl = NULL;
|
||
|
if(PARAM_autocaptureCL.Get(cl))
|
||
|
{
|
||
|
m_ResultList.changeList = cl;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_ResultList.changeList = "specify with -autocaptureCL";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CaptureInstance::StartSampling(int samplingId, const char * samplingName)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
Assert(Running());
|
||
|
Assert(samplingId != NOT_SAMPLING);
|
||
|
|
||
|
m_SamplingId = samplingId;
|
||
|
m_SamplingName = samplingName;
|
||
|
|
||
|
metricsList *list = rage_new metricsList;
|
||
|
list->idx = samplingId;
|
||
|
list->name = samplingName;
|
||
|
list->fpsResult = NULL;
|
||
|
list->msPFResult = NULL;
|
||
|
list->scriptMemResult = NULL;
|
||
|
list->pedAndVehicleResults = NULL;
|
||
|
m_ResultList.results.Grow() = list;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CaptureInstance::StopSampling()
|
||
|
{
|
||
|
Assert(Running());
|
||
|
m_SamplingId = NOT_SAMPLING;
|
||
|
m_SamplingName = "";
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void CaptureInstance::SendToTelemetry()
|
||
|
{
|
||
|
debugLocationMetricsList *pList = GetResults();
|
||
|
|
||
|
// Send each capture instance to NetworkTelemetry
|
||
|
for(int i=0;i<pList->results.size();i++)
|
||
|
{
|
||
|
metricsList *pMetric = pList->results[i];
|
||
|
#if !__FINAL
|
||
|
CNetworkDebugTelemetry::AddAutoGPUTelemetry(pMetric);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static void GetBasePath(char *filename, bool useDev = false )
|
||
|
{
|
||
|
char baseName[RAGE_MAX_PATH];
|
||
|
|
||
|
// The thing with the __DATE__:
|
||
|
// MMM DD YYYY
|
||
|
// 01234567890
|
||
|
// Apr 1 2011 -> 11Apr01
|
||
|
formatf(baseName, "autoCapture.%s.%c%c%c%c%c%c%c",
|
||
|
__XENON == 1 ? "360" : (__PS3 == 1 ? "ps3" : "xxx"),
|
||
|
__DATE__[9],__DATE__[10],
|
||
|
__DATE__[0],__DATE__[1],__DATE__[2],
|
||
|
__DATE__[4] == ' ' ? '0' : __DATE__[4], __DATE__[5]
|
||
|
);
|
||
|
|
||
|
if ( useDev )
|
||
|
{
|
||
|
snprintf(filename, RAGE_MAX_PATH, "devkit:\\%s", baseName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(filename, "%s%s", CFileMgr::GetRootDirectory(),baseName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
#if DEBUG_METRICS_CAPTURES
|
||
|
static const float g_AutoCaptureWarpTime = 5.0f * 1000.0f;
|
||
|
static const float g_AutoCaptureCallbackTime = 2.5f * 1000.0f;
|
||
|
static const float g_AutoCaptureTimeBeforeStart = 5.0f * 1000.0f;
|
||
|
#else
|
||
|
static const float g_AutoCaptureWarpTime = 25.0f * 1000.0f;
|
||
|
static const float g_AutoCaptureCallbackTime = 15.0f * 1000.0f;
|
||
|
static const float g_AutoCaptureTimeBeforeStart = 10.0f * 1000.0f;
|
||
|
#endif
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
static TimingArray s_Timebars;
|
||
|
static ThreadTimingArray s_Threads;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
debugLocationList *g_LocationList;
|
||
|
static debugLocationList::visitCallback g_AutoCaptureCallback;
|
||
|
static bool g_AutoCaptureRun = false;
|
||
|
static float g_AutoCaptureStartTime = 0.0f;
|
||
|
static float g_AutoCaptureLastWarningTime = 0.0f;
|
||
|
static bool g_PlayerCanBeDamagedBaseState = false;
|
||
|
static CaptureInstance g_AutoCapture;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static CaptureInstance g_OnDemandCapture;
|
||
|
static CMetricsCaptureWindow g_OnDemandWindow(*g_OnDemandCapture.GetResults());
|
||
|
static bool g_OnDemandShowWindow = false;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
CaptureInstance g_ZoneCapture;
|
||
|
static CMetricsCaptureWindow g_ZoneWindow(*g_ZoneCapture.GetResults());
|
||
|
static bool g_ZoneShowWindow = false;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static CaptureInstance s_SmokeTestCapture;
|
||
|
static CMetricsCaptureWindow g_SmokeTestWindow(*s_SmokeTestCapture.GetResults());
|
||
|
static bool g_SmokeTestShowWindow = false;
|
||
|
|
||
|
static SampledValue<float> s_SmokeTestFramesPerSecond;
|
||
|
static SampledValue<float> s_SmokeTestMSPerFrame;
|
||
|
|
||
|
static MemoryBucketUsage s_SmokeTestMemoryBucketUsages[] =
|
||
|
{
|
||
|
{MEMBUCKET_DEFAULT},
|
||
|
{MEMBUCKET_ANIMATION},
|
||
|
{MEMBUCKET_STREAMING},
|
||
|
{MEMBUCKET_WORLD},
|
||
|
{MEMBUCKET_GAMEPLAY},
|
||
|
{MEMBUCKET_FX},
|
||
|
{MEMBUCKET_RENDER},
|
||
|
{MEMBUCKET_PHYSICS},
|
||
|
{MEMBUCKET_AUDIO},
|
||
|
{MEMBUCKET_NETWORK},
|
||
|
{MEMBUCKET_SYSTEM},
|
||
|
{MEMBUCKET_SCALEFORM},
|
||
|
{MEMBUCKET_SCRIPT},
|
||
|
{MEMBUCKET_RESOURCE},
|
||
|
{MEMBUCKET_UI},
|
||
|
{MEMBUCKET_DEBUG},
|
||
|
{(MemoryBucketIds)MEMBUCKET_SLOSH}, //slosh goes here
|
||
|
{MEMBUCKET_INVALID}
|
||
|
};
|
||
|
|
||
|
static memoryHeapResult s_SmokeTestMemoryHeaps[] =
|
||
|
{
|
||
|
{MEMHEAP_GAME_VIRTUAL},
|
||
|
{MEMHEAP_RESOURCE_VIRTUAL},
|
||
|
{MEMHEAP_DEBUG_VIRTUAL},
|
||
|
{MEMHEAP_STREAMING_VIRTUAL},
|
||
|
{MEMHEAP_EXTERNAL_VIRTUAL},
|
||
|
{MEMHEAP_SLOSH_VIRTUAL},
|
||
|
{MEMHEAP_SMALL_ALLOCATOR},
|
||
|
{MEMHEAP_INVALID}
|
||
|
};
|
||
|
|
||
|
static DrawListCount s_SmokeTestDrawListCounts[DL_MAX_TYPES];
|
||
|
|
||
|
static ScriptMemoryUsage s_SmokeTestScriptMemUsage;
|
||
|
|
||
|
static MemoryDistributionArray s_SmokeTestMemoryDistributionUsage;
|
||
|
|
||
|
static pedAndVehicleStatUsage s_SmokeTestPedAndVehicleStatUsage;
|
||
|
|
||
|
static StreamingStatsArray g_SmokeTestStreamingStats;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static SampledValue<float> g_AutoFramesPerSecond;
|
||
|
static SampledValue<float> g_AutoMSPerFrame;
|
||
|
|
||
|
static TimingArray g_AutoCpuTimings;
|
||
|
static ThreadTimingArray g_AutoThreadTimings;
|
||
|
|
||
|
static MemoryBucketUsage g_AutoMemoryBucketUsages[] =
|
||
|
{
|
||
|
{MEMBUCKET_DEFAULT},
|
||
|
{MEMBUCKET_ANIMATION},
|
||
|
{MEMBUCKET_STREAMING},
|
||
|
{MEMBUCKET_WORLD},
|
||
|
{MEMBUCKET_GAMEPLAY},
|
||
|
{MEMBUCKET_FX},
|
||
|
{MEMBUCKET_RENDER},
|
||
|
{MEMBUCKET_PHYSICS},
|
||
|
{MEMBUCKET_AUDIO},
|
||
|
{MEMBUCKET_NETWORK},
|
||
|
{MEMBUCKET_SYSTEM},
|
||
|
{MEMBUCKET_SCALEFORM},
|
||
|
{MEMBUCKET_SCRIPT},
|
||
|
{MEMBUCKET_RESOURCE},
|
||
|
{MEMBUCKET_DEBUG},
|
||
|
{MEMBUCKET_INVALID}
|
||
|
};
|
||
|
|
||
|
static DrawListCount g_AutoDrawListCounts[DL_MAX_TYPES];
|
||
|
|
||
|
static ScriptMemoryUsage g_AutoScriptMemUsage;
|
||
|
|
||
|
static MemoryDistributionArray g_AutoMemoryDistributionUsage;
|
||
|
|
||
|
static pedAndVehicleStatUsage g_AutoPedAndVehicleStatUsage;
|
||
|
|
||
|
static StreamingStatsArray g_AutoStreamingStats;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static SampledValue<float> g_OnDemandFramesPerSecond;
|
||
|
static SampledValue<float> g_OnDemandMSPerFrame;
|
||
|
|
||
|
static TimingArray g_OnDemandCpuTimings;
|
||
|
static ThreadTimingArray g_OnDemandThreadTimings;
|
||
|
static MemoryBucketUsage g_OnDemandMemoryBucketUsages[] =
|
||
|
{
|
||
|
{MEMBUCKET_DEFAULT},
|
||
|
{MEMBUCKET_ANIMATION},
|
||
|
{MEMBUCKET_STREAMING},
|
||
|
{MEMBUCKET_WORLD},
|
||
|
{MEMBUCKET_GAMEPLAY},
|
||
|
{MEMBUCKET_FX},
|
||
|
{MEMBUCKET_RENDER},
|
||
|
{MEMBUCKET_PHYSICS},
|
||
|
{MEMBUCKET_AUDIO},
|
||
|
{MEMBUCKET_NETWORK},
|
||
|
{MEMBUCKET_SYSTEM},
|
||
|
{MEMBUCKET_SCALEFORM},
|
||
|
{MEMBUCKET_SCRIPT},
|
||
|
{MEMBUCKET_RESOURCE},
|
||
|
{MEMBUCKET_DEBUG},
|
||
|
{MEMBUCKET_INVALID}
|
||
|
};
|
||
|
|
||
|
static DrawListCount g_OnDemandDrawListCounts[DL_MAX_TYPES];
|
||
|
|
||
|
static ScriptMemoryUsage g_OnDemandScriptMemUsage;
|
||
|
|
||
|
static MemoryDistributionArray g_OnDemandMemoryDistributionUsage;
|
||
|
|
||
|
static pedAndVehicleStatUsage g_OnDemandPedAndVehicleStatUsage;
|
||
|
|
||
|
static StreamingStatsArray g_OnDemandStreamingStats;
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static SampledValue<float> g_ZoneFramesPerSecond;
|
||
|
static SampledValue<float> g_ZoneMSPerFrame;
|
||
|
|
||
|
|
||
|
|
||
|
static MemoryBucketUsage g_ZoneMemoryBucketUsages[] =
|
||
|
{
|
||
|
{MEMBUCKET_DEFAULT},
|
||
|
{MEMBUCKET_ANIMATION},
|
||
|
{MEMBUCKET_STREAMING},
|
||
|
{MEMBUCKET_WORLD},
|
||
|
{MEMBUCKET_GAMEPLAY},
|
||
|
{MEMBUCKET_FX},
|
||
|
{MEMBUCKET_RENDER},
|
||
|
{MEMBUCKET_PHYSICS},
|
||
|
{MEMBUCKET_AUDIO},
|
||
|
{MEMBUCKET_NETWORK},
|
||
|
{MEMBUCKET_SYSTEM},
|
||
|
{MEMBUCKET_SCALEFORM},
|
||
|
{MEMBUCKET_SCRIPT},
|
||
|
{MEMBUCKET_RESOURCE},
|
||
|
{MEMBUCKET_UI},
|
||
|
{MEMBUCKET_DEBUG},
|
||
|
{MEMBUCKET_INVALID}
|
||
|
};
|
||
|
|
||
|
static DrawListCount g_ZoneDrawListCounts[DL_MAX_TYPES];
|
||
|
|
||
|
static ScriptMemoryUsage g_ZoneScriptMemUsage;
|
||
|
|
||
|
static MemoryDistributionArray g_ZoneMemoryDistributionUsage;
|
||
|
|
||
|
static pedAndVehicleStatUsage g_ZonePedAndVehicleStatUsage;
|
||
|
|
||
|
static StreamingStatsArray g_ZoneStreamingStats;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitDrawListCounts()
|
||
|
{
|
||
|
// starts at the first valid renderphase (1)
|
||
|
for (int i = 1; i < DL_MAX_TYPES; i++)
|
||
|
{
|
||
|
g_AutoDrawListCounts[i - 1].id = i;
|
||
|
}
|
||
|
g_AutoDrawListCounts[DL_MAX_TYPES - 1].id = -1;
|
||
|
|
||
|
// starts at the first valid renderphase (1)
|
||
|
for (int i = 1; i < DL_MAX_TYPES; i++)
|
||
|
{
|
||
|
g_OnDemandDrawListCounts[i - 1].id = i;
|
||
|
}
|
||
|
g_OnDemandDrawListCounts[DL_MAX_TYPES - 1].id = -1;
|
||
|
|
||
|
g_ZoneDrawListCounts[0].id = -1;
|
||
|
|
||
|
// starts at the first valid renderphase (1)
|
||
|
for (int i = 1; i < DL_MAX_TYPES; i++)
|
||
|
{
|
||
|
s_SmokeTestDrawListCounts[i - 1].id = i;
|
||
|
}
|
||
|
s_SmokeTestDrawListCounts[DL_MAX_TYPES - 1].id = -1;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void SaveMemVisualizeFiles(const char *RAGE_TRACKING_ONLY(targetFile))
|
||
|
{
|
||
|
#if RAGE_TRACKING
|
||
|
if (diagTracker::GetCurrent())
|
||
|
{
|
||
|
char fullPath[RAGE_MAX_PATH];
|
||
|
ASSET.FullWritePath(fullPath, sizeof(fullPath), targetFile, "");
|
||
|
|
||
|
// We'll use the final name as a directory.
|
||
|
char pathName[RAGE_MAX_PATH];
|
||
|
ASSET.RemoveExtensionFromPath(pathName, sizeof(pathName), fullPath);
|
||
|
|
||
|
char finalPath[RAGE_MAX_PATH];
|
||
|
formatf(finalPath, "%s_MemVisualize/MV.mvz", pathName);
|
||
|
diagTracker::GetCurrent()->FullReport(finalPath);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void OverridePathName(char *targetBuffer, size_t targetBufferSize, const char *filename)
|
||
|
{
|
||
|
const char *pathAddition = NULL;
|
||
|
|
||
|
if (PARAM_autocapturepath.Get(pathAddition))
|
||
|
{
|
||
|
// Remove the existing path information.
|
||
|
const char *nameOnly = ASSET.FileName(filename);
|
||
|
char pathOnly[RAGE_MAX_PATH];
|
||
|
ASSET.RemoveNameFromPath(pathOnly, RAGE_MAX_PATH, filename);
|
||
|
|
||
|
const char *platform = PLATFORM_STRING;
|
||
|
|
||
|
formatf(targetBuffer, targetBufferSize, "%s/%s/%s/%s", pathOnly, pathAddition, platform, nameOnly);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
safecpy(targetBuffer, filename, targetBufferSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void SaveResults(const debugLocationMetricsList * resultList)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
Assert(resultList);
|
||
|
|
||
|
char baseFilename[RAGE_MAX_PATH];
|
||
|
GetBasePath(baseFilename);
|
||
|
|
||
|
char filename[RAGE_MAX_PATH];
|
||
|
OverridePathName(filename, sizeof(filename), baseFilename);
|
||
|
|
||
|
ASSET.CreateLeadingPath(filename);
|
||
|
SaveMemVisualizeFiles(filename);
|
||
|
|
||
|
fiStream* stream = ASSET.Create(filename, "xml");
|
||
|
if (stream)
|
||
|
{
|
||
|
// Use the XML writer instead of PARSER.SaveObject because none of these objects have onSave callbacks that would require us to use SaveObject
|
||
|
parXmlWriterVisitor visitor(stream);
|
||
|
visitor.Visit(const_cast<debugLocationMetricsList&>(*resultList));
|
||
|
stream->Close();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Errorf("Saving %s.xml failed", filename);
|
||
|
}
|
||
|
|
||
|
Displayf("Saved as %s.xml", filename);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void AutoCaptureToggle()
|
||
|
{
|
||
|
g_AutoCaptureRun = !g_AutoCaptureRun;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void OnDemandCaptureToggle()
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if(!g_OnDemandCapture.Running())
|
||
|
{
|
||
|
g_OnDemandCapture.Reset();
|
||
|
g_OnDemandCapture.StartCapture();
|
||
|
}
|
||
|
|
||
|
if(g_OnDemandCapture.Sampling())
|
||
|
{
|
||
|
g_OnDemandCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(g_OnDemandCapture.GetResults(), g_OnDemandFramesPerSecond);
|
||
|
StoreMSPerFrameResult(g_OnDemandCapture.GetResults(), g_OnDemandMSPerFrame);
|
||
|
StoreCPUTimingResults(g_OnDemandCapture.GetResults(), g_OnDemandCpuTimings);
|
||
|
StoreThreadTimingResults(g_OnDemandCapture.GetResults(), g_OnDemandThreadTimings);
|
||
|
StoreMemoryBucketUsageResults(g_OnDemandCapture.GetResults(), g_OnDemandMemoryBucketUsages);
|
||
|
StoreDrawListResults(g_OnDemandCapture.GetResults(), g_OnDemandDrawListCounts);
|
||
|
StoreScriptMemResult(g_OnDemandCapture.GetResults(), g_OnDemandScriptMemUsage );
|
||
|
StoreMemDistributionResult(g_OnDemandCapture.GetResults(), g_OnDemandMemoryDistributionUsage);
|
||
|
StorePedAndVehicleStatResult(g_OnDemandCapture.GetResults(), g_OnDemandPedAndVehicleStatUsage);
|
||
|
StoreStreamingStats(g_OnDemandCapture.GetResults(), g_OnDemandStreamingStats);
|
||
|
SaveResults(g_OnDemandCapture.GetResults());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InitFramesPerSecondResult(&g_OnDemandFramesPerSecond);
|
||
|
InitMSPerFrameResult(&g_OnDemandMSPerFrame);
|
||
|
InitCPUTimingResults(g_OnDemandCpuTimings);
|
||
|
InitThreadTimingResults(g_OnDemandThreadTimings);
|
||
|
InitMemoryBucketUsageResults(g_OnDemandMemoryBucketUsages);
|
||
|
InitDrawListResults(g_OnDemandDrawListCounts);
|
||
|
InitScriptMemResult(g_OnDemandScriptMemUsage);
|
||
|
InitMemDistributionResult(g_OnDemandMemoryDistributionUsage);
|
||
|
InitPedAndVehicleStatResult(g_OnDemandPedAndVehicleStatUsage);
|
||
|
InitStreamingStats(g_OnDemandStreamingStats);
|
||
|
|
||
|
g_OnDemandCapture.StartSampling(0, "On Demand Capture");
|
||
|
|
||
|
for(int i=0;i<gDrawListMgr->GetDrawListTypeCount();i++)
|
||
|
{
|
||
|
gpuTimingResult *result = rage_new gpuTimingResult;
|
||
|
result->idx = i;
|
||
|
result->name = gDrawListMgr->GetDrawListName(i);
|
||
|
result->time = gDrawListMgr->GetDrawListGPUTime(i);
|
||
|
g_OnDemandCapture.GetResults()->results.Top()->gpuResults.Grow() = result;
|
||
|
}
|
||
|
|
||
|
#if __BANK
|
||
|
CStreamGraph streamingMemTracker;
|
||
|
streamingMemTracker.IncludeVirtualMemory(true);
|
||
|
streamingMemTracker.IncludePhysicalMemory(true);
|
||
|
streamingMemTracker.IncludeReferencedObjects(true);
|
||
|
streamingMemTracker.IncludeDontDeleteObjects(true);
|
||
|
streamingMemTracker.IncludeCachedObjects(true);
|
||
|
streamingMemTracker.CollectResultsForAutoCapture(g_OnDemandCapture.GetResults()->results.Top()->streamingMemoryResults);
|
||
|
#endif //__BANK
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void InitPlayerState()
|
||
|
{
|
||
|
CPed *player = CGameWorld::FindLocalPlayer();
|
||
|
|
||
|
if(player)
|
||
|
{
|
||
|
g_PlayerCanBeDamagedBaseState = player->GetPlayerInfo()->GetPlayerDataCanBeDamaged() != 0;
|
||
|
player->GetPlayerInfo()->SetPlayerCanBeDamaged(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void RestorePlayerState()
|
||
|
{
|
||
|
CPed *player = CGameWorld::FindLocalPlayer();
|
||
|
|
||
|
if(player)
|
||
|
{
|
||
|
player->GetPlayerInfo()->SetPlayerCanBeDamaged(g_PlayerCanBeDamagedBaseState);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void PrintStatus(const char * status)
|
||
|
{
|
||
|
bool output = diagChannel::GetOutput();
|
||
|
diagChannel::SetOutput(true);
|
||
|
Displayf("%s", status);
|
||
|
diagChannel::SetOutput(output);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StartSingleFrameReport()
|
||
|
{
|
||
|
OnDemandCaptureToggle();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StartMultiFrameReport()
|
||
|
{
|
||
|
OnDemandCaptureToggle();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void ProcessParams()
|
||
|
{
|
||
|
// allow the capture to be started by a param the first time through
|
||
|
static bool paramStartCapture = PARAM_startAutoMetricsCapture.Get() || PARAM_startAutoGPUCapture.Get();
|
||
|
if(paramStartCapture)
|
||
|
{
|
||
|
paramStartCapture = false;
|
||
|
AutoCaptureToggle();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void ProcessKeyboardInput()
|
||
|
{
|
||
|
if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_F12, KEYBOARD_MODE_DEBUG, "metrics report immediate"))
|
||
|
{
|
||
|
StartSingleFrameReport();
|
||
|
}
|
||
|
if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_F12, KEYBOARD_MODE_DEBUG_SHIFT, "metrics report 10s capture"))
|
||
|
{
|
||
|
StartMultiFrameReport();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZonesClear()
|
||
|
{
|
||
|
if( Verifyf( g_ZoneCapture.Sampling() == false, "Called METRICS_ZONES_CLEAR while sampling is running! Call METRICS_ZONE_STOP first!!\n" ))
|
||
|
{
|
||
|
MutexHelper Helper;
|
||
|
|
||
|
g_ZoneCapture.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZonesDisplay(bool show)
|
||
|
{
|
||
|
g_ZoneShowWindow = show;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZonesDraw()
|
||
|
{
|
||
|
g_ZoneWindow.Draw();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZonesSave()
|
||
|
{
|
||
|
SaveResults(g_ZoneCapture.GetResults());
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZonesSaveToFilename(const char *pFilename)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
Assertf(pFilename != NULL, "Passed filename is NULL");
|
||
|
|
||
|
char filename[RAGE_MAX_PATH];
|
||
|
|
||
|
#if __WIN32PC
|
||
|
if (PARAM_fpsCaptureUseUserFolder.Get())
|
||
|
{
|
||
|
const char* extraPath = NULL;
|
||
|
if (PARAM_fpsCaptureExtraPath.Get(extraPath))
|
||
|
{
|
||
|
sprintf(filename, "%s%s%s", CFileMgr::GetUserDataRootDirectory(), extraPath, pFilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(filename, "%s%s", CFileMgr::GetUserDataRootDirectory(), pFilename);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
char rawFilename[RAGE_MAX_PATH];
|
||
|
#if RSG_DURANGO && !__FINAL
|
||
|
formatf(rawFilename, "debug:/%s", pFilename);
|
||
|
#else
|
||
|
formatf(rawFilename, "%s%s", CFileMgr::GetRootDirectory(), pFilename);
|
||
|
#endif // RSG_DURANGO && !__FINAL
|
||
|
|
||
|
OverridePathName(filename, sizeof(filename), rawFilename);
|
||
|
}
|
||
|
|
||
|
ASSET.CreateLeadingPath(filename);
|
||
|
SaveMemVisualizeFiles(filename);
|
||
|
|
||
|
Verifyf(PARSER.SaveObject(filename, "xml", g_ZoneCapture.GetResults(), parManager::XML), "Saving %s.xml failed", filename);
|
||
|
Displayf("Saved zone report as %s.xml", filename);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZoneStart(const char * zoneName)
|
||
|
{
|
||
|
if(!g_ZoneCapture.Running())
|
||
|
{
|
||
|
g_ZoneCapture.StartCapture();
|
||
|
}
|
||
|
if(g_ZoneCapture.Sampling())
|
||
|
{
|
||
|
MetricsZoneStop();
|
||
|
}
|
||
|
InitFramesPerSecondResult(&g_ZoneFramesPerSecond);
|
||
|
InitMSPerFrameResult(&g_ZoneMSPerFrame);
|
||
|
InitCPUTimingResults(s_Timebars);
|
||
|
InitThreadTimingResults(s_Threads);
|
||
|
InitMemoryBucketUsageResults(g_ZoneMemoryBucketUsages);
|
||
|
InitDrawListResults(g_ZoneDrawListCounts);
|
||
|
InitScriptMemResult(g_ZoneScriptMemUsage);
|
||
|
InitMemDistributionResult(g_ZoneMemoryDistributionUsage);
|
||
|
InitPedAndVehicleStatResult(g_ZonePedAndVehicleStatUsage);
|
||
|
InitStreamingStats(g_ZoneStreamingStats);
|
||
|
g_ZoneCapture.StartSampling(0, zoneName);
|
||
|
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsZoneStop()
|
||
|
{
|
||
|
Assertf(g_ZoneCapture.GetResults()->results.GetCount(), "Calling MetricsZoneStop() on an empty result list - was MetricsZoneStart() not called first?");
|
||
|
|
||
|
g_ZoneCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(g_ZoneCapture.GetResults(), g_ZoneFramesPerSecond);
|
||
|
StoreMSPerFrameResult(g_ZoneCapture.GetResults(), g_ZoneMSPerFrame);
|
||
|
StoreCPUTimingResults(g_ZoneCapture.GetResults(), s_Timebars);
|
||
|
StoreThreadTimingResults(g_ZoneCapture.GetResults(), s_Threads);
|
||
|
StoreMemoryBucketUsageResults(g_ZoneCapture.GetResults(), g_ZoneMemoryBucketUsages);
|
||
|
StoreDrawListResults(g_ZoneCapture.GetResults(), g_ZoneDrawListCounts);
|
||
|
StoreScriptMemResult(g_ZoneCapture.GetResults(), g_ZoneScriptMemUsage);
|
||
|
StoreMemDistributionResult(g_ZoneCapture.GetResults(), g_ZoneMemoryDistributionUsage);
|
||
|
StorePedAndVehicleStatResult(g_ZoneCapture.GetResults(), g_ZonePedAndVehicleStatUsage);
|
||
|
StoreStreamingStats(g_ZoneCapture.GetResults(), g_ZoneStreamingStats);
|
||
|
}
|
||
|
|
||
|
// DEBUG
|
||
|
void MetricsZoneWriteTelemetry()
|
||
|
{
|
||
|
g_ZoneCapture.SendToTelemetry();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestClear()
|
||
|
{
|
||
|
if( Verifyf( g_ZoneCapture.Sampling() == false, "Called METRICS_ZONES_CLEAR while sampling is running! Call METRICS_ZONE_STOP first!!\n" ))
|
||
|
{
|
||
|
MutexHelper Helper;
|
||
|
|
||
|
s_SmokeTestCapture.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestDisplay(bool show)
|
||
|
{
|
||
|
g_SmokeTestShowWindow = show;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestDraw()
|
||
|
{
|
||
|
g_SmokeTestWindow.Draw();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestSave()
|
||
|
{
|
||
|
SaveResults(s_SmokeTestCapture.GetResults());
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestSaveToFilename(const char *pFilename)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
Assertf(pFilename != NULL, "Passed filename is NULL");
|
||
|
|
||
|
char rawFilename[RAGE_MAX_PATH];
|
||
|
formatf(rawFilename, "%s%s", CFileMgr::GetRootDirectory(), pFilename);
|
||
|
|
||
|
char filename[RAGE_MAX_PATH];
|
||
|
OverridePathName(filename, sizeof(filename), rawFilename);
|
||
|
|
||
|
ASSET.CreateLeadingPath(filename);
|
||
|
SaveMemVisualizeFiles(filename);
|
||
|
|
||
|
Verifyf(PARSER.SaveObject(filename, "xml", s_SmokeTestCapture.GetResults(), parManager::XML), "Saving %s.xml failed", filename);
|
||
|
Displayf("Saved zone report as %s.xml", filename);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestStop()
|
||
|
{
|
||
|
Assertf(s_SmokeTestCapture.GetResults()->results.GetCount(), "Calling MetricsSmokeTestStop() on an empty result list - was MetricsSmokeTestStart() not called first?");
|
||
|
|
||
|
s_SmokeTestCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(s_SmokeTestCapture.GetResults(), s_SmokeTestFramesPerSecond);
|
||
|
StoreMSPerFrameResult(s_SmokeTestCapture.GetResults(), s_SmokeTestMSPerFrame);
|
||
|
StoreCPUTimingResults(s_SmokeTestCapture.GetResults(), s_Timebars);
|
||
|
StoreMemoryBucketUsageResults(s_SmokeTestCapture.GetResults(), s_SmokeTestMemoryBucketUsages);
|
||
|
StoreMemHeapResults(s_SmokeTestCapture.GetResults());
|
||
|
StoreStreamingModuleMemory(s_SmokeTestCapture.GetResults());
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void MetricsSmokeTestStart(const char * zoneName)
|
||
|
{
|
||
|
if(!s_SmokeTestCapture.Running())
|
||
|
{
|
||
|
s_SmokeTestCapture.StartCapture();
|
||
|
}
|
||
|
if(s_SmokeTestCapture.Sampling())
|
||
|
{
|
||
|
MetricsSmokeTestStop();
|
||
|
}
|
||
|
|
||
|
InitFramesPerSecondResult(&s_SmokeTestFramesPerSecond);
|
||
|
InitMSPerFrameResult(&s_SmokeTestMSPerFrame);
|
||
|
InitCPUTimingResults(s_Timebars);
|
||
|
InitMemoryBucketUsageResults(s_SmokeTestMemoryBucketUsages);
|
||
|
s_SmokeTestCapture.StartSampling(0, zoneName);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
#if __BANK
|
||
|
void AddWidgets(bkBank& bank)
|
||
|
{
|
||
|
bank.AddToggle("Show On Demand Window", &g_OnDemandShowWindow);
|
||
|
bank.AddToggle("Show Zone Window", &g_ZoneShowWindow);
|
||
|
bank.AddButton("Start/Stop Auto Metrics Capture",CFA(AutoCaptureToggle));
|
||
|
bank.AddButton("Start/Stop On Demand Metrics Capture",CFA(OnDemandCaptureToggle));
|
||
|
bank.AddButton("Save zone report",CFA(MetricsZonesSave));
|
||
|
bank.AddButton("Printout Script Timing Report",CFA(SetScriptReportAllScriptTimes));
|
||
|
|
||
|
// DEBUG, to test telemetry writing for Zone Capture Report
|
||
|
bank.AddButton("Metrics Zone Start",CFA(MetricsZoneStart));
|
||
|
bank.AddButton("Metrics Zone Stop",CFA(MetricsZoneStop));
|
||
|
bank.AddButton("Metrics Zone Write Telemetry",CFA(MetricsZoneWriteTelemetry));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool AutoCaptureCountdownRunning(float currentTime)
|
||
|
{
|
||
|
return g_AutoCaptureStartTime != 0.0f && (currentTime < g_AutoCaptureStartTime);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void AutoCaptureCountdownUpdate(float currentTime)
|
||
|
{
|
||
|
float deltaTime = (currentTime - g_AutoCaptureLastWarningTime);
|
||
|
if(deltaTime > 1000.0f)
|
||
|
{
|
||
|
bool output = diagChannel::GetOutput();
|
||
|
diagChannel::SetOutput(true);
|
||
|
Displayf("About to start auto metrics capture, %.0f", (g_AutoCaptureStartTime - currentTime) / 1000.0f);
|
||
|
diagChannel::SetOutput(output);
|
||
|
g_AutoCaptureLastWarningTime = currentTime;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool AutoCaptureCountdownExpired(float currentTime)
|
||
|
{
|
||
|
return g_AutoCaptureStartTime != 0.0f && (currentTime > g_AutoCaptureStartTime);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void AutoCaptureCountdownStart(float currentTime, float countdownMilliseconds)
|
||
|
{
|
||
|
g_AutoCaptureStartTime = currentTime + countdownMilliseconds;
|
||
|
g_AutoCaptureLastWarningTime = currentTime;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void AutoCaptureCountdownCancel()
|
||
|
{
|
||
|
g_AutoCaptureStartTime = 0.0f;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool AutoCaptureCallback(int currentLocation)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
char name[RAGE_MAX_PATH];
|
||
|
char nameScreenshot[RAGE_MAX_PATH];
|
||
|
char capturePath[RAGE_MAX_PATH];
|
||
|
char screenshotPath[RAGE_MAX_PATH];
|
||
|
{
|
||
|
MutexHelper Helper;
|
||
|
|
||
|
GetBasePath(name, __XENON);
|
||
|
GetBasePath(nameScreenshot);
|
||
|
|
||
|
|
||
|
InitFramesPerSecondResult(&g_AutoFramesPerSecond);
|
||
|
InitMSPerFrameResult(&g_AutoMSPerFrame);
|
||
|
InitCPUTimingResults(g_AutoCpuTimings);
|
||
|
InitThreadTimingResults(g_AutoThreadTimings);
|
||
|
InitMemoryBucketUsageResults(g_AutoMemoryBucketUsages);
|
||
|
InitDrawListResults(g_AutoDrawListCounts);
|
||
|
InitScriptMemResult(g_AutoScriptMemUsage);
|
||
|
InitMemDistributionResult(g_AutoMemoryDistributionUsage);
|
||
|
InitPedAndVehicleStatResult(g_AutoPedAndVehicleStatUsage);
|
||
|
InitStreamingStats(g_AutoStreamingStats);
|
||
|
|
||
|
g_AutoCapture.StartSampling(currentLocation, g_LocationList->GetLocationName(currentLocation));
|
||
|
|
||
|
//If a name is specified use it
|
||
|
if (g_LocationList->GetLocationName(currentLocation))
|
||
|
{
|
||
|
#if __XENON
|
||
|
formatf(capturePath, "%s.%s.pix2", name, g_LocationList->GetLocationName(currentLocation));
|
||
|
#else
|
||
|
formatf(capturePath, "%s.%s.vr", name, g_LocationList->GetLocationName(currentLocation));
|
||
|
#endif
|
||
|
formatf(screenshotPath, "%s.%s", nameScreenshot, g_LocationList->GetLocationName(currentLocation));
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if __XENON
|
||
|
formatf(capturePath, "%s.%d.pix2", name, currentLocation);
|
||
|
#else
|
||
|
formatf(capturePath, "%s.%d.vr", name, currentLocation);
|
||
|
#endif
|
||
|
formatf(screenshotPath, "%s.%d", nameScreenshot, currentLocation);
|
||
|
}
|
||
|
|
||
|
for(int i=0;i<gDrawListMgr->GetDrawListTypeCount();i++)
|
||
|
{
|
||
|
gpuTimingResult *result = rage_new gpuTimingResult;
|
||
|
result->idx = i;
|
||
|
result->name = gDrawListMgr->GetDrawListName(i);
|
||
|
result->time = gDrawListMgr->GetDrawListGPUTime(i);
|
||
|
g_AutoCapture.GetResults()->results.Top()->gpuResults.Grow() = result;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if __BANK
|
||
|
CStreamGraph streamingMemTracker;
|
||
|
streamingMemTracker.IncludeVirtualMemory(true);
|
||
|
streamingMemTracker.IncludePhysicalMemory(true);
|
||
|
streamingMemTracker.IncludeReferencedObjects(true);
|
||
|
streamingMemTracker.IncludeDontDeleteObjects(true);
|
||
|
streamingMemTracker.IncludeCachedObjects(true);
|
||
|
streamingMemTracker.CollectResultsForAutoCapture(g_AutoCapture.GetResults()->results.Top()->streamingMemoryResults);
|
||
|
#endif //__BANK
|
||
|
}
|
||
|
|
||
|
|
||
|
#if DEBUG_METRICS_CAPTURES == 0
|
||
|
CSystem::GetRageSetup()->SetScreenShotNamingConvention( grcSetup::OVERWRITE_SCREENSHOT );
|
||
|
CSystem::GetRageSetup()->TakeScreenShot( screenshotPath);
|
||
|
Assert( !PIXIsGPUCapturing() );
|
||
|
PIXSaveGPUCapture(capturePath);
|
||
|
#endif // DEBUG_METRICS_CAPTURES == 0
|
||
|
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StartAutoCapture()
|
||
|
{
|
||
|
g_AutoCaptureCallback.Bind(&AutoCaptureCallback);
|
||
|
g_LocationList->SetVisitCallback(g_AutoCaptureCallback);
|
||
|
g_AutoCapture.StartCapture();
|
||
|
g_LocationList->Visit(g_AutoCaptureWarpTime, g_AutoCaptureCallbackTime);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void StopAutoCapture()
|
||
|
{
|
||
|
g_LocationList->StopVisiting();
|
||
|
g_AutoCapture.Reset();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// SmokeTest
|
||
|
|
||
|
//static const char* s_lastSection = NULL;
|
||
|
|
||
|
void SmokeTestSectionCaptureStart(const char * section)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
if(!s_SmokeTestCapture.Running())
|
||
|
{
|
||
|
s_SmokeTestCapture.StartCapture();
|
||
|
}
|
||
|
// s_lastSection = section;
|
||
|
|
||
|
Assert(!s_SmokeTestCapture.Sampling());
|
||
|
|
||
|
InitFramesPerSecondResult(&s_SmokeTestFramesPerSecond);
|
||
|
InitMSPerFrameResult(&s_SmokeTestMSPerFrame);
|
||
|
InitCPUTimingResults(s_Timebars);
|
||
|
InitThreadTimingResults(s_Threads);
|
||
|
InitMemoryBucketUsageResults(s_SmokeTestMemoryBucketUsages);
|
||
|
InitDrawListResults(s_SmokeTestDrawListCounts);
|
||
|
InitScriptMemResult(s_SmokeTestScriptMemUsage);
|
||
|
InitMemDistributionResult(s_SmokeTestMemoryDistributionUsage);
|
||
|
InitPedAndVehicleStatResult(s_SmokeTestPedAndVehicleStatUsage);
|
||
|
InitStreamingStats(g_SmokeTestStreamingStats);
|
||
|
|
||
|
s_SmokeTestCapture.StartSampling(s_SmokeTestCapture.GetResults()->results.GetCount(), section);
|
||
|
|
||
|
for(int i=0;i<gDrawListMgr->GetDrawListTypeCount();i++)
|
||
|
{
|
||
|
gpuTimingResult *result = rage_new gpuTimingResult;
|
||
|
result->idx = i;
|
||
|
result->name = gDrawListMgr->GetDrawListName(i);
|
||
|
result->time = gDrawListMgr->GetDrawListGPUTime(i);
|
||
|
s_SmokeTestCapture.GetResults()->results.Top()->gpuResults.Grow() = result;
|
||
|
}
|
||
|
|
||
|
#if __BANK
|
||
|
CStreamGraph streamingMemTracker;
|
||
|
streamingMemTracker.IncludeVirtualMemory(true);
|
||
|
streamingMemTracker.IncludePhysicalMemory(true);
|
||
|
streamingMemTracker.IncludeReferencedObjects(true);
|
||
|
streamingMemTracker.IncludeDontDeleteObjects(true);
|
||
|
streamingMemTracker.IncludeCachedObjects(true);
|
||
|
streamingMemTracker.CollectResultsForAutoCapture(s_SmokeTestCapture.GetResults()->results.Top()->streamingMemoryResults);
|
||
|
#endif //__BANK
|
||
|
}
|
||
|
|
||
|
void SmokeTestSectionCaptureStop()
|
||
|
{
|
||
|
Assert(s_SmokeTestCapture.Sampling());
|
||
|
s_SmokeTestCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(s_SmokeTestCapture.GetResults(), s_SmokeTestFramesPerSecond);
|
||
|
StoreMSPerFrameResult(s_SmokeTestCapture.GetResults(), s_SmokeTestMSPerFrame);
|
||
|
StoreCPUTimingResults(s_SmokeTestCapture.GetResults(), s_Timebars);
|
||
|
StoreThreadTimingResults(s_SmokeTestCapture.GetResults(), s_Threads);
|
||
|
StoreMemoryBucketUsageResults(s_SmokeTestCapture.GetResults(), s_SmokeTestMemoryBucketUsages);
|
||
|
StoreMemHeapResults(s_SmokeTestCapture.GetResults());
|
||
|
StoreDrawListResults(s_SmokeTestCapture.GetResults(), s_SmokeTestDrawListCounts);
|
||
|
StoreScriptMemResult(s_SmokeTestCapture.GetResults(), s_SmokeTestScriptMemUsage);
|
||
|
StoreMemDistributionResult(s_SmokeTestCapture.GetResults(), s_SmokeTestMemoryDistributionUsage);
|
||
|
StorePedAndVehicleStatResult(s_SmokeTestCapture.GetResults(), s_SmokeTestPedAndVehicleStatUsage);
|
||
|
StoreStreamingStats(g_AutoCapture.GetResults(), g_SmokeTestStreamingStats);
|
||
|
}
|
||
|
|
||
|
void SmokeTestSaveResults(const char * report)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
char filename[256];
|
||
|
formatf(filename, "%s%s", CFileMgr::GetRootDirectory(), report);
|
||
|
|
||
|
ASSET.CreateLeadingPath(filename);
|
||
|
SaveMemVisualizeFiles(filename);
|
||
|
|
||
|
Verifyf(PARSER.SaveObject(report, "xml", s_SmokeTestCapture.GetResults(), parManager::XML), "Saving %s.xml failed", report);
|
||
|
Displayf("Saved report as %s.xml", report);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
static void UpdateSmokeTestCapture(float UNUSED_PARAM(currentTime))
|
||
|
{
|
||
|
if(s_SmokeTestCapture.Running())
|
||
|
{
|
||
|
if(s_SmokeTestCapture.Sampling())
|
||
|
{
|
||
|
UpdateFramesPerSecondResult(&s_SmokeTestFramesPerSecond);
|
||
|
UpdateMSPerFrameResult(&s_SmokeTestMSPerFrame);
|
||
|
UpdateCPUTimingResults(s_Timebars);
|
||
|
UpdateThreadTimingResults(s_Threads);
|
||
|
UpdateMemoryBucketUsageResults(s_SmokeTestMemoryBucketUsages);
|
||
|
UpdateDrawListResults(s_SmokeTestDrawListCounts);
|
||
|
UpdateScriptMemResult(s_SmokeTestScriptMemUsage);
|
||
|
UpdateMemDistributionResult(s_SmokeTestMemoryDistributionUsage);
|
||
|
UpdatePedAndVehicleStatResult(s_SmokeTestPedAndVehicleStatUsage);
|
||
|
UpdateStreamingStats(g_SmokeTestStreamingStats);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void UpdateAutomatedSmokeTestCapture(float UNUSED_PARAM(currentTime))
|
||
|
{
|
||
|
if(s_SmokeTestCapture.Running())
|
||
|
{
|
||
|
if(s_SmokeTestCapture.Sampling())
|
||
|
{
|
||
|
UpdateFramesPerSecondResult(&s_SmokeTestFramesPerSecond);
|
||
|
UpdateMSPerFrameResult(&s_SmokeTestMSPerFrame);
|
||
|
UpdateCPUTimingResults(s_Timebars);
|
||
|
UpdateMemoryBucketUsageResults(s_SmokeTestMemoryBucketUsages);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateAutoCapture(float currentTime)
|
||
|
{
|
||
|
if(g_AutoCaptureRun)
|
||
|
{
|
||
|
if(g_AutoCapture.Running())
|
||
|
{
|
||
|
if(g_LocationList->Visiting())
|
||
|
{
|
||
|
if(g_AutoCapture.Sampling() && g_LocationList->GetCurrentLocation() != g_AutoCapture.GetSamplingId())
|
||
|
{
|
||
|
g_AutoCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(g_AutoCapture.GetResults(), g_AutoFramesPerSecond);
|
||
|
StoreMSPerFrameResult(g_AutoCapture.GetResults(), g_AutoMSPerFrame);
|
||
|
StoreCPUTimingResults(g_AutoCapture.GetResults(), g_AutoCpuTimings);
|
||
|
StoreThreadTimingResults(g_AutoCapture.GetResults(), g_AutoThreadTimings);
|
||
|
StoreMemoryBucketUsageResults(g_AutoCapture.GetResults(), g_AutoMemoryBucketUsages);
|
||
|
StoreDrawListResults(g_AutoCapture.GetResults(), g_AutoDrawListCounts);
|
||
|
StoreScriptMemResult(g_AutoCapture.GetResults(), g_AutoScriptMemUsage);
|
||
|
StoreMemDistributionResult(g_AutoCapture.GetResults(), g_AutoMemoryDistributionUsage);
|
||
|
StorePedAndVehicleStatResult(g_AutoCapture.GetResults(), g_AutoPedAndVehicleStatUsage);
|
||
|
StoreStreamingStats(g_AutoCapture.GetResults(), g_AutoStreamingStats);
|
||
|
}
|
||
|
else if(g_AutoCapture.Sampling())
|
||
|
{
|
||
|
UpdateFramesPerSecondResult(&g_AutoFramesPerSecond);
|
||
|
UpdateMSPerFrameResult(&g_AutoMSPerFrame);
|
||
|
UpdateCPUTimingResults(g_AutoCpuTimings);
|
||
|
UpdateThreadTimingResults(g_AutoThreadTimings);
|
||
|
UpdateMemoryBucketUsageResults(g_AutoMemoryBucketUsages);
|
||
|
UpdateDrawListResults(g_AutoDrawListCounts);
|
||
|
UpdateScriptMemResult(g_AutoScriptMemUsage);
|
||
|
UpdateMemDistributionResult(g_AutoMemoryDistributionUsage);
|
||
|
UpdatePedAndVehicleStatResult(g_AutoPedAndVehicleStatUsage);
|
||
|
UpdateStreamingStats(g_AutoStreamingStats);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_AutoCapture.StopSampling();
|
||
|
StoreFramesPerSecondResult(g_AutoCapture.GetResults(), g_AutoFramesPerSecond);
|
||
|
StoreMSPerFrameResult(g_AutoCapture.GetResults(), g_AutoMSPerFrame);
|
||
|
StoreCPUTimingResults(g_AutoCapture.GetResults(), g_AutoCpuTimings);
|
||
|
StoreThreadTimingResults(g_AutoCapture.GetResults(), g_AutoThreadTimings);
|
||
|
StoreMemoryBucketUsageResults(g_AutoCapture.GetResults(), g_AutoMemoryBucketUsages);
|
||
|
StoreDrawListResults(g_AutoCapture.GetResults(), g_AutoDrawListCounts);
|
||
|
StoreScriptMemResult(g_AutoCapture.GetResults(), g_AutoScriptMemUsage);
|
||
|
StoreMemDistributionResult(g_AutoCapture.GetResults(), g_AutoMemoryDistributionUsage);
|
||
|
StorePedAndVehicleStatResult(g_AutoCapture.GetResults(), g_AutoPedAndVehicleStatUsage);
|
||
|
StoreStreamingStats(g_AutoCapture.GetResults(), g_AutoStreamingStats);
|
||
|
|
||
|
SaveResults(g_AutoCapture.GetResults());
|
||
|
AutoCaptureToggle();
|
||
|
}
|
||
|
}
|
||
|
else if(AutoCaptureCountdownRunning(currentTime))
|
||
|
{
|
||
|
AutoCaptureCountdownUpdate(currentTime);
|
||
|
}
|
||
|
else if(AutoCaptureCountdownExpired(currentTime))
|
||
|
{
|
||
|
PrintStatus("Metrics capture started");
|
||
|
InitPlayerState();
|
||
|
StartAutoCapture();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AutoCaptureCountdownStart(currentTime, g_AutoCaptureTimeBeforeStart);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(g_AutoCapture.Running())
|
||
|
{
|
||
|
PrintStatus("Metrics capture stopped");
|
||
|
StopAutoCapture();
|
||
|
RestorePlayerState();
|
||
|
}
|
||
|
AutoCaptureCountdownCancel();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateOnDemandCapture(float UNUSED_PARAM(currentTime))
|
||
|
{
|
||
|
if(g_OnDemandCapture.Running())
|
||
|
{
|
||
|
if(g_OnDemandCapture.Sampling())
|
||
|
{
|
||
|
UpdateFramesPerSecondResult(&g_OnDemandFramesPerSecond);
|
||
|
UpdateMSPerFrameResult(&g_OnDemandMSPerFrame);
|
||
|
UpdateCPUTimingResults(g_OnDemandCpuTimings);
|
||
|
UpdateThreadTimingResults(g_OnDemandThreadTimings);
|
||
|
UpdateMemoryBucketUsageResults(g_OnDemandMemoryBucketUsages);
|
||
|
UpdateDrawListResults(g_OnDemandDrawListCounts);
|
||
|
UpdateScriptMemResult(g_OnDemandScriptMemUsage);
|
||
|
UpdateMemDistributionResult(g_OnDemandMemoryDistributionUsage);
|
||
|
UpdatePedAndVehicleStatResult(g_OnDemandPedAndVehicleStatUsage);
|
||
|
UpdateStreamingStats(g_OnDemandStreamingStats);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void UpdateZoneCapture(float UNUSED_PARAM(currentTime))
|
||
|
{
|
||
|
if(g_ZoneCapture.Running())
|
||
|
{
|
||
|
if(g_ZoneCapture.Sampling())
|
||
|
{
|
||
|
UpdateFramesPerSecondResult(&g_ZoneFramesPerSecond);
|
||
|
UpdateMSPerFrameResult(&g_ZoneMSPerFrame);
|
||
|
UpdateCPUTimingResults(s_Timebars);
|
||
|
UpdateThreadTimingResults(s_Threads);
|
||
|
UpdateMemoryBucketUsageResults(g_ZoneMemoryBucketUsages);
|
||
|
UpdateDrawListResults(g_ZoneDrawListCounts);
|
||
|
UpdateScriptMemResult(g_ZoneScriptMemUsage);
|
||
|
UpdateMemDistributionResult(g_ZoneMemoryDistributionUsage);
|
||
|
UpdatePedAndVehicleStatResult(g_ZonePedAndVehicleStatUsage);
|
||
|
UpdateStreamingStats(g_ZoneStreamingStats);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void Init()
|
||
|
{
|
||
|
ProcessParams();
|
||
|
InitDrawListCounts();
|
||
|
g_OnDemandWindow.Move(0.5f, 0.2f);
|
||
|
|
||
|
MutexHelper::sm_Mutex = rage::sysIpcCreateMutex();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void Update(float currentTime)
|
||
|
{
|
||
|
MutexHelper Helper;
|
||
|
|
||
|
ProcessKeyboardInput();
|
||
|
UpdateAutoCapture(currentTime);
|
||
|
UpdateOnDemandCapture(currentTime);
|
||
|
UpdateZoneCapture(currentTime);
|
||
|
UpdateSmokeTestCapture(currentTime);
|
||
|
UpdateAutomatedSmokeTestCapture(currentTime);
|
||
|
|
||
|
ScriptTimingUpdate(currentTime);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void Shutdown()
|
||
|
{
|
||
|
sysIpcDeleteMutex(MutexHelper::sm_Mutex);
|
||
|
|
||
|
g_AutoCapture.Reset();
|
||
|
g_OnDemandCapture.Reset();
|
||
|
g_ZoneCapture.Reset();
|
||
|
s_SmokeTestCapture.Reset();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
void DrawWindows()
|
||
|
{
|
||
|
MutexHelper Helper;
|
||
|
|
||
|
if(g_OnDemandShowWindow) g_OnDemandWindow.Draw();
|
||
|
if(g_ZoneShowWindow) g_ZoneWindow.Draw();
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Script timing (B*496942)
|
||
|
// Wasn't up to par as it only did all threads, updated to do individual threads also.. now B*529119
|
||
|
#include "script/thread.h"
|
||
|
|
||
|
#if __WIN32PC
|
||
|
#define SAMPLE_FRAMES_PER_SECOND 65 // PC can go at 60Hz (plus a little overhead)
|
||
|
#else
|
||
|
#define SAMPLE_FRAMES_PER_SECOND 35 // Consoles go at 30Hz (plus a little overhead, looks like it can go faster during loading transitions.)
|
||
|
#endif
|
||
|
|
||
|
// Ring buffer to capture script timing info
|
||
|
#define SCRIPT_TIME_SAMPLES_TIME (10)
|
||
|
#define NUM_SCRIPT_TIME_SAMPLES (SAMPLE_FRAMES_PER_SECOND * SCRIPT_TIME_SAMPLES_TIME) // 30 samples (maxfps) for 10 seconds (upped to 40 to prevent any possible overflow).
|
||
|
#define MIN_SCRIPT_SAMPLE_TIME ( 1000.0f / SAMPLE_FRAMES_PER_SECOND)
|
||
|
|
||
|
class ScriptTimingRingBufferContents
|
||
|
{
|
||
|
public:
|
||
|
ScriptTimingRingBufferContents()
|
||
|
{
|
||
|
timeStamp = -SCRIPT_TIME_SAMPLES_TIME * 1000.0f;
|
||
|
cpuTime = 0.0f;
|
||
|
}
|
||
|
float timeStamp;
|
||
|
float cpuTime;
|
||
|
};
|
||
|
|
||
|
class ScriptTimingContainer
|
||
|
{
|
||
|
public:
|
||
|
ScriptTimingContainer()
|
||
|
{
|
||
|
m_Name = atHashString("");
|
||
|
m_ScriptTimingIndex = 0;
|
||
|
m_DoReport = false;
|
||
|
m_Updated = false;
|
||
|
}
|
||
|
|
||
|
void SetName(const char *pName)
|
||
|
{
|
||
|
m_Name = atHashString(pName);
|
||
|
}
|
||
|
|
||
|
void SetThreadID(scrThreadId id)
|
||
|
{
|
||
|
m_threadID = id;
|
||
|
}
|
||
|
|
||
|
u32 GetPreviousTimeIndex()
|
||
|
{
|
||
|
s32 lastTimeIndex = m_ScriptTimingIndex-1;
|
||
|
if( lastTimeIndex < 0)
|
||
|
{
|
||
|
lastTimeIndex+=NUM_SCRIPT_TIME_SAMPLES;
|
||
|
}
|
||
|
return (u32)lastTimeIndex;
|
||
|
}
|
||
|
|
||
|
void GetAverageAndPeakTimes(float currentTime, float &average, float &peak)
|
||
|
{
|
||
|
CPUTiming timing;
|
||
|
timing.value.Reset();
|
||
|
for(int i=0;i<NUM_SCRIPT_TIME_SAMPLES;i++)
|
||
|
{
|
||
|
ScriptTimingRingBufferContents &thisRingEntry = m_ScriptTimings[i];
|
||
|
if( currentTime - thisRingEntry.timeStamp < (SCRIPT_TIME_SAMPLES_TIME*1000.0f) )
|
||
|
{
|
||
|
timing.value.AddSample(thisRingEntry.cpuTime);
|
||
|
}
|
||
|
}
|
||
|
average = timing.value.Mean();
|
||
|
peak = timing.value.Max();
|
||
|
}
|
||
|
|
||
|
|
||
|
atHashString m_Name; // The script name, which is used for the timebar for that script.
|
||
|
scrThreadId m_threadID;
|
||
|
u32 m_ScriptTimingIndex; // Ring buffer index
|
||
|
atRangeArray<ScriptTimingRingBufferContents, NUM_SCRIPT_TIME_SAMPLES> m_ScriptTimings; // The actual ring buffer
|
||
|
bool m_DoReport;
|
||
|
bool m_Updated;
|
||
|
};
|
||
|
|
||
|
atArray<ScriptTimingContainer*> g_ScriptTimingContainers;
|
||
|
|
||
|
/*
|
||
|
ScriptTimingContainer *FindTimingContainerByName(const char *pName)
|
||
|
{
|
||
|
atHashString nameHash(pName);
|
||
|
for(int i=0;i<g_ScriptTimingContainers.size();i++)
|
||
|
{
|
||
|
if( g_ScriptTimingContainers[i]->m_Name == nameHash )
|
||
|
{
|
||
|
return g_ScriptTimingContainers[i];
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
ScriptTimingContainer *FindTimingContainerByThreadID(scrThreadId id)
|
||
|
{
|
||
|
int numContainers = g_ScriptTimingContainers.size();
|
||
|
ScriptTimingContainer **pContainerPtr = g_ScriptTimingContainers.begin();
|
||
|
for(int i=0;i<numContainers;i++)
|
||
|
{
|
||
|
ScriptTimingContainer *pContainer = *pContainerPtr;
|
||
|
if( pContainer->m_threadID == id )
|
||
|
{
|
||
|
return pContainer;
|
||
|
}
|
||
|
pContainerPtr++;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
void UpdateScriptTiming(scrThread *pScriptThread, float currentTime)
|
||
|
{
|
||
|
USE_DEBUG_MEMORY();
|
||
|
|
||
|
// Find the existing timing info struct (if it exists)
|
||
|
ScriptTimingContainer *pThisTimebarData = FindTimingContainerByThreadID(pScriptThread->GetThreadId());
|
||
|
// Check if we found it, if not, make one
|
||
|
if( !pThisTimebarData )
|
||
|
{
|
||
|
pThisTimebarData = rage_new ScriptTimingContainer;
|
||
|
pThisTimebarData->SetName(pScriptThread->GetScriptName());
|
||
|
pThisTimebarData->SetThreadID(pScriptThread->GetThreadId());
|
||
|
g_ScriptTimingContainers.Grow() = pThisTimebarData;
|
||
|
}
|
||
|
|
||
|
// If we couldn't allocate one, it's busted!
|
||
|
Assertf(pThisTimebarData!=NULL,"");
|
||
|
|
||
|
// Check if we're updating faster than NUM_SCRIPT_TIME_SAMPLES(Hz)
|
||
|
// Get the last time
|
||
|
u32 lastTimeIndex = pThisTimebarData->GetPreviousTimeIndex();
|
||
|
ScriptTimingRingBufferContents &lastRingEntry = pThisTimebarData->m_ScriptTimings[lastTimeIndex];
|
||
|
float diffTime = currentTime - lastRingEntry.timeStamp;
|
||
|
if( diffTime < MIN_SCRIPT_SAMPLE_TIME )
|
||
|
{
|
||
|
// We've got a time update that is faster than the max game update time.. Game is updating faster than 30Hz, skip this sample
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the next used ring buffer entry
|
||
|
ScriptTimingRingBufferContents &ringEntry = pThisTimebarData->m_ScriptTimings[pThisTimebarData->m_ScriptTimingIndex];
|
||
|
// Wrap index
|
||
|
pThisTimebarData->m_ScriptTimingIndex++;
|
||
|
if( pThisTimebarData->m_ScriptTimingIndex >= NUM_SCRIPT_TIME_SAMPLES )
|
||
|
{
|
||
|
pThisTimebarData->m_ScriptTimingIndex = 0;
|
||
|
}
|
||
|
|
||
|
// Assert if the timestamp is not over 10 seconds old (this should now never happen due to overspeed check above)
|
||
|
Assertf( ringEntry.timeStamp <= (currentTime - (SCRIPT_TIME_SAMPLES_TIME*1000.0f)), "Timestamp is under 10 seconds old!! It's going to go wrong" );
|
||
|
|
||
|
// Store the timestamp & get the CPU times from the Timebars
|
||
|
ringEntry.timeStamp = currentTime;
|
||
|
|
||
|
#if SCRIPT_DEBUGGING
|
||
|
|
||
|
ringEntry.cpuTime = (pScriptThread->GetUpdateTime() - pScriptThread->GetConsoleOutputTime()) * 1000.0f; // Times in seconds.
|
||
|
|
||
|
#endif //SCRIPT_DEBUGGING
|
||
|
|
||
|
/* // If we wanna go back to timebars
|
||
|
#if RAGE_TIMEBARS
|
||
|
// Using Timebars
|
||
|
ringEntry.cpuTime = 0.0f;
|
||
|
int callcount = 0;
|
||
|
g_pfTB.GetFunctionTotals(pTimebarName, callcount, ringEntry.cpuTime, 1);
|
||
|
#endif // RAGE_TIMEBARS
|
||
|
*/
|
||
|
|
||
|
pThisTimebarData->m_Updated = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReportScriptTimings(float currentTime)
|
||
|
{
|
||
|
int numContainers = g_ScriptTimingContainers.size();
|
||
|
ScriptTimingContainer **pContainerPtr = g_ScriptTimingContainers.begin();
|
||
|
for(int i=0;i<numContainers;i++)
|
||
|
{
|
||
|
ScriptTimingContainer *pContainer = *pContainerPtr;
|
||
|
|
||
|
if(pContainer->m_DoReport == true)
|
||
|
{
|
||
|
pContainer->m_DoReport = false;
|
||
|
|
||
|
// Output the data
|
||
|
float average, peak;
|
||
|
pContainer->GetAverageAndPeakTimes(currentTime, average, peak);
|
||
|
|
||
|
u32 lastTimeIndex = pContainer->GetPreviousTimeIndex();
|
||
|
ScriptTimingRingBufferContents &lastRingEntry = pContainer->m_ScriptTimings[lastTimeIndex];
|
||
|
|
||
|
// Should now have min/max/mean in timing
|
||
|
// Should now have this time in the latest lastRingEntry
|
||
|
Displayf("/-----------------------------------------------------------------------/");
|
||
|
Displayf("Timing data for script %s:-", pContainer->m_Name.GetCStr() );
|
||
|
Displayf("Script Current Processing Time = %f (mSecs)", lastRingEntry.cpuTime );
|
||
|
Displayf("Script Average processing time (over last %d seconds) = %f (mSecs)", SCRIPT_TIME_SAMPLES_TIME, average );
|
||
|
Displayf("Script Peak processing time (over last %d seconds) = %f (mSecs)", SCRIPT_TIME_SAMPLES_TIME, peak );
|
||
|
Displayf("/-----------------------------------------------------------------------/");
|
||
|
}
|
||
|
|
||
|
// Reset Update Flag here
|
||
|
pContainer->m_Updated = false;
|
||
|
pContainerPtr++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// remove anything that wasn't updated this frame.
|
||
|
void CleanupOldScriptTimings()
|
||
|
{
|
||
|
int numContainers = g_ScriptTimingContainers.size();
|
||
|
if( numContainers )
|
||
|
{
|
||
|
ScriptTimingContainer **pContainerPtr = &g_ScriptTimingContainers[numContainers-1];
|
||
|
for(int i=numContainers-1;i>=0;i--)
|
||
|
{
|
||
|
ScriptTimingContainer *pContainer = *pContainerPtr;
|
||
|
if(pContainer->m_Updated == false)
|
||
|
{
|
||
|
// Ditch it!
|
||
|
delete pContainer;
|
||
|
g_ScriptTimingContainers.Delete(i);
|
||
|
}
|
||
|
pContainerPtr--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// currentTime == gameTime in milliSeconds (fwTimer::GetTimeInMilliseconds())
|
||
|
void ScriptTimingUpdate(float currentTime)
|
||
|
{
|
||
|
|
||
|
#if !SCRIPT_DEBUGGING
|
||
|
UNUSED_VAR(currentTime);
|
||
|
#else
|
||
|
|
||
|
// Each individual running script
|
||
|
atArray<scrThread*> &threadsArray = scrThread::GetScriptThreads();
|
||
|
int numThreads = threadsArray.size();
|
||
|
for(int i=0;i<numThreads;i++)
|
||
|
{
|
||
|
if(threadsArray[i]->GetThreadId()) // Only process valid threadID's
|
||
|
{
|
||
|
UpdateScriptTiming(threadsArray[i], currentTime); // NOTE: Sets update flag to true for containers that have been updated.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove script timing containers that are no longer active
|
||
|
CleanupOldScriptTimings();
|
||
|
|
||
|
// Report any timings to the TTY
|
||
|
ReportScriptTimings(currentTime);
|
||
|
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void SetScriptReportAllScriptTimes()
|
||
|
{
|
||
|
for(int i=0;i<g_ScriptTimingContainers.size();i++)
|
||
|
{
|
||
|
ScriptTimingContainer *pContainer = g_ScriptTimingContainers[i];
|
||
|
pContainer->m_DoReport = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Stuff for B*554468
|
||
|
float GetScriptUpdateTime(scrThreadId scriptThreadID)
|
||
|
{
|
||
|
ScriptTimingContainer *pThisTimebarData = FindTimingContainerByThreadID(scriptThreadID);
|
||
|
if(pThisTimebarData)
|
||
|
{
|
||
|
u32 lastTimeIndex = pThisTimebarData->GetPreviousTimeIndex();
|
||
|
ScriptTimingRingBufferContents &lastRingEntry = pThisTimebarData->m_ScriptTimings[lastTimeIndex];
|
||
|
return lastRingEntry.cpuTime;
|
||
|
}
|
||
|
return 0.0f; // error!
|
||
|
}
|
||
|
|
||
|
|
||
|
bool GetScriptPeakAverageTime(scrThreadId scriptThreadID, float &peak, float &average)
|
||
|
{
|
||
|
ScriptTimingContainer *pThisTimebarData = FindTimingContainerByThreadID(scriptThreadID);
|
||
|
if(pThisTimebarData)
|
||
|
{
|
||
|
// Since we don't know the current time (this is called via script), just use the last time anything was updated for this script
|
||
|
// Should be OK since the timing data will have vanished should this script have gone, or updated this frame anyway
|
||
|
u32 lastTimeIndex = pThisTimebarData->GetPreviousTimeIndex();
|
||
|
ScriptTimingRingBufferContents &lastRingEntry = pThisTimebarData->m_ScriptTimings[lastTimeIndex];
|
||
|
// Get average and peak times.
|
||
|
pThisTimebarData->GetAverageAndPeakTimes(lastRingEntry.timeStamp, average, peak );
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
}; // namespace
|
||
|
|
||
|
#endif // ENABLE_STATS_CAPTURE
|