一个标准的时间超时成本宏
最近在帮同事处理一些比较复杂的逻辑过程,在此过程中,需要一个对函数调用时间成本进行判断的函数。纵然,每次写time = Bgein(),time = end, end - beging 也行,但是看上去实在是太杂乱了,而且代码重复且无必要。
于是抽空,封装了一个时间成本的宏,利用类的构造和析构,达成目标。
实现的目标:
(1)代码要在windows和Linux都可以编译使用。
(2)代码计算要到毫秒级
(3)调用方式,在要监测的函数上只能有一行代码,力求最大的简洁。
(4)自动生成超时函数日志,记录发生时间,所在函数名,行数,文件名。
综合以上的需求,花了一上午写了出来。
代码不多,但是其中遇到的一些概念和问题。我留在这里,供大家做一个参考。
这个宏实现本身不复杂,对于时间的选用,这里正好做一个比较详细的测试。
首先,考虑到windows和Linux下通用,那么就要用time.h下的标准时间API,这样才能排除差异性。
首先考虑的最简单,就是time_t,通过asctime()一系列函数,实现时间的记录,但是问题是,这个在某些系统下只能到秒级。与需求(2)不符合。
于是考虑了time.h中的clock()一系列API,经测试,在windows下,Sleep(1000),可以获得正确的数值,但是在Linux,我用usleep(1000*1000),结果是0,很奇怪,于是查了一下man,发现clock是这么解释的,clock是记录进程占用CPU的运行时间,而在linux下,sleep()挂起是不计算为CPU时间的,所以永远是0,我查阅了windows的MSDN,发现这里的实现,和linux是有差异的,虽然这里也是进程时间,但是sleep()的挂起依旧计算在clock内,且获得的这个值明显是一个进程运行时间,而非当前时间。这个方法也只能PASS。
其实仔细想想,我只想知道一个相对时间差距,至于现在是何年月日,并无必要知道,问题的关键是,正确在不同平台下获得一样的结果,且在时间修改的前提下,我一样能获得时间相对的差值。
windows倒是有gettickcount(),那么,沿着这个思路,我有没有方法在Linux实现一个一样的东东?
答案是有的。 unsigned long GetSystemTickCount()
{
#ifdef WIN32
return GetTickCount();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
#endif
}clock_gettime是一个标准的time.h 提供的C++ API,号称能达到纳秒级别(1秒=1000毫秒 = 1000*1000微秒 = 1000*1000*1000纳秒)
但是从实际来看,windows和linux硬件上是有差异的,如果硬件不支持到纳秒级的终端(大部分硬件不支持),那么操作系统会random一个随机的三位数,填充微秒和纳秒,实际多数情况下,纳秒的获得是没有意义的。一般毫秒级别的就足够了,特殊需求另说。
我只要获得毫秒级别的就够了。
于是,看看clock_gettime支持哪些宏:
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间恩,看到这里,我非常满意,这里的宏完全可以满足我的需求。
材料准备完毕,厨师开始做菜了,呵呵。
首先,实现一个类,这个类是负责计算时间成本,并自动根据需要写入文件。//用于计算时间消耗类
class CTimeCost
{
public:
CTimeCost(int nMillionSecond, const char* pFunctionName, const char* pFileName, int nLine)
{
m_nMillionSecond = nMillionSecond;
sprintf(m_szFunctionName, "%s", pFunctionName);
sprintf(m_szFileName, "%s", pFileName);
m_nFileLine = nLine;
TimeBegin();
};
~CTimeCost()
{
TimeEnd();
};
void TimeBegin()
{
m_lBegin = GetSystemTickCount();
};
void TimeEnd()
{
m_lEnd = GetSystemTickCount();
long lTimeInterval = m_lEnd - m_lBegin;//转换成毫秒
if(lTimeInterval >= (long)m_nMillionSecond)
{
char szLog = {'\0'};
//记录日志
FILE* pFile = fopen("TimeCost.log", "a");
if(pFile != NULL)
{
char szTimeNow = {'\0'};
time_t tNow = time(NULL);
struct tm* tmNow = localtime(&tNow);
sprintf(szTimeNow, "%04d-%02d-%02d %02d:%02d:%02d", tmNow->tm_year + 1900, tmNow->tm_mon + 1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec);
sprintf(szLog, "[%s]dbTimeInterval more than (%d) < (%d), %s:%s:%d行.\n", szTimeNow, m_nMillionSecond, lTimeInterval, m_szFileName, m_szFunctionName, m_nFileLine);
fwrite(szLog, strlen(szLog), sizeof(char), pFile);
}
fclose(pFile);
}
};
private:
unsigned long GetSystemTickCount()
{
#ifdef WIN32
return GetTickCount();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
#endif
}
private:
long m_lBegin;
long m_lEnd;
unsigned int m_nMillionSecond;
char m_szFunctionName;
char m_szFileName;
int m_nFileLine;
};
这里的代码就不一行行解释了,C++有基础的人一看就懂。
然后,我来实现这个宏,#define __TIMECOST(cost) CTimeCost timecost(cost, __FUNCTION__, __FILE__, __LINE__);这里的cost,就是你设置的能容忍的超时时间,如果超过了这个时间,就会自动记录日志文件。
那么来看看,怎么用。class CTest
{
public:
CTest() {};
~CTest() {};
void func()
{
__TIMECOST(100);
#if WIN32
Sleep(500);
#else
usleep(500*1000); //usleep单位是微秒
#endif
}
};好了,我们来详细测试一下。int main(int argc, char* argv[])
{
CTest Test;
Test.func();
getchar();
return 0;
}代码在windows下和linux下,得到的结果一致。
输出日志结果为:(windows)
dbTimeInterval more than (100) < (500), d:\freeeyeswork\2013年\timecost\timecost\timecost.cpp:CTest::func:90行.
来看看Linux下的输出结果
dbTimeInterval more than (100) < (500), TimeCost.cpp:func:90行.
恩,达到目标需求,交付。同事很喜欢,一行代码达到目的。
此代码在windows和linux下测试通过。
页:
[1]