1
0
forked from 0ad/0ad

new cumulative timer as requested for entity slowdown investigation.

use SUM_TIMER; see comments in source+header.

(i've tested this on my laptop, but only get as far as the main menu.
hopefully this won't break anything :S)

This was SVN commit r2893.
This commit is contained in:
janwas 2005-10-10 17:33:34 +00:00
parent 6efb1e1c00
commit f2ccab089c
3 changed files with 178 additions and 16 deletions

View File

@ -234,3 +234,77 @@ void calc_fps()
// C float -> int rounds down; we want to round up to
// hit vsync-locked framerates exactly.
}
//-----------------------------------------------------------------------------
// cumulative timer API, useful for profiling.
// this supplements in-game profiling by providing low-overhead,
// high resolution time accounting.
struct TimerClient
{
double sum; // total bill [s]
// only store a pointer for efficiency.
const char* name;
};
// use static storage to ensure clients can be added at any time,
// especially before the heap has been initialized.
// that means there's a fixed limit, but that's not a problem since
// these timers are added manually for performance measuring.
static uint num_clients;
static const uint MAX_CLIENTS = 16;
static TimerClient clients[MAX_CLIENTS];
// allocate a new TimerClient whose total (added to by timer_bill_client)
// will be displayed by timer_display_client_totals.
// notes:
// - uses static data; there is a fixed limit. rationale: see clients[].
// - may be called at any time;
// - free() is not needed nor possible.
// - name must remain valid until exit; passing a string literal is safest.
TimerClient* timer_add_client(const char* name)
{
if(num_clients == MAX_CLIENTS)
{
debug_warn("timer: increase MAX_CLIENTS");
return 0;
}
TimerClient* tc = &clients[num_clients++];
tc->name = name;
// note: tc->sum is already 0 (static data)
return tc;
}
// add <dt> [s] to the client's total.
void timer_bill_client(TimerClient* tc, double dt)
{
tc->sum += dt;
}
// display all clients' totals; does not reset them.
// typically called at exit.
void timer_display_client_totals()
{
debug_printf("TIMER TOTALS (%d clients)\n", num_clients);
debug_printf("-----------------------------------------------------\n");
for(uint i = 0; i < num_clients; i++)
{
const double sum = clients[i].sum;
// determine scale factor for pretty display
double scale = 1e6;
const char* unit = "us";
if(sum > 1.0)
scale = 1, unit = "s";
else if(sum > 1e-3)
scale = 1e3, unit = "ms";
debug_printf(" %s: %g %s\n", clients[i].name, sum*scale, unit);
}
debug_printf("-----------------------------------------------------\n");
}

View File

