una-i
28/06/2006, 07:02
Bueno cono voy corriendo no voy a dar muchas explicaciones, me he hecho esto para auydarme a profilear el psx4all...
Consiste en código y unas macros para que poner y calcular tiempos sea mas fácil...
El truco esta en que usa constructores y destructores de c++ para que no haya que emarcar el final de la "cuenta".
Acontinuación el codigo a meter en "profiller.h"
#ifndef PROFILLER_H
#define PROFILLER_H
///////////////////////////////////////////////////////////////////////////////
// Profilling helper functions, minimal libs are needed for timer.
#include "minimal.h"
///////////////////////////////////////////////////////////////////////////////
// Minimal extensions used for better accuracy and speed.
/*
unsigned long gp2x_timer_raw(void)
{
return gp2x_memregl[0x0A00>>2];
}
unsigned long gp2x_timer_raw_to_ticks(unsigned long ticks)
{
return ticks/gp2x_ticks_per_second;
}
unsigned long gp2x_timer_raw_second()
{
return 7372800;
}
*/
///////////////////////////////////////////////////////////////////////////////
// Profiler Interface/Macro Definitions
///////////////////////////////////////////////////////////////////////////////
#ifndef ENABLE_PROFILLER
#define PROFILE_NAMED_FENCE(name,time,count)
#define PROFILE_NAMED_PAUSE(name)
#define PROFILE_NAMED_RESUME(name)
#define PROFILE_FENCE(time,count)
#define PROFILE_PAUSE()
#define PROFILE_RESUME()
#define PROFILE_RATIO(time,total) (.0f)
#define PROFILE_RESET(time,count)
#else
///////////////////////////////////////////////////////////////////////////////
// Profiller claas implementation
class Profiller
{
u32& uTotalTime;
u32 uLocalTime;
public:
Profiller(u32& _uTime, u32& _uCount) : uTotalTime(_uTime)
{
++_uCount;
uLocalTime = gp2x_timer_raw();
}
void Pause()
{
uTotalTime += gp2x_timer_raw()-uLocalTime;
}
void Resume()
{
uLocalTime = gp2x_timer_raw();
}
~Profiller()
{
uTotalTime += gp2x_timer_raw()-uLocalTime;
}
static void Reset(u32& _uTime, u32& _uCount)
{
_uTime = _uCount = 0;
}
static float Ratio(u32 _uTime, u32 _uTotal)
{
return float(_uTime)/float(_uTotal);
}
};
///////////////////////////////////////////////////////////////////////////////
// Profiller macros
#define PROFILE_NAMED_FENCE(name,time,count) Profiller __myProfiller##name(time,count)
#define PROFILE_NAMED_PAUSE(name) __myProfiller##name.Pause()
#define PROFILE_NAMED_RESUME(name) __myProfiller##name.Resume()
#define PROFILE_FENCE(time,count) PROFILE_NAMED_FENCE(0,time,count)
#define PROFILE_PAUSE() PROFILE_NAMED_PAUSE(0)
#define PROFILE_RESUME() PROFILE_NAMED_RESUME(0)
#define PROFILE_RATIO(time,total) Profiller::Ratio(time,total)
#define PROFILE_RESET(time,count) Profiller::Reset(time,count)
#endif //ENABLE_PROFILLER
///////////////////////////////////////////////////////////////////////////////
#endif // PROFILLER_H
Para usarlo lo único que hay que hacer es lo siguiente
// estas variables almacenaran mis medidas
unsigned int variableDeTiempo,variableDeCuenta
void miFuncion()
{
// La siguiente marca creas una medida desde ella hasta que se sale de la función
PROFILE_FENCE(variableDeTiempo,variableDeCuenta);
for(int i=0;i<10000;++i)
{
HazAlgoDificil();
}
}
void miRun()
{
// A Continuación leemos los "contadores" y reseteamos las variables
printf("tiempo %d, veces%d", variableDeTiempo,variableDeCuenta);
PROFILE_RESET(variableDeTiempo,variableDeCuenta);
}
El mayor "problema" que tiene el sistema es que las variables de "profile" tiene que estar "declaradas en algun sitio, eso se puede "arreglar" con mas ingenieria, pero esto es lo que necesitaba para lo que estaba haciendo..
Si queremos medir partes de una funcion hay que hacer lo siguiente, ya que el tiempo esta ligado al "scope" en el que se mete la marca.
void miFuncion()
{
// medicion completa de toda la función
PROFILE_FENCE(variableDeTiempoTotal,variableDeCuen taTotal);
if(bOpcion)
{
PROFILE_FENCE(variableDeTiempoParcialA,variableDeC uentaParcialA);
for(int i=0;i<10000;++i)
HazAlgoDificil();
}
else
{
PROFILE_FENCE(variableDeTiempoParcialB,variableDeC uentaParcialB);
for(int i=0;i<100;++i)
HazAlgoDificilTambien();
}
// el código siguiente no se medirá con lo cual
// variableDeTiempoTotal > ( variableDeTiempoParcialA + variableDeTiempoParcialB + variableDeTiempoParcialC )
// y tiempo de este for será igual a variableDeTiempoTotal - ( variableDeTiempoParcialA + variableDeTiempoParcialB + variableDeTiempoParcialC )
for(int i=0;i<100;++i)
HazAlgo();
// para medir una parte aislada de codigo lo metemos entre {}
{
PROFILE_FENCE(variableDeTiempoPArcialC,variableDeC uentaParcialC);
for(int i=0;i<100;++i)
HazAlgoMas();
}
}
La dependenci de las minimal es algo facilmente solucionable, si quereis usarlo con sdl solo tenies que sustituir la lamada a gp2x_timer_read() por una a SDL_GetTicks() creo recordar, teniendo en cuenta que estas medidas son en "unidades de tick" no en segundos...
En breve supongo publicare una version "mejorada" con soporte "de serie" para la SDL y con ayudas para calcular porcentajes sobre un total... que es muy fácil y biene bien para saber que areas de un programa se estás llebando más tiempo.
Por último comentar que hay que hacer un #define ENABLE_PROFILLER en vuestro código o el sistema esta preparado para eliminar completamente todo rastro del profiler si no esta definido ese "símbolo"
Unai.
Consiste en código y unas macros para que poner y calcular tiempos sea mas fácil...
El truco esta en que usa constructores y destructores de c++ para que no haya que emarcar el final de la "cuenta".
Acontinuación el codigo a meter en "profiller.h"
#ifndef PROFILLER_H
#define PROFILLER_H
///////////////////////////////////////////////////////////////////////////////
// Profilling helper functions, minimal libs are needed for timer.
#include "minimal.h"
///////////////////////////////////////////////////////////////////////////////
// Minimal extensions used for better accuracy and speed.
/*
unsigned long gp2x_timer_raw(void)
{
return gp2x_memregl[0x0A00>>2];
}
unsigned long gp2x_timer_raw_to_ticks(unsigned long ticks)
{
return ticks/gp2x_ticks_per_second;
}
unsigned long gp2x_timer_raw_second()
{
return 7372800;
}
*/
///////////////////////////////////////////////////////////////////////////////
// Profiler Interface/Macro Definitions
///////////////////////////////////////////////////////////////////////////////
#ifndef ENABLE_PROFILLER
#define PROFILE_NAMED_FENCE(name,time,count)
#define PROFILE_NAMED_PAUSE(name)
#define PROFILE_NAMED_RESUME(name)
#define PROFILE_FENCE(time,count)
#define PROFILE_PAUSE()
#define PROFILE_RESUME()
#define PROFILE_RATIO(time,total) (.0f)
#define PROFILE_RESET(time,count)
#else
///////////////////////////////////////////////////////////////////////////////
// Profiller claas implementation
class Profiller
{
u32& uTotalTime;
u32 uLocalTime;
public:
Profiller(u32& _uTime, u32& _uCount) : uTotalTime(_uTime)
{
++_uCount;
uLocalTime = gp2x_timer_raw();
}
void Pause()
{
uTotalTime += gp2x_timer_raw()-uLocalTime;
}
void Resume()
{
uLocalTime = gp2x_timer_raw();
}
~Profiller()
{
uTotalTime += gp2x_timer_raw()-uLocalTime;
}
static void Reset(u32& _uTime, u32& _uCount)
{
_uTime = _uCount = 0;
}
static float Ratio(u32 _uTime, u32 _uTotal)
{
return float(_uTime)/float(_uTotal);
}
};
///////////////////////////////////////////////////////////////////////////////
// Profiller macros
#define PROFILE_NAMED_FENCE(name,time,count) Profiller __myProfiller##name(time,count)
#define PROFILE_NAMED_PAUSE(name) __myProfiller##name.Pause()
#define PROFILE_NAMED_RESUME(name) __myProfiller##name.Resume()
#define PROFILE_FENCE(time,count) PROFILE_NAMED_FENCE(0,time,count)
#define PROFILE_PAUSE() PROFILE_NAMED_PAUSE(0)
#define PROFILE_RESUME() PROFILE_NAMED_RESUME(0)
#define PROFILE_RATIO(time,total) Profiller::Ratio(time,total)
#define PROFILE_RESET(time,count) Profiller::Reset(time,count)
#endif //ENABLE_PROFILLER
///////////////////////////////////////////////////////////////////////////////
#endif // PROFILLER_H
Para usarlo lo único que hay que hacer es lo siguiente
// estas variables almacenaran mis medidas
unsigned int variableDeTiempo,variableDeCuenta
void miFuncion()
{
// La siguiente marca creas una medida desde ella hasta que se sale de la función
PROFILE_FENCE(variableDeTiempo,variableDeCuenta);
for(int i=0;i<10000;++i)
{
HazAlgoDificil();
}
}
void miRun()
{
// A Continuación leemos los "contadores" y reseteamos las variables
printf("tiempo %d, veces%d", variableDeTiempo,variableDeCuenta);
PROFILE_RESET(variableDeTiempo,variableDeCuenta);
}
El mayor "problema" que tiene el sistema es que las variables de "profile" tiene que estar "declaradas en algun sitio, eso se puede "arreglar" con mas ingenieria, pero esto es lo que necesitaba para lo que estaba haciendo..
Si queremos medir partes de una funcion hay que hacer lo siguiente, ya que el tiempo esta ligado al "scope" en el que se mete la marca.
void miFuncion()
{
// medicion completa de toda la función
PROFILE_FENCE(variableDeTiempoTotal,variableDeCuen taTotal);
if(bOpcion)
{
PROFILE_FENCE(variableDeTiempoParcialA,variableDeC uentaParcialA);
for(int i=0;i<10000;++i)
HazAlgoDificil();
}
else
{
PROFILE_FENCE(variableDeTiempoParcialB,variableDeC uentaParcialB);
for(int i=0;i<100;++i)
HazAlgoDificilTambien();
}
// el código siguiente no se medirá con lo cual
// variableDeTiempoTotal > ( variableDeTiempoParcialA + variableDeTiempoParcialB + variableDeTiempoParcialC )
// y tiempo de este for será igual a variableDeTiempoTotal - ( variableDeTiempoParcialA + variableDeTiempoParcialB + variableDeTiempoParcialC )
for(int i=0;i<100;++i)
HazAlgo();
// para medir una parte aislada de codigo lo metemos entre {}
{
PROFILE_FENCE(variableDeTiempoPArcialC,variableDeC uentaParcialC);
for(int i=0;i<100;++i)
HazAlgoMas();
}
}
La dependenci de las minimal es algo facilmente solucionable, si quereis usarlo con sdl solo tenies que sustituir la lamada a gp2x_timer_read() por una a SDL_GetTicks() creo recordar, teniendo en cuenta que estas medidas son en "unidades de tick" no en segundos...
En breve supongo publicare una version "mejorada" con soporte "de serie" para la SDL y con ayudas para calcular porcentajes sobre un total... que es muy fácil y biene bien para saber que areas de un programa se estás llebando más tiempo.
Por último comentar que hay que hacer un #define ENABLE_PROFILLER en vuestro código o el sistema esta preparado para eliminar completamente todo rastro del profiler si no esta definido ese "símbolo"
Unai.