软件中Profile的解释很多,有时候指的是一组设置值,这里说的Profile是对运行程序的数据采样,获得内存使用和运行时间的纪录,通过分析得以优化代码。
1)内存Profile。C++提供宏和函数重载的功能,由此可以添加对内存的纪录,将一下代码放在头文件中,项目中每个.cpp文件都include这个头文件,使其产生效应。
#ifdef _DEBUG
#define new((x)) newObj((__FUNCTION__, __LINE__, (x));
#define delete((x)) deleteObj(__FUNCTION__, __LINE__, (x));
inline void * newObj(const char * function, int line, size_t size)
{
void ptr = (void *)malloc(size);
//Record the function, line and size, ptr
return ptr;
}
inline void deleteObj(const char * function, int line, void *ptr)
{
//Record the function, line, and ptr.
free ptr;
}
#endif
至于如何纪录添加释放内存,方法很多,可以直接打印出来或者写到一个文件,不过这样非常影响效率,而且不利于产生容易阅读的输出。比较合理的方法,建立一个Singletion的类,每次纪录都通过这个类添加纪录,这个类的析构函数把所有的纪录按照需要的方式dump出来。
重载new/delete仅仅用于做profile,在debug版本中发现内存分配问题,在release版本中通过不定义_DEBUG去掉。
1)运行时间Profile。要获得某一段代码的运行时间,就得在入口纪录一个时间,在出口记录一个时间,然后取二者之差,这样的代码比较难看,其实可以利用C++程序对局部变量的处理。C++程序执行到一个scope结束的时候会删除这个scope里面局部变量,也就是调用其的析构函数
#ifdef _DEBUG
#define PROFILE_BEGIN Profile p(__FILE__, __FUNCTION__, __LINE__);
class Profile
{
public:
Profile(const char * file, const char *function, int line)
{
//record info
beginTimestamp = ...//current time
}
~Profile()
{
timeGap = current time - beginTimestamp;
//register info
}
private:
int beginTimestamp;
int timeGap;
};
#else
#define PROFILE_BEGIN
#endif
这样在源代码里面,只需要在一个函数入口写上PROFILE_BEGIN,就可以获得这个函数体的运行时间。
int foo()
{
PROFILE_BEGIN
//....
}
如果想要获得函数中某一部分code的运行时间,可以把这一部分用{}扩起来,在开始处加一个PROFILE_BEGIN.
如果想要获得函数中某一部分code的运行时间,可以把这一部分用{}扩起来,在开始处加一个PROFILE_BEGIN.