@ -40,6 +40,29 @@ extern int fps;
extern void calc_fps(void);
//
// cumulative timer API
//
struct TimerClient; // opaque
// allocate a new TimerClient whose total (added to by timer_bill_client)
// will be displayed by timer_display_client_totals.
// notes:
// - uses static data; there is a fixed limit. rationale: see clients[].
// - may be called at any time;
// - free() is not needed nor possible.
// - name must remain valid until exit; passing a string literal is safest.
extern TimerClient* timer_add_client(const char* name);
// add <dt> [s] to the client's total.
extern void timer_bill_client(TimerClient* tc, double dt);
// display all clients' totals; does not reset them.
// typically called at exit.
extern void timer_display_client_totals();
#ifdef __cplusplus
}
#endif
@ -49,39 +72,85 @@ extern void calc_fps(void);
class ScopedTimer
{
double t0;
const std::string name;
const char* name;
public:
ScopedTimer(const char* _name)
: name(_name)
{
t0 = get_time();
name = _name;
}
~ScopedTimer()
{
double t1 = get_time();
double dt = t1-t0;
// assume microseconds
// determine scale factor for pretty display
double scale = 1e6;
char unit = 'u';
const char* unit = "us";
if(dt > 1.0)
scale = 1, unit = ' ';
// milli
scale = 1, unit = "s";
else if(dt > 1e-3)
scale = 1e3, unit = 'm';
scale = 1e3, unit = "ms";
debug_printf("TIMER %s: %g %cs\n", name.c_str(), dt*scale, unit);
debug_printf("TIMER %s: %g %s\n", name, dt*scale, unit);
}
// no copy ctor, since some members are const
// disallow copying (makes no sense)
private:
ScopedTimer& operator=(const ScopedTimer&);
};
#define TIMER(name) ScopedTimer st##name##instance(#name)
#define TIMER(name) ScopedTimer ST##name(#name)
// Cheat a bit to make things slightly easier on the user
#define TIMER_START(name) { ScopedTimer __timer( name )
#define TIMER_END(name) }
/*
Example usage:
static TimerClient* client = timer_add_client("description");
void func()
{
SUM_TIMER(client);
(code to be measured)
}
[at exit]
timer_display_client_totals();
*/
class ScopedSumTimer
{
double t0;
TimerClient* tc;
public:
ScopedSumTimer(TimerClient* tc_)
{
t0 = get_time();
tc = tc_;
}
~ScopedSumTimer()
{
double t1 = get_time();
double dt = t1-t0;
timer_bill_client(tc, dt);
}
// disallow copying (makes no sense)
private:
ScopedSumTimer& operator=(const ScopedSumTimer&);
};
// bills to <client> the time elapsed between execution reaching the
// point of macro invocation and end of the current basic block.
// total times for all clients are displayed by timer_display_client_totals.
#define SUM_TIMER(client) ScopedSumTimer UID__(client)
#endif // #ifndef TIMER_H

View File

@ -771,6 +771,8 @@ void Shutdown()
h_mgr_shutdown();
mem_shutdown();
timer_display_client_totals();
debug_shutdown();
delete &g_Logger;
@ -793,6 +795,9 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
debug_set_thread_name("main");
// If you ever want to catch a particular allocation:
//_CrtSetBreakAlloc(187);
// Query CPU capabilities, possibly set some CPU-dependent flags
cpu_init();
@ -862,6 +867,9 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
uint quality = SANE_TEX_QUALITY_DEFAULT; // TODO: set value from config file
SetTextureQuality(quality);
// required by ogl_tex to detect broken gfx card/driver combos
get_gfx_info();
}
oglCheck();
@ -880,7 +888,7 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
}
// (must come after SetVideoMode, since it calls oglInit)
const char* missing = oglHaveExtensions(0, "GL_ARB_multitexture", "GL_ARB_texture_env_combine", "GL_ARB_texture_env_dot3", "GL_ARB_texture_env_crossbar", 0);
const char* missing = oglHaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", "GL_ARB_texture_env_combine", "GL_ARB_texture_env_dot3", "GL_ARB_texture_env_crossbar", 0);
if(missing)
{
wchar_t buf[500];
@ -906,20 +914,26 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
oglCheck();
InitRenderer();
TIMER(init_after_InitRenderer);
{
TIMER(Init_entitiessection);
// This needs to be done after the renderer has loaded all its actors...
new CBaseEntityCollection;
// CEntityManager is managed by CWorld
//new CEntityManager;
new CPathfindEngine;
new CSelectedEntities;
new CMouseoverEntities;
}
{
TIMER(Init_miscgamesection);
new CPathfindEngine;
new CBuildingPlacer;
new CSessionManager;
new CGameAttributes;
}
{
TIMER(Init_misc);
// Register a few Game/Network JS globals
g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes.GetScript()));
@ -932,13 +946,18 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
InitInput();
oglCheck();
}
#ifndef NO_GUI
{
TIMER(Init_guiload);
g_GUI.SendEventToAll("load");
}
#endif
if (setup_gfx)
{
TIMER(Init_renderblank);
MICROLOG(L"render blank");
// render everything to a blank frame to force renderer to load everything
RenderNoCull();