Files
GTASource/game/tools/SmokeTest.cpp

1368 lines
42 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
#if !__FINAL
// Framework hdrs
#include "fwscene/world/WorldLimits.h"
// Rage hdrs
#include "bank/button.h"
#include "diag/output.h"
#include "grcore/image.h"
#include "grmodel/setup.h"
#include "grprofile/timebars.h"
// Game hdrs
#include "Camera/camInterface.h"
#include "Camera/debug/debugdirector.h"
#include "Camera/helpers/frame.h"
#include "Control/GameLogic.h"
#include "Core/Game.h"
#include "cutscene/CutSceneManagerNew.h"
#include "frontend/MiniMap.h"
#include "Game/clock.h"
#include "Game/weather.h"
#include "ModelInfo/ModelInfo.h"
#include "ModelInfo/ModelInfo_Factories.h"
#include "Peds/PedFactory.h"
#include "Peds/PedIntelligence.h"
#include "Peds/PedPopulation.h"
#include "Peds/Ped.h"
#include "peds/rendering/pedvariationDebug.h"
#include "Physics/gtaInst.h"
#include "scene/scene.h"
#include "scene/animatedbuilding.h"
#include "scene/WarpManager.h"
#include "SectorTools.h"
#include "streaming/streaming.h" // For CStreaming::LoadAllRequestedObjects(), etc.
#include "streaming/streamingengine.h"
#include "streaming/streaminginfo.h"
#include "streaming/streamingmodule.h"
#include "streaming/streamingmodulemgr.h"
#include "streaming/streamingdebug.h"
#include "text/TextConversion.h"
#include "Tools/smokeTest.h"
#include "Tools/TracingStats.h"
#include "Tools/ObjectProfiler.h"
#include "Vehicles/VehicleFactory.h"
#include "Weapons/Explosion.h"
#include "system/autogpucapture.h"
// DON'T COMMIT
//OPTIMISATIONS_OFF()
RAGE_DEFINE_CHANNEL(AssetTest)
BANK_ONLY(extern void UpdateAvailableCarsCB();)
extern void CreateNextCar(bool bOnlyIfTheresRoom);
namespace SmokeTests
{
// function prototypes
void InitRageBuilderUnitTest();
void ProcessRageBuilderUnitTest();
void InitBuildState();
void ProcessBuildState();
void InitWanderingTest();
void ProcessWanderingTest();
void InitWarpingTest();
void ProcessWarpingTest();
void ProcessWarping(const int iWarpPeriod);
void InitExplosionTest();
void ProcessExplosionTest();
void ProcessCutsceneTest();
void InitLoadVehicles();
void InitLoadPeds();
void ProcessRestartTest();
void ProcessLevelLoad();
void ProcessLevelReload();
void InitShutdownTest();
void ProcessMemoryTest();
void InitPedPics();
void ProcessPedPics();
void InitCodebuilderStats();
void ProcessCodebuilderStats();
void CaptureCodebuilderStatsState();
void InitJunctionMemStats();
void ProcessJunctionMemStats();
void InitObjectProfiler();
void ProcessObjectProfiler();
PARAM(smoketestwantedlevel, "Set wanted level when initializing the smoketest." );
PARAM(smoketest, "Set up a stress-test situation to see if the game survives! Use with a value (smoketest=n|name) or on its own to select the first." );
PARAM(smokeDuration, "Duration of smoke test to run ");
PARAM(automatedtest, "Tell us that an automated test is running");
PARAM(warpingInterval, "Set up time between warps for smoketest=warping (default 60 seconds)");
#if __BANK // ped pics params
PARAM(pedpiccampos, "[debug] ped pics : camera position");
PARAM(pedpicdisttocrowd, "[debug] ped pics : dist to ped crowd created");
PARAM(pedpiccrowdSize, "[debug] ped pics : crowd dimensions");
PARAM(pedpicgroupuniformdistribution, "[debug] ped pics : density / distribution of crowd.");
PARAM(pedpicstartidx, "[debug] ped pics : start index to capture.");
PARAM(pedpicmaxcaptures, "[debug] ped pics : max picture captures to try, -1 is unlimited.");
PARAM(pedpicheading, "[debug] ped pics : heading of camera");
PARAM(pedpicpitch, "[debug] ped pics : pitch of camera");
PARAM(pedpicroll, "[debug] ped pics : roll of camera");
PARAM(pedpichour, "[debug] ped pics : hour of day");
PARAM(pedpicminute, "[debug] ped pics : minute of day");
PARAM(pedpicsecond, "[debug] ped pics : second of day");
PARAM(pedpicfov, "[debug] ped pics : field fo view");
#endif // __BANK
SmokeTestDef g_SmokeTests[] =
{
// name // init function // update function // description
{"wandering", &InitWanderingTest, &ProcessWanderingTest, "The player is set to wander about the world invincible with a high wanted level."},
{"warping", &InitWarpingTest, &ProcessWarpingTest, "Player is teleported around random areas of the world and set to wander at each location with a high wanted level for a specified time. Any errors are reported."},
{"explosion", &InitExplosionTest, &ProcessExplosionTest, "Player wanders about with explosions going on about the player every second, cars get created periodically."},
{"restart", NULL, &ProcessRestartTest, "A level ( the same one ) is reloaded many times so to determine memory leaks and errors upon reloading itself."},
{"cutscene", NULL, &ProcessCutsceneTest, "Plays each cutscene"},
{"loadvehicles", &InitLoadVehicles, NULL, "For all vehicles... Stream the vehicles in. Instance them. Destroy instance. Remove vehicles and their dependencies from streaming. Record memory heaps before and after. "},
{"loadpeds", &InitLoadPeds, NULL, "For all peds... Stream the peds in. Instance them. Destroy instance. Remove peds and their dependencies from streaming. Record memory heaps before and after."},
{"levelload", NULL, &ProcessLevelLoad, "Cycles through various specified levels for a specified time. Memory usage is displayed between each level to determine if there are memory leaks."},
{"levelreload", NULL, &ProcessLevelReload, "Reloads the default level. Memory usage is displayed between each load to determine if there are memory leaks."},
{"shutdown", &InitShutdownTest, NULL, "The level is shutdown, any errors are reported."},
{"memory", NULL, &ProcessMemoryTest, "Display memory usage periodically."},
{"validatescripts", NULL, NULL, "Loads all .sco files to cause them to be checked for unrecognised native commands by scrThread::Validate inside scrProgram::Load"},
{"pedpics", &InitPedPics, &ProcessPedPics, "Takes pictures of groups of peds in different variations."},
{"buildstate", &InitBuildState, &ProcessBuildState, "Prints 'build state' to tty in a standard parsable form."},
{"ragebuilder_unittest",&InitRageBuilderUnitTest, &ProcessRageBuilderUnitTest,"performs the tests required for checking if assets converted with latest ragebuilder executable are sound."},
{"codebuilder_stats", &InitCodebuilderStats, &ProcessCodebuilderStats, "performs statistic gathering after a codebuilder has made a successful build"},
{"junction_mem_stats", &InitJunctionMemStats, &ProcessJunctionMemStats, "runs the sector tools as a smoketest gathering streaming memory stats captured at junctions"},
{"object_profile", &InitObjectProfiler, &ProcessObjectProfiler, "displays list of objects consecutively, rotating 360 degree's and capturing GPU timing data"},
// ensure last entry has a NULL name
{NULL, NULL, NULL, ""}
};
bool s_terminateSmokeTest = false;
float g_smokeTestDuration = -1.0f;
s32 g_iTimeBeforeStarting = 10000;
SmokeTestDef* g_pSmokeTestDef = NULL;
bool g_bHasParam = true;
Vector3 g_pedPicCamStartPos = Vector3(-1362.0f,-1121.0f,4.75f);
int g_automatedSmokeTest = -1;
int g_defaultWantedLevel = 4;
SmokeTestDef* GetSmokeTestDef(const char* const pStr)
{
SmokeTestDef* pDef = &g_SmokeTests[0];
// search through smoke test list
while(pDef->pName != NULL)
{
if(!stricmp(pDef->pName, pStr))
{
return pDef;
}
pDef++;
}
return NULL;
}
void DisplaySmokeTestStarted(const char* const pStr)
{
char commandLine[1024];
strcpy(commandLine,"");
for (s32 i=0;i<sysParam::GetArgCount();i++)
{
safecat(commandLine,sysParam::GetArg(i));
safecat(commandLine," ");
}
atDisplayf("Smoke Test %s started Duration %d CommandLine %s",pStr,(int)g_smokeTestDuration, commandLine );
atDisplayf("Smoke Test Description : %s", g_pSmokeTestDef->pDesc);
}
void PrintSkeletonData()
{
Displayf("\nSKELETON DATA");
CVehicle::PrintSkeletonData();
CPed::PrintSkeletonData();
CObject::PrintSkeletonData();
CAnimatedBuilding::PrintSkeletonData();
}
void DisplaySmokeTestFinished()
{
PrintSkeletonData();
atDisplayf("Smoke Test finished");
}
//
// name: CSmokeTests::ProcessSmokeTest
// description:
void ProcessSmokeTest()
{
PF_START_TIMEBAR_DETAIL("process smoketest");
if(!g_bHasParam)
return;
const char* pSmokeTestName = NULL;
if (PARAM_automatedtest.Get())
{
g_automatedSmokeTest = 0;
int smoketest = 0;
if (PARAM_automatedtest.Get(smoketest))
g_automatedSmokeTest = smoketest;
}
if (!PARAM_smoketest.Get(pSmokeTestName))
{
return;
}
g_automatedSmokeTest = 0;
// wait 10 seconds before starting smoke tests
if(g_iTimeBeforeStarting > 0)
{
g_iTimeBeforeStarting -= fwTimer::GetTimeStepInMilliseconds();
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "SmokeTest %s is about to start.", pSmokeTestName));
return;
}
// if no definition setup then get command line parameter and search through smoke test list
// for related smoke test
if(g_pSmokeTestDef == NULL)
{
// get smoke test duration value
PARAM_smokeDuration.Get(g_smokeTestDuration);
const char* pStr = NULL;
if(PARAM_smoketest.Get(pStr))
{
g_pSmokeTestDef = GetSmokeTestDef(pStr);
// if smoke test name wasn't found
if(g_pSmokeTestDef == NULL)
{
atDisplayf("Unrecognised smoke tests %s", pStr);
g_bHasParam = false;
return;
}
if (g_pSmokeTestDef->InitFn || g_pSmokeTestDef->UpdateFn)
{
DisplaySmokeTestStarted(pStr);
}
// call initialisation function
if(g_pSmokeTestDef->InitFn != NULL)
g_pSmokeTestDef->InitFn();
}
else
{
// no smoke test parameter
g_bHasParam = false;
}
}
else
{
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "SmokeTest Running : %s", pSmokeTestName));
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "SmokeTest Description : %s", g_pSmokeTestDef->pDesc));
if(g_pSmokeTestDef->UpdateFn != NULL)
{
g_pSmokeTestDef->UpdateFn();
}
}
// Sanity check the heap every frame during smoke tests.
// This causes contention with path finding so just run with -sanitycheckupdate instead
// if you really want it.
// sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_GAME_VIRTUAL)->SanityCheck();
}
//
// name: IsSmokeTestFinished
// description: Return if smoke tests have finished
bool HasSmokeTestFinished()
{
static rage::sysTimer timer;
bool bWantToExit = false;
if ( g_smokeTestDuration != -1 || s_terminateSmokeTest )
{
bWantToExit = ( g_smokeTestDuration > 0 && g_smokeTestDuration < timer.GetTime() );
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "SmokeTest duration %d/%d.", g_smokeTestDuration, timer.GetTime()));
if ( bWantToExit || s_terminateSmokeTest)
{
if (bWantToExit)
{
Errorf("Smoketest being terminated because 'smoketestduration' has elapsed (%2.3f) - bug Derek Ward", g_smokeTestDuration);
}
const char* pSmokeTestName = NULL;
PARAM_smoketest.Get(pSmokeTestName);
// shutdown is a special case smoketest where we care about the
// results of the shutdown
if(pSmokeTestName == NULL || stricmp(pSmokeTestName, "shutdown"))
{
// note can't use displayf as could get filtered out
if (g_pSmokeTestDef->InitFn || g_pSmokeTestDef->UpdateFn)
{
DisplaySmokeTestFinished();
printf("*** TESTER IGNORE REST OF ERRORS ***");
}
}
}
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "Smoke Duration : %d seconds.", g_smokeTestDuration));
}
else
{
const char* pSmokeTestName = NULL;
if (PARAM_smoketest.Get(pSmokeTestName))
{
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput( Color32(1.0f, 1.0f, 0.0f), "Smoke Duration : controlled externally"));
}
}
return bWantToExit || s_terminateSmokeTest;
}
void FinishSmokeTest()
{
s_terminateSmokeTest = true;
}
//********************************************************
// "smoke-tests" which can be run from the command line
void DisplayMemoryUsage(const char* const pStrFilter = NULL,
const bool bDisplayBuckets = true,
const bool bDisplayHeapsAvailable = true,
const bool bDisplayHeapsLargestAvailableBlock = true)
{
const rage::eMemoryType allocators[MAX_ALLOCATORS] = { MEMTYPE_GAME_VIRTUAL,
MEMTYPE_GAME_PHYSICAL,
MEMTYPE_RESOURCE_VIRTUAL,
MEMTYPE_RESOURCE_PHYSICAL };
const char allocStr[MAX_ALLOCATORS][30] = {"GAME_VIRTUAL",
"GAME_PHYSICAL",
"RESOURCE_VIRTUAL",
"RESOURCE_PHYSICAL" };
const char allocStrShort[MAX_ALLOCATORS][5] = {"GV",
"GP",
"RV",
"RP" };
const int buckets[NUM_MEM_BUCKETS] = { 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,
};
char concat[1024],temp[1024];
if (bDisplayBuckets)
{
atDisplayf("Used Memory in Buckets.");
// Memory buckets
for (s32 b=0;b<NUM_MEM_BUCKETS;b++)
{
float val[MAX_ALLOCATORS];
MemoryBucketIds bucket = (MemoryBucketIds)b;
sprintf(concat,"%s",sysMemGetBucketName(bucket));
if (!pStrFilter || !strcmp(pStrFilter,sysMemGetBucketName(bucket)))
{
for (s32 a=0;a<MAX_ALLOCATORS;a++)
{
val[a] = (float)sysMemAllocator::GetMaster().GetAllocator(a)->GetMemoryUsed(buckets[b])/(float)MB;
sprintf(temp,"\t%s %7.3fMB",allocStrShort[a],val[a]);
safecat(concat,temp);
}
}
atDisplayf("%s", concat);
}
atDisplayf(" ");
}
{
// Heap stats
if (bDisplayHeapsLargestAvailableBlock)
{
atDisplayf("Largest Available Block.");
for (s32 i=0;i<MAX_ALLOCATORS;i++)
{
if (!pStrFilter || !strcmp(pStrFilter,allocStr[i]))
{
sprintf(concat,"%s.%s",allocStr[i],"LargestAvailableBlock");
float val = (float)sysMemAllocator::GetCurrent().GetAllocator(allocators[i])->GetLargestAvailableBlock()/(float)MB;
if (val>0.0f)
{
atDisplayf("%s = \t%7.3fMB ",concat,val);
}
}
}
atDisplayf(" ");
}
if (bDisplayHeapsAvailable)
{
atDisplayf("Available.");
for (s32 i=0;i<MAX_ALLOCATORS;i++)
{
if (!pStrFilter || !strcmp(pStrFilter,allocStr[i]))
{
sprintf(concat,"%s.%s",allocStr[i],"Available");
float val = (float)sysMemAllocator::GetCurrent().GetAllocator(allocators[i])->GetMemoryAvailable()/(float)MB;
if (val>0.0f)
{
atDisplayf("%s = \t%7.3fMB ",concat,val);
}
}
}
}
}
}
void ProcessMemoryTest()
{
static u32 timeToDisplayMemory = 5000;
static u32 delayToDisplayMemory = 60000;
u32 t = fwTimer::GetTimeInMilliseconds();
if(t > timeToDisplayMemory)
{
atDisplayf("Memory Report at time %d seconds",t/1000);
DisplayMemoryUsage();
timeToDisplayMemory = t + delayToDisplayMemory;
}
}
static void DisplayMemoryAvailable()
{
#if __PS3 || RSG_PC
atDisplayf("Memory available GAME_VIRTUAL %dK RESOURCE_VIRTUAL %dK GAME_PHYSICAL %dK RESOURCE_PHYSICAL %dK",
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryAvailable() / 1024,
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryAvailable() / 1024,
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_GAME_PHYSICAL)->GetMemoryAvailable() / 1024,
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_RESOURCE_PHYSICAL)->GetMemoryAvailable() / 1024);
#else
atDisplayf("Memory available GAME_VIRTUAL %" SIZETFMT "uK RESOURCE_VIRTUAL %" SIZETFMT "uK",
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryAvailable() / 1024,
sysMemAllocator::GetCurrent().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryAvailable() / 1024);
#endif
}
//
// name: ProcessLevelLoad
// description: Check for memory leaks while cycling through the levels
void ProcessLevelLoad()
{
static u32 timeOfNextLevelLoad = 5000;
static u32 delayOfNextLevelLoad = 50000;
u32 t = fwTimer::GetTimeInMilliseconds();
#define MAX_LEVELS_CYCLE 2
static u32 levels[MAX_LEVELS_CYCLE] = {1,2};
static u32 levelNum = 0;
if(t > timeOfNextLevelLoad)
{
PF_BEGIN_STARTUPBAR();
levelNum++;
levelNum%=MAX_LEVELS_CYCLE;
atDisplayf("Smoke Test level %s", CScene::GetLevelsData().GetFriendlyName(levels[levelNum]));
DisplayMemoryAvailable();
atDisplayf("Restarting level %s", CScene::GetLevelsData().GetFriendlyName(levels[levelNum]));
CGame::ChangeLevel(levels[levelNum]);
timeOfNextLevelLoad = t + delayOfNextLevelLoad;
}
}
//
// name: ProcessLevelLoad
// description: Check for memory leaks while cycling through the levels
void ProcessLevelReload()
{
static u32 timeOfNextLevelLoad = 5000;
static u32 delayOfNextLevelLoad = 50000;
u32 t = fwTimer::GetTimeInMilliseconds();
if(t > timeOfNextLevelLoad)
{
PF_BEGIN_STARTUPBAR();
atDisplayf("Smoke Test level %s", CScene::GetLevelsData().GetFriendlyName(CGameLogic::GetRequestedLevelIndex()));
DisplayMemoryAvailable();
atDisplayf("Restarting level %s", CScene::GetLevelsData().GetFriendlyName(CGameLogic::GetRequestedLevelIndex()));
CGameSessionStateMachine::SetForceInitLevel();
CGame::StartNewGame(CGameLogic::GetRequestedLevelIndex());
timeOfNextLevelLoad = t + delayOfNextLevelLoad;
}
}
#if __BANK
static char fn[255] = "";
#endif // #if __BANK
//
// name: InitPedPics
// description: take pictures of groups of peds.
void InitPedPics()
{
#if __BANK
// DEBUG_DRAW_ONLY(grcDebugDraw::SetDisplayDebugText(true));
CMiniMap::SetDisplayGameMiniMap(false);
float pos[3];
if(PARAM_pedpiccampos.GetArray(pos, 3))
{
g_pedPicCamStartPos = Vector3(pos[0], pos[1], pos[2]);
}
#endif // #if __BANK
}
//
// name: ProcessPedPics
// description: take pictures of groups of peds.
void ProcessPedPics()
{
#if __BANK
const s32 frameTickerDefault = 5; // frames to wait before picture is taken after being paused ( gets rid of motion blur )
const char pedPicsPath[MAX_PATH] = "X:\\pedpics"; // where to dump pics
const float textSize = 2.5f; // size/scale of text on screen
const Vector2 textPos = Vector2(0.05f,0.05f); // where to print text on screen
const Color32 textColour = Color32(1.0f, 0.0f, 0.0f); // colour of text on screen
const bool textBackground = true; // draw a background behind the text
const u32 delayTillPic = 500; // delay after loading peds till their piccy is taken
const bool createExactGroupSize = false; // something to do with the crowd creation.
const bool wanderAfterCreate = true; // peds wander about after being created.
const u32 t = fwTimer::GetTimeInMilliseconds();
const u32 numPedNames = CPedVariationDebug::GetNumPedNames();
static s32 numCaptured = 0;
static u32 timeLoaded = 0;
static u32 pedPicId = 0;
static bool load = true;
static s32 frameTicker = frameTickerDefault;
static s32 maxCaptures = -1;
static Vector3 startPos = g_pedPicCamStartPos; // where the camera is positioned.
static u32 crowdSize = 3; // crowd size ( fickle )
static float distToCrowd = 6.0f; // distance crowd is created form the camera
static float groupUniformDistribution= 1.5f; // spacing between peds ( -1 for old method - can't understand it though )
static float heading = 0.0f;
static float pitch = 0.0f;
static float roll = 0.0f;
static float fov = 60.0f;
static s32 hour = 12;
static s32 minute = 0;
static s32 second = 0;
if (maxCaptures>=0 && numCaptured>=maxCaptures)
{
return;
}
if (numCaptured==0)
{
// Tweakables
float fVal;
int iVal;
if (CPed::ms_pCreateButton)
{
CPed::ms_pCreateButton->Activate();
return;
}
if (PARAM_pedpicstartidx.Get(iVal))
{
pedPicId = iVal;
}
if (PARAM_pedpicmaxcaptures.Get(iVal))
{
maxCaptures = iVal;
}
if(PARAM_pedpicdisttocrowd.Get(fVal))
{
distToCrowd = fVal;
}
if(PARAM_pedpicgroupuniformdistribution.Get(fVal))
{
groupUniformDistribution = fVal;
}
if(PARAM_pedpiccrowdSize.Get(iVal))
{
crowdSize = iVal;
}
if(PARAM_pedpicheading.Get(fVal))
{
heading = fVal;
}
if(PARAM_pedpicpitch.Get(fVal))
{
pitch = fVal;
}
if(PARAM_pedpicroll.Get(fVal))
{
roll = fVal;
}
if(PARAM_pedpichour.Get(iVal))
{
hour = iVal;
}
if(PARAM_pedpicminute.Get(iVal))
{
minute = iVal;
}
if(PARAM_pedpicsecond.Get(iVal))
{
second = iVal;
}
if(PARAM_pedpicfov.Get(fVal))
{
fov = fVal;
}
}
// Load in peds.
if (load)
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
debugDirector.ActivateFreeCam();
camFrame& freeCamFrame = debugDirector.GetFreeCamFrameNonConst();
freeCamFrame.SetWorldMatrixFromHeadingPitchAndRoll( heading, pitch, roll );
freeCamFrame.SetPosition(startPos);
freeCamFrame.SetFov(fov);
CClock::SetTime(hour, minute, second);
g_weather.ForceTypeClear();
CPedVariationDebug::SetDistToCreateCrowdFromCamera(distToCrowd);
CPedVariationDebug::SetCrowdSize(crowdSize);
CPedVariationDebug::SetCreateExactGroupSize(createExactGroupSize);
CPedVariationDebug::SetWanderAfterCreate(wanderAfterCreate);
CPedVariationDebug::SetCrowdSpawnLocation(freeCamFrame.GetPosition()+(freeCamFrame.GetFront()*distToCrowd));
CPedVariationDebug::SetCrowdUniformDistribution(groupUniformDistribution);
if (pedPicId < numPedNames)
{
pedPicId++;
CPedVariationDebug::SetCrowdPedSelection(0,pedPicId);
if (!strstr(CPedVariationDebug::pedNames[pedPicId],"CS_") &&
!strstr(CPedVariationDebug::pedNames[pedPicId],"cs_") &&
!strstr(CPedVariationDebug::pedNames[pedPicId],"slod_human") &&
!strstr(CPedVariationDebug::pedNames[pedPicId],"slod_small_quadped") &&
!strstr(CPedVariationDebug::pedNames[pedPicId],"slod_large_quadped") &&
!strstr(CPedVariationDebug::pedNames[pedPicId],"singlemeshman"))
{
createCrowdCB();
createCrowdCB(); // deliberately called twice
}
timeLoaded = t;
}
else
{
FinishSmokeTest();
return;
}
load = false;
}
sprintf(fn,"PedPic [%d of %d] %s",pedPicId,numPedNames,CPedVariationDebug::pedNames[pedPicId]);
if(!load && t > timeLoaded + delayTillPic)
{
fwTimer::StartUserPause( );
frameTicker--;
if (frameTicker<=0)
{
atDisplayf("PED ON DISPLAY IS %s",fn);
// Take piccy
rage::grmSetup* pSetup = CSystem::GetRageSetup();
if (pSetup)
{
char path[MAX_PATH],fullpath[MAX_PATH];
const fiDevice* pDevice = fiDevice::GetDevice( path, false );
Assertf( pDevice, "Failed to get device" );
formatf( path, MAX_PATH, pedPicsPath );
pDevice->MakeDirectory( path );
sprintf(fullpath,"%s\\%s",path,fn);
#if __PS3 && HACK_GTA4
grcImage::SetUseGammaCorrection(false);
#endif
pSetup->SetScreenShotNamingConvention( grcSetup::OVERWRITE_SCREENSHOT );
pSetup->TakeScreenShot( fullpath, true );
numCaptured++;
// resume the game - no pause
fwTimer::EndUserPause( );
}
// Destroy peds we created
CPedPopulation::RemoveAllRandomPeds();
fwPool<CPed> *pedPool = CPed::GetPool();
for(s32 i = 0; i < pedPool->GetSize(); i++)
{
CPed *ped = pedPool->GetSlot(i);
if(ped && !ped->IsPlayer())
{
CPedFactory::GetFactory()->DestroyPed(ped);
ped = NULL;
}
}
// schedule next pic.
load = true;
frameTicker = frameTickerDefault;
}
}
DEBUG_DRAW_ONLY(grcDebugDraw::Text(textPos,textColour, fn, textBackground,textSize,textSize));
#endif
}
//
// name: RemoveObjectAndDependencies
// description: Remove a streamed object and all of its dependencies
// parameters: index is the streaming index
void RemoveObjectAndDependencies(strIndex index)
{
strStreamingModule* pModule = strStreamingEngine::GetInfo().GetModule(index);
strLocalIndex objIndex = pModule->GetObjectIndex(index);
// if we can delete this (flags not set, reference count is zero)
if(!(strStreamingEngine::GetInfo().GetObjectFlags(index) & STR_DONTDELETE_MASK) &&
pModule->GetNumRefs(objIndex) == 0)
{
pModule->StreamingRemove(objIndex);
}
strIndex deps[STREAMING_MAX_DEPENDENCIES];
s32 numDeps = pModule->GetDependencies(objIndex, &deps[0], STREAMING_MAX_DEPENDENCIES);
while(numDeps--)
{
RemoveObjectAndDependencies(deps[numDeps]);
}
}
//
// name: LoadAllPedModelInfos
// description: Load all peds and create an instance of each
template<class T> void LoadAllFromStaticStore(fwArchetypeDynamicFactory<T>& store, void (*InstanceFn)(u32 index))
{
// clear out streaming request list so there are no entries to pollute the results
CStreaming::LoadAllRequestedObjects();
atArray<T*> typeArray;
store.GatherPtrs(typeArray);
for(s32 i=0; i<typeArray.GetCount(); i++)
{
//T& entry = store.GetEntry(i);
T& entry = *typeArray[i];
fwModelId modelId = CModelInfo::GetModelIdFromName(entry.GetModelName());
Assert(modelId.IsValid());
if(!strcmp("player", entry.GetModelName()))
continue;
atDisplayf("Loading %s", entry.GetModelName());
if(!modelId.IsValid())
{
atDisplayf("%s is not in any img file", entry.GetModelName());
continue;
}
// If ped is already in memory don't stream it
bool bInMemory = CModelInfo::HaveAssetsLoaded(modelId);
if(!bInMemory)
{
// load and remove object once to check if memory leak occurs with every load of the object
CModelInfo::RequestAssets(modelId, STRFLAG_FORCE_LOAD);
// remove any requests in the streaming list
CStreaming::LoadAllRequestedObjects();
// instance object
InstanceFn(modelId.GetModelIndex());
// ensure object and all its dependencies aren't in memory
strLocalIndex transientLocalIndex = CModelInfo::LookupLocalIndex(modelId);
RemoveObjectAndDependencies(strStreamingEngine::GetInfo().GetModuleMgr().GetModule(CModelInfo::GetStreamingModuleId())->GetStreamingIndex(transientLocalIndex));
}
// store memory before loading
size_t gameVirtual = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryUsed();
size_t rscVirtual = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryUsed();
// stream ped model
if(!bInMemory)
{
// request and load object
CModelInfo::RequestAssets(modelId, STRFLAG_FORCE_LOAD);
CStreaming::LoadAllRequestedObjects();
}
// store memory before instancing
size_t gameVirtual1 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryUsed();
size_t rscVirtual1 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryUsed();
// instance object
InstanceFn(modelId.GetModelIndex());
// compare memory after deleting instance
size_t gameVirtual2 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryUsed();//rage/jimmy/dev/rage/base/src/paging/streamer.cpp
size_t rscVirtual2 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryUsed();
if(gameVirtual1 != gameVirtual2 || rscVirtual1 != rscVirtual2)
atDisplayf("Memory leak (Game Virtual %" SIZETFMT "d) (Resource Virtual %" SIZETFMT "d) when instancing %s", gameVirtual2 - gameVirtual1, rscVirtual2 - rscVirtual1, entry.GetModelName());
// remove ped model
// If ped was already in memory don't remove it
if(!bInMemory){
strLocalIndex transientLocalIndex = CModelInfo::LookupLocalIndex(modelId);
RemoveObjectAndDependencies(strStreamingEngine::GetInfo().GetModuleMgr().GetModule(CModelInfo::GetStreamingModuleId())->GetStreamingIndex(transientLocalIndex));
}
// compare memory after deleting model
gameVirtual2 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL)->GetMemoryUsed();
rscVirtual2 = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_RESOURCE_VIRTUAL)->GetMemoryUsed();
if(gameVirtual != gameVirtual2 || rscVirtual != rscVirtual2)
atDisplayf("Memory leak (Game Virtual %" SIZETFMT "d) (Resource Virtual %" SIZETFMT "d) when loading %s", gameVirtual2 - gameVirtual, rscVirtual2 - rscVirtual, entry.GetModelName());
}
// Exit
FinishSmokeTest();
}
static void InstancePed(u32 index)
{
Matrix34 identity(Matrix34::IdentityType);
// instance and delete ped
fwModelId modelId((strLocalIndex(index)));
CPed* pPed = CPedFactory::GetFactory()->CreatePed(CControlledByInfo(false, false), modelId, &identity, false, true, false);
CPedFactory::GetFactory()->DestroyPed(pPed);
}
static void InstanceVehicle(u32 index)
{
Matrix34 identity(Matrix34::IdentityType);
// instance and delete vehicle
fwModelId modelId((strLocalIndex(index)));
CVehicle* pVehicle = CVehicleFactory::GetFactory()->Create(modelId, ENTITY_OWNEDBY_OTHER, POPTYPE_RANDOM_AMBIENT, &identity);
CVehicleFactory::GetFactory()->Destroy(pVehicle);
}
//
// name: InitLoadVehicles
// description: Check for problems while loading and instancing all the peds
void InitLoadPeds()
{
LoadAllFromStaticStore<CPedModelInfo>(CModelInfo::GetPedModelInfoStore(), &InstancePed);
}
//
// name: InitLoadVehicles
// description: Check for problems while loading and instancing all the vehicles
void InitLoadVehicles()
{
LoadAllFromStaticStore<CVehicleModelInfo>(CModelInfo::GetVehicleModelInfoStore(), &InstanceVehicle);
}
//
// name: InitWanderingTest
// description: Check for crashes while wandering about the world
void InitWanderingTest()
{
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->GetPedIntelligence()->ClearTasks();
CTask * pTaskWander = pPlayer->ComputeWanderTask(*pPlayer);
pPlayer->GetPedIntelligence()->AddTaskDefault(pTaskWander);
CPlayerInfo::ms_bDebugPlayerInvincible = true;
CWanted * pWanted = pPlayer->GetPlayerWanted();
int wantedLevel = g_defaultWantedLevel;
PARAM_smoketestwantedlevel.Get(wantedLevel);
pWanted->SetWantedLevelNoDrop(VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition()), wantedLevel, 0, WL_FROM_TEST);
}
}
void ProcessWanderingTest()
{
int interval = (60*5) * 1000; // 5 mins in ms
ProcessWarping(interval);
}
//
// name: InitWarpingTest
// description: Check for crashes while warping the player about the world
void InitWarpingTest()
{
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->GetPedIntelligence()->ClearTasks();
CTask * pTaskWander = pPlayer->ComputeWanderTask(*pPlayer);
pPlayer->GetPedIntelligence()->AddTaskDefault(pTaskWander);
CPlayerInfo::ms_bDebugPlayerInvincible = true;
CWanted * pWanted = pPlayer->GetPlayerWanted();
int wantedLevel = g_defaultWantedLevel;
PARAM_smoketestwantedlevel.Get(wantedLevel);
pWanted->SetWantedLevel(VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition()), wantedLevel, 0, WL_FROM_TEST);
}
}
void ProcessWarping(const int iWarpPeriod)
{
static int iTimer=iWarpPeriod;
CPed * pPlayer = FindPlayerPed();
if(!pPlayer)
{
return;
}
if(CWarpManager::IsActive())
{
iTimer=iWarpPeriod;
return;
}
iTimer -= fwTimer::GetTimeStepInMilliseconds();
if(iTimer <= 0)
{
Vector3 vPos;
bool bFoundPosition = false;
while(!bFoundPosition)
{
vPos.x = fwRandom::GetRandomNumberInRange(-3870.0f, 4064.0f);
vPos.y = fwRandom::GetRandomNumberInRange(-5658.0f, 7904.0f);
vPos.z = 1000.0f;
float fGround = WorldProbe::FindGroundZFor3DCoord(TOP_SURFACE, vPos.x, vPos.y, vPos.z, &bFoundPosition);
if(bFoundPosition)
{
vPos.z = fGround;
}
else
{
strStreamingEngine::GetLoader().LoadRequestedObjects();
}
}
pPlayer->Teleport(vPos, pPlayer->GetCurrentHeading());
pPlayer->GetPedIntelligence()->ClearTasks();
CTask * pTaskWander = pPlayer->ComputeWanderTask(*pPlayer);
pPlayer->GetPedIntelligence()->AddTaskDefault(pTaskWander);
CWanted * pWanted = pPlayer->GetPlayerWanted();
int wantedLevel = g_defaultWantedLevel;
PARAM_smoketestwantedlevel.Get(wantedLevel);
pWanted->SetWantedLevel(VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition()), wantedLevel, 0, WL_FROM_TEST);
iTimer=iWarpPeriod;
}
}
void ProcessWarpingTest()
{
int interval = 60;
PARAM_warpingInterval.Get(interval);
ProcessWarping(interval * 1000);
}
//
// name: InitExplosionTest
// description: Check for crashes while wandering around and having random explosions occur all over the place
void InitExplosionTest()
{
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->GetPedIntelligence()->ClearTasks();
CTask * pTaskWander = pPlayer->ComputeWanderTask(*pPlayer);
pPlayer->GetPedIntelligence()->AddTaskDefault(pTaskWander);
CPlayerInfo::ms_bDebugPlayerInvincible = true;
BANK_ONLY(UpdateAvailableCarsCB();)
}
}
void ProcessExplosionTest()
{
static u32 timeOfNextExplosion = 1000;
if(fwTimer::GetTimeInMilliseconds() > timeOfNextExplosion)
{
Vector3 pos = VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()) + Vector3((fwRandom::GetRandomTrueFalse() ? -1.f : 1.f) * fwRandom::GetRandomNumberInRange(5.f, 15.f),
(fwRandom::GetRandomTrueFalse() ? -1.f : 1.f) * fwRandom::GetRandomNumberInRange(5.f, 15.f), 0.f);
CExplosionManager::CExplosionArgs explosionArgs(EXP_TAG_HI_OCTANE, pos);
explosionArgs.m_sizeScale = 50.f;
explosionArgs.m_fCamShake = 0.0f;
CExplosionManager::AddExplosion(explosionArgs);
timeOfNextExplosion = fwTimer::GetTimeInMilliseconds() + (u32)fwRandom::GetRandomNumberInRange(200, 1000);
}
ProcessWarping(60*1000*10); // Only warp every 10 mins
#if __BANK
static u32 timeOfNextCar = 1000;
if(fwTimer::GetTimeInMilliseconds() > timeOfNextCar)
{
CreateNextCar(true);
timeOfNextCar = fwTimer::GetTimeInMilliseconds() + (u32)fwRandom::GetRandomNumberInRange(10000, 20000);
}
#endif
}
void ProcessCutsceneTest()
{
#if __BANK
CutSceneManager::GetInstance()->CutsceneSmokeTest();
#endif // __BANK
}
//
// name: ProcessRestartTest
// description: Check for memory leaks while restarting the level
void ProcessRestartTest()
{
static sysTimer timer;
if(timer.GetTime() > 60.0f)
{
timer.Reset();
DisplayMemoryAvailable();
const char *pLevelName = CScene::GetLevelsData().GetFriendlyName(CGameLogic::GetCurrentLevelIndex());
atDisplayf("Restarting level %s", pLevelName);
CGame::StartNewGame(CGameLogic::GetCurrentLevelIndex());
}
DEBUG_DRAW_ONLY(grcDebugDraw::AddDebugOutput("Restarting in %f secs", 60.0f - timer.GetTime()));
}
//
// name: InitShutdownTest
// description: Test if shutdown crashes or asserts
void InitShutdownTest()
{
FinishSmokeTest();
}
//
// name: InitBuildState
// description: Record the overall state of the build.
void InitBuildState()
{
}
void ProcessBuildState()
{
static sysTimer timer;
static float timeOfBuildStateCapture = 60.0f;
if(timer.GetTime() > timeOfBuildStateCapture && timeOfBuildStateCapture>0.0f)
{
timeOfBuildStateCapture = -1.0f; // invalidate
sysMemAllocator* pAllocator = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL);
if (pAllocator)
{
// DW - discrepency has been seen between these calls where Used or Available mem will change ~16K - this just leads to confusion.
// simple solution :- read the values and pre-cache... although it seems to suggest something cookie is going on with allocator - defrag?, another thread?, atDisplayf allocs mem?
size_t available = CStreamingDebug::GetMainMemoryAvailable() / 1024;
size_t used = CStreamingDebug::GetMainMemoryUsed() / 1024;
atDisplayf("BuildState:GH Total=%" SIZETFMT "u",(available + used));
atDisplayf("BuildState:GH Used=%" SIZETFMT "u",used);
atDisplayf("BuildState:GH Left=%" SIZETFMT "u",available);
}
atDisplayf("BuildState:Default=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_DEFAULT)/1024);
atDisplayf("BuildState:Animation=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_ANIMATION)/1024);
atDisplayf("BuildState:Streaming=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_STREAMING)/1024);
atDisplayf("BuildState:World=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_WORLD)/1024);
atDisplayf("BuildState:Gameplay=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_GAMEPLAY)/1024);
atDisplayf("BuildState:FX=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_FX)/1024);
atDisplayf("BuildState:Rendering=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_RENDER)/1024);
atDisplayf("BuildState:Physics=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_PHYSICS)/1024);
atDisplayf("BuildState:Audio=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_AUDIO)/1024);
atDisplayf("BuildState:Network=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_NETWORK)/1024);
atDisplayf("BuildState:System=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_SYSTEM)/1024);
atDisplayf("BuildState:Scaleform=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_SCALEFORM)/1024);
atDisplayf("BuildState:Script=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_SCRIPT)/1024);
atDisplayf("BuildState:Resource=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_RESOURCE)/1024);
atDisplayf("BuildState:Debug=%" SIZETFMT "u",CStreamingDebug::GetMainMemoryUsed(MEMBUCKET_DEBUG)/1024);
atDisplayf("BuildState:Bounds=%d",0);
atDisplayf("BuildState:Pools=%d",0);
atDisplayf("BuildState:AI=%d",0);
atDisplayf("BuildState:Process=%d",0);
atDisplayf("BuildState:Pathfinding=%d",0);
const char *platform = "PC";
#if __XENON
platform = "Xbox360";
#elif __PS3
platform = "PS3";
#endif
// Create the path
char outputPath[RAGE_MAX_PATH];
sprintf(outputPath, "X:/gta5/docs/Code/BuildState/%s/%s/", RSG_CONFIGURATION, platform);
#if RAGE_TRACKING
if (diagTracker::GetCurrent())
{
char memVisPath[RAGE_MAX_PATH];
sprintf(memVisPath, "%smemvisualize/dummy.txt", outputPath);
atDisplayf("Dumping memvis files to %s", memVisPath);
diagTracker::GetCurrent()->FullReport(memVisPath);
atDisplayf("Dumping memvis completed");
}
else
{
Errorf("diagTracker::GetCurrent is not set");
}
#endif // RAGE_TRACKING
#if __BANK
// Save out SceneCosts.txt
char outputFile[RAGE_MAX_PATH];
sprintf(outputFile, "%s%s", outputPath, "SceneCosts.txt");
fiStream *pLogFileHandle = ASSET.Create(outputFile, ""); // Default location
if( pLogFileHandle )
{
ResourceMemoryUseDump::BuildSceneCostStreamingIndices();
ResourceMemoryUseDump::DumpSceneCostDetails(pLogFileHandle);
fflush(pLogFileHandle);
pLogFileHandle->Close();
}
else
{
Errorf("Could not create output file %s for writing.", outputFile);
}
// Save out ModuleInfo.txt
sprintf(s_DumpOutputFile, "%sModuleInfo.txt", outputPath); // Default location
CStreamingDebug::DumpModuleInfoAllObjects();
#endif
DisplaySmokeTestFinished();
}
}
//
// name: RageBuilderUnitTest
void InitRageBuilderUnitTest()
{
}
void ProcessRageBuilderUnitTest()
{
static sysTimer timer;
static float timeOfRageBuilderUnitTestCapture = 60.0f;
if(timer.GetTime() > timeOfRageBuilderUnitTestCapture && timeOfRageBuilderUnitTestCapture>0.0f)
{
timeOfRageBuilderUnitTestCapture = -1.0f; // invalidate
DisplaySmokeTestFinished();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// Codebuilder Capture of stats
// A smoketest that is designated to run after successful codebuilder builds.
// - Maintained by runtime team.
// - Writes capture to an external file (* NOT the database directly! *)
// - Analysis of database is performed by external script.
////////////////////////////////////////////////////////////////////////////////////////////////////
static bool s_bCodebuilderStatsEnabled = false;
static bool s_bCodebuilderStatsEnded = false;
// Control Logic
bool SmokeTestStarted()
{
return s_bCodebuilderStatsEnabled;
}
bool SmokeTestEnded()
{
return s_bCodebuilderStatsEnded;
}
void SmokeTestEnd()
{
s_bCodebuilderStatsEnabled = false;
}
void InitCodebuilderStats()
{
s_bCodebuilderStatsEnabled = true;
}
void ProcessCodebuilderStats()
{
if (!s_bCodebuilderStatsEnabled && !s_bCodebuilderStatsEnded)
{
#if ENABLE_STATS_CAPTURE
MetricsCapture::SmokeTestSaveResults("stats");
#endif // ENABLE_STATS_CAPTURE
s_bCodebuilderStatsEnded = true;
FinishSmokeTest();
}
}
// Capture the state of the game
// - this is an example
void CaptureCodebuilderStatsState()
{
char filename[255] = "stats.xml";
fiStream* stream = filename ? fiStream::Create(filename, fiDeviceLocal::GetInstance()) : NULL;
if (!stream)
{
Errorf("Could not create '%s'", filename);
return;
}
fprintf(stream, "<?xml version='1.0' encoding='utf-8'?>\n");
// Note we MUST tag the time, date on - since every capture needs to be different - otherwise we revert unchanged files when we submit them.
char date_time[64];
sprintf(date_time, "%d %d %d %d:%d:%d", CClock::GetYear(),CClock::GetMonth(), CClock::GetHour(), CClock::GetDay(), CClock::GetMinute(), CClock::GetSecond());
fprintf(stream, "<STATS capture_time='%s'>\n",date_time);
{
sysMemAllocator* pAllocator = sysMemAllocator::GetMaster().GetAllocator(MEMTYPE_GAME_VIRTUAL);
if (pAllocator)
{
// good practice is to grab the state in one go without making other calls since these may have influence on memory allocated etc.
size_t available = pAllocator->GetMemoryAvailable() / 1024;
size_t used = pAllocator->GetMemoryUsed() / 1024;
size_t total = (available + used);
fprintf(stream, "<MEMORY>\n");
{
fprintf(stream, "<MEMTYPE_GAME_VIRTUAL>\n");
{
fprintf(stream, "<TOTAL>%d</TOTAL>\n",total);
fprintf(stream, "<USED>%d</USED>\n",used);
fprintf(stream, "<AVAILABLE>%d</AVAILABLE>\n",available);
fprintf(stream, "<TEST>%d</TEST>\n",available);
}
fprintf(stream, "</MEMTYPE_GAME_VIRTUAL>\n");
}
fprintf(stream, "</MEMORY>\n");
}
}
fprintf(stream, "</STATS>\n");
fflush(stream);
}
//====================================================================================
// STREAMING MEMORY STATS
void InitJunctionMemStats()
{
CSectorTools::SetEnabled(false); // off by default - wait till we are ready to capture.
}
void ProcessJunctionMemStats()
{
static sysTimer timer;
static float timeOfJunctionMemStatsCapture = 60.0f;
if(timer.GetTime() > timeOfJunctionMemStatsCapture && timeOfJunctionMemStatsCapture>0.0f)
{
timeOfJunctionMemStatsCapture = -1.0f; // invalidate
CSectorTools::SetEnabled(true); // now it is enabled.
}
if(CSectorTools::IsFinished())
{
DisplaySmokeTestFinished();
}
}
//====================================================================================
// OBJECT PROFILER
#include "ObjectProfiler.h"
void InitObjectProfiler()
{
#if __BANK
CObjectProfiler::Init();
#endif //__BANK
}
void ProcessObjectProfiler()
{
#if __BANK
if( CObjectProfiler::Process() )
#endif //__BANK
{
DisplaySmokeTestFinished();
}
}
}; // namespace
#endif // #if !__FINAL