Not sure anyone cares about this but I've updated my timerbar code.
The timerbar code allows you to time parts of the code and see a representation of the times on screen.
If anyone is thinking about optimisation I strongly suggest you use this tool.
Currently it is only supported by DX5 but the main code is totally generic and uses a callback function to
render the bars. So Phreak could put together a OGL version in about 2 mins I reckon.
The code currently commited has a bug that messes up nested checks, I have fixed that and also added push and pop functions for ease of use when nesting checks.
Take it over leave it.
timerbar.h
/*
* Code created by Random Tiger for a Freespace 2 source code project
*
* You may not sell or otherwise commercially exploit the source or things you
* created based on the source.
*
*/
#ifndef _TIMERBAR_HEADER_
#define _TIMERBAR_HEADER_
const int MAX_NUM_TIMERBARS = 20;
// These functions should never be used directly, always use macros below
void timerbar_start_frame();
void timerbar_end_frame();
void timerbar_set_draw_func(void (*new_draw_func_ptr)(int colour, float x, float y, float w, float h));
void timerbar_push(int value);
void timerbar_pop();
// This function shouldnt not be used any more or it will break push and pop calls
void timerbar_switch_type(int num);
// Only show timer bars if in debug mode in windows unless TIMERBAR_ON compile flag is set
#if (!defined(NDEBUG) && defined(_WIN32)) || defined(TIMERBAR_ON)
#define TIMERBAR_SET_DRAW_FUNC(f) timerbar_set_draw_func(f);
#define TIMERBAR_START_FRAME() timerbar_start_frame();
#define TIMERBAR_END_FRAME() timerbar_end_frame();
#define TIMERBAR_SWITCH_TYPE(n) timerbar_switch_type(n);
#define TIMERBAR_PUSH(v) timerbar_push(v);
#define TIMERBAR_POP() timerbar_pop();
#else
#define TIMERBAR_SET_DRAW_FUNC(f) ;
#define TIMERBAR_START_FRAME() ;
#define TIMERBAR_END_FRAME() ;
#define TIMERBAR_SWITCH_TYPE(n) ;
#define TIMERBAR_PUSH(v) ;
#define TIMERBAR_POP() ;
#endif
#endif
timerbar.cpp
/*
* Code created by Random Tiger for a Freespace 2 source code project
*
* You may not sell or otherwise commercially exploit the source or things you
* created based on the source.
*
*/
/*
* This module is intended as a debug tool to measure the speed of blocks of code and display
* that information as coloured bars across the top of the screen.
*
* This allows interactive measuring of components of the code, very useful for optimisztion.
*/
#ifdef _WIN32
#include
#include
#include "timerbar.h"
// Internal structure for handling frame data
typedef struct
{
LARGE_INTEGER start_value;
LARGE_INTEGER total_value;
LARGE_INTEGER average;
LARGE_INTEGER frame_total;
} timerbar_profile;
timerbar_profile profiles[MAX_NUM_TIMERBARS];
int timerbar_current_profile = 0;
LARGE_INTEGER timerbar_ultimate_start_value;
LARGE_INTEGER timerbar_last_start_value;
// Data needed for push and pop functionality
const MAX_TB_STACK_SIZE = 100;
int timerbar_stack[MAX_TB_STACK_SIZE];
int timerbar_current_stack_layer = 0;
/*
*
*
*
*/
void timerbar_push(int value)
{
Assert((timerbar_current_stack_layer + 1) < MAX_TB_STACK_SIZE);
timerbar_stack[timerbar_current_stack_layer] = timerbar_current_profile;
timerbar_current_stack_layer++;
timerbar_switch_type(value);
}
/*
*
*
*
*/
void timerbar_pop()
{
timerbar_current_stack_layer--;
Assert(timerbar_current_stack_layer >= 0);
timerbar_switch_type(timerbar_stack[timerbar_current_stack_layer]);
}
// This pointer holds the draw function to use or NULL
void (*draw_func_ptr)(int colour, float x, float y, float w, float h) = NULL;
void timerbar_start_frame()
{
timerbar_current_stack_layer = 0;
timerbar_current_profile = 0;
if(QueryPerformanceCounter(&timerbar_ultimate_start_value) == FALSE)
{
// DBUGFILE_OUTPUT_0("QueryPerformanceCounter not supported by hardware");
draw_func_ptr = NULL;
}
timerbar_last_start_value = timerbar_ultimate_start_value;
}
// Constants need for timerbar_conv_and_draw calculations
const int WIDTH = 480;
const float WIDTHF = ((float) WIDTH) * 1.01f;
/**
* Internal conversion function to convert draw data into bars for the screen
*
* @param int colour - colour index (>=0)
* @param int xpos - x position to start bar on
* @param int xwidth - width of bar
* @param int yrow - Index of row bar belongs to
*/
void timerbar_conv_and_draw(int colour, int xpos, int xwidth, int yrow)
{
float fxpos = (float) xpos;
float fxwidth = (float) xwidth;
draw_func_ptr(colour,
fxpos / WIDTHF,
yrow * 0.01f,
fxwidth / WIDTHF,
0.005f);
}
void timerbar_end_frame()
{
// Now we want to draw the bars
if(draw_func_ptr == NULL)
{
// we have not been given a draw function so we are going to have to quit
return;
}
timerbar_switch_type(-1);
int last_xpos = 0;
int y_pos = 0;
for(int i = 0; i < MAX_NUM_TIMERBARS; i++)
{
// Nothing to render this frame
if(profiles[i].frame_total.QuadPart == 0)
{
continue;
}
int xsize = (int) profiles[i].frame_total.QuadPart / 90;
// break condition in else
while(1)
{
// if bar runs over
if(last_xpos + xsize > WIDTH)
{
int rem_len = WIDTH - last_xpos;
// Draw from current position to the end of the bar
timerbar_conv_and_draw(i, last_xpos, rem_len, y_pos);
xsize -= rem_len;
last_xpos = 0;
y_pos++;
}
else
{
// Draw whats left and break for the next bar
timerbar_conv_and_draw(i,last_xpos, xsize, y_pos);
last_xpos += xsize;
break;
}
}
// reset for next frame
profiles[i].frame_total.QuadPart = 0;
}
}
void timerbar_switch_type(int num)
{
if(num >= MAX_NUM_TIMERBARS)
{
return;
}
// Calculate old profile's total
LARGE_INTEGER now;
if(QueryPerformanceCounter(&now) == FALSE)
{
// DBUGFILE_OUTPUT_0("QueryPerformanceCounter not supported by hardware");
}
profiles[timerbar_current_profile].frame_total.QuadPart +=
(now.QuadPart - timerbar_last_start_value.QuadPart);
if(num != -1)
{
// Switch to new profile
timerbar_current_profile = num;
}
// Update time to count from
if(QueryPerformanceCounter(&timerbar_last_start_value) == FALSE)
{
// DBUGFILE_OUTPUT_0("QueryPerformanceCounter not supported by hardware");
}
}
/**
* @param void (*new_draw_func_ptr)(int colour, float x, float y, float w, float h) - pointer to draw function
*
* Sets the draw function used to output the timer data, designed to be generic allowing any API
* to take advantage of this module. Set to NULL to disable drawing.
*
* By default the draw function is set to NULL
*/
void timerbar_set_draw_func(void (*new_draw_func_ptr)(int colour, float x, float y, float w, float h))
{
draw_func_ptr = new_draw_func_ptr;
}
#endif