頭文件<time_cost_record.h>:
#if defined (__linux)
#include <sys/time.h>
#include <stdio.h>
#elif defined (_WIN32)
#include <windows.h>
#endif
#include <stdarg.h>
#include <string>
#include <vector>
#include <map>
#if defined (__linux)
#define format_str snprintf
#define vformat_str vsnprintf
#define _max std::max
#elif defined (_WIN32)
#define format_str sprintf_s
#define vformat_str vsprintf_s
#define _max max
#endif
class time_cost_record_tool
{
public:
static void make_time_now(char* timestr, int timestrlen);
static void output_str(const std::string& str);
};
//////////////////////////////////////////////////////////////////////////
// 性能測試
class time_cost_record
{
public:
time_cost_record(const char *strFormat);
~time_cost_record(void);
void begin_time_cost_record();
void end_time_cost_record();
void begin_timing();
void end_timing();
public:
#if defined (__linux)
timeval m_t1, m_t2;
#elif defined (_WIN32)
LARGE_INTEGER m_t1, m_t2, m_tc;
#endif
std::string m_strFormat;
double m_cost_ms;
};
//////////////////////////////////////////////////////////////////////////
// SEMI-AUTO性能測試
class time_cost_record_semi_auto
{
public:
time_cost_record_semi_auto(const char *strFormat, ...);
void begin_time_cost_record_semi_auto();
~time_cost_record_semi_auto(void);
private:
time_cost_record* m_instance;
};
//////////////////////////////////////////////////////////////////////////
// RAII性能測試
class time_cost_record_raii
{
public:
time_cost_record_raii(const char *strFormat, ...);
~time_cost_record_raii(void);
private:
time_cost_record* m_instance;
};
//////////////////////////////////////////////////////////////////////////
// 分組性能測試
class time_cost_record_group
{
public:
time_cost_record_group(const char *strFormat);
~time_cost_record_group(void);
void begin_time_cost_record_group();
void end_time_cost_record_group();
void begin_time_cost_record_item(const char *strItem, const char *strFormat, ...);
void end_time_cost_record_item(const char *strItem);
public:
#pragma warning(disable:4251)
std::vector<std::string> m_vctgroups;
std::map<std::string, time_cost_record*> m_maptests;
std::string m_strFormat;
#pragma warning(default:4251)
size_t m_nFormatLen;
};
//////////////////////////////////////////////////////////////////////////
// RAII分組性能測試
class time_cost_record_group_raii
{
public:
time_cost_record_group_raii(const char *strFormat, ...);
~time_cost_record_group_raii(void);
public:
time_cost_record_group* m_instance;
};
//////////////////////////////////////////////////////////////////////////
// RAII分組性能測試
class time_cost_record_group_item_raii
{
public:
time_cost_record_group_item_raii(time_cost_record_group *group, const char *strItem, const char *strFormat, ...);
~time_cost_record_group_item_raii();
public:
time_cost_record_group* m_group;
#pragma warning(disable:4251)
std::string m_strItem;
#pragma warning(default:4251)
};
#pragma warning(disable:4010)
#if defined (__linux)
#define TimeCostRecordBegin(name,strFormat,args...) \
char strFormat_buf_##name[1024] = {}; \
format_str(strFormat_buf_##name,1024,strFormat,##args); \
time_cost_record time_cost_record##name(strFormat_buf_##name); \
time_cost_record##name.begin_time_cost_record();
#define TimeCostRecordEnd(name) \
time_cost_record##name.end_time_cost_record();
#define TimeCostRecordSemiAuto(name,strFormat,args...) \
time_cost_record_semi_auto time_cost_record_semi_auto##name(strFormat,##args);
#define TimeCostRecordSemiAutoBegin(name) \
time_cost_record_semi_auto##name.begin_time_cost_record_semi_auto();
#define TimeCostRecordAuto(name,strFormat,args...) \
time_cost_record_raii time_cost_record_raii##name(strFormat,##args);
#define TimeCostRecordGroupBegin(name,strFormat,args...) \
char strFormat_buf_##name[1024] = {}; \
sprintf_s(strFormat_buf_##name,1024,strFormat,##args); \
time_cost_record_group time_cost_record_group##name(strFormat_buf_##name); \
time_cost_record_group##name.begin_time_cost_record_group();
#define TimeCostRecordGroupItemBegin(name,item,strFormat,args...) \
time_cost_record_group##name.begin_time_cost_record_item(#item,strFormat,##args);
#define TimeCostRecordGroupItemEnd(name,item) \
time_cost_record_group##name.end_time_cost_record_item(#item);
#define TimeCostRecordGroupEnd(name) \
time_cost_record_group##name.end_time_cost_record_group();
#define TimeCostRecordGroupAuto(name,strFormat,args...) \
time_cost_record_group_raii time_cost_record_group_raii##name(strFormat,##args); \
time_cost_record_group &time_cost_record_group##name = *time_cost_record_group_raii##name.m_instance;
#define TimeCostRecordGroupItemAuto(name,item,strFormat,args...) \
time_cost_record_group_item_raii time_cost_record_group_item_raii##item(&time_cost_record_group##name, #item, strFormat,##args);
#elif defined (_WIN32)
#ifdef _DEBUG
#define TimeCostRecordBegin(name,strFormat,...) \
char strFormat_buf_##name[1024] = {}; \
format_str(strFormat_buf_##name,1024,strFormat,__VA_ARGS__); \
time_cost_record time_cost_record##name(strFormat_buf_##name); \
time_cost_record##name.begin_time_cost_record();
#define TimeCostRecordEnd(name) \
time_cost_record##name.end_time_cost_record();
#define TimeCostRecordSemiAuto(name,strFormat,...) \
time_cost_record_semi_auto time_cost_record_semi_auto##name(strFormat,__VA_ARGS__);
#define TimeCostRecordSemiAutoBegin(name) \
time_cost_record_semi_auto##name.begin_time_cost_record_semi_auto();
#define TimeCostRecordAuto(name,strFormat,...) \
time_cost_record_raii time_cost_record_raii##name(strFormat,__VA_ARGS__);
#define TimeCostRecordGroupBegin(name,strFormat,...) \
char strFormat_buf_##name[1024] = {}; \
sprintf_s(strFormat_buf_##name,1024,strFormat,__VA_ARGS__); \
time_cost_record_group time_cost_record_group##name(strFormat_buf_##name); \
time_cost_record_group##name.begin_time_cost_record_group();
#define TimeCostRecordGroupItemBegin(name,item,strFormat,...) \
time_cost_record_group##name.begin_time_cost_record_item(#item,strFormat,__VA_ARGS__);
#define TimeCostRecordGroupItemEnd(name,item) \
time_cost_record_group##name.end_time_cost_record_item(#item);
#define TimeCostRecordGroupEnd(name) \
time_cost_record_group##name.end_time_cost_record_group();
#define TimeCostRecordGroupAuto(name,strFormat,...) \
time_cost_record_group_raii time_cost_record_group_raii##name(strFormat,__VA_ARGS__); \
time_cost_record_group &time_cost_record_group##name = *time_cost_record_group_raii##name.m_instance;
#define TimeCostRecordGroupItemAuto(name,item,strFormat,...) \
time_cost_record_group_item_raii time_cost_record_group_item_raii##item(&time_cost_record_group##name, #item, strFormat,__VA_ARGS__);
#else
#define TimeCostRecordBegin(name,strFormat,...) // \
char strFormat_buf_##name[1024] = {}; \
format_str(strFormat_buf_##name,1024,strFormat,__VA_ARGS__); \
time_cost_record time_cost_record##name(strFormat_buf_##name); \
time_cost_record##name.begin_time_cost_record();
#define TimeCostRecordEnd(name) // \
time_cost_record##name.end_time_cost_record();
#define TimeCostRecordSemiAuto(name,strFormat,...) // \
time_cost_record_semi_auto time_cost_record_semi_auto##name(strFormat,__VA_ARGS__);
#define TimeCostRecordSemiAutoBegin(name) // \
time_cost_record_semi_auto##name.begin_time_cost_record_semi_auto();
#define TimeCostRecordAuto(name,strFormat,...) // \
time_cost_record_raii time_cost_record_raii##name(strFormat,__VA_ARGS__);
#define TimeCostRecordGroupBegin(name,strFormat,...) // \
char strFormat_buf_##name[1024] = {}; \
sprintf_s(strFormat_buf_##name,1024,strFormat,__VA_ARGS__); \
time_cost_record_group time_cost_record_group##name(strFormat_buf_##name); \
time_cost_record_group##name.begin_time_cost_record_group();
#define TimeCostRecordGroupItemBegin(name,item,strFormat,...) // \
time_cost_record_group##name.begin_time_cost_record_item(#item,strFormat,__VA_ARGS__);
#define TimeCostRecordGroupItemEnd(name,item) // \
time_cost_record_group##name.end_time_cost_record_item(#item);
#define TimeCostRecordGroupEnd(name) // \
time_cost_record_group##name.end_time_cost_record_group();
#define TimeCostRecordGroupAuto(name,strFormat,...) // \
time_cost_record_group_raii time_cost_record_group_raii##name(strFormat,__VA_ARGS__); \
time_cost_record_group &time_cost_record_group##name = *time_cost_record_group_raii##name.m_instance;
#define TimeCostRecordGroupItemAuto(name,item,strFormat,...) // \
time_cost_record_group_item_raii time_cost_record_group_item_raii##item(&time_cost_record_group##name, #item, strFormat,__VA_ARGS__);
#endif
#endif
#pragma warning(default:4010)
源文件<time_cost_record.cpp>:
#include "time_cost_record.h"
#include <string.h>
void time_cost_record_tool::make_time_now(char* timestr, int timestrlen)
{
#if defined (__linux)
timeval tv;
gettimeofday(&tv,NULL);
tm* stm = localtime(&tv.tv_sec);
format_str(timestr, timestrlen, "%02d:%02d:%02d:%03ld", stm->tm_hour, stm->tm_min, stm->tm_sec, tv.tv_usec / 1000);
#elif defined (_WIN32)
SYSTEMTIME systm;
GetLocalTime(&systm);
format_str(timestr, timestrlen, "%02d:%02d:%02d:%03d", systm.wHour, systm.wMinute, systm.wSecond, systm.wMilliseconds);
#endif
}
void time_cost_record_tool::output_str(const std::string& str)
{
#if defined (__linux)
printf("%s",str.c_str());
#elif defined (_WIN32)
OutputDebugStringA(str.c_str());
#endif
}
time_cost_record::time_cost_record(const char *strFormat)
: m_strFormat(strFormat)
, m_cost_ms(0.0f)
{
}
time_cost_record::~time_cost_record(void)
{
}
void time_cost_record::begin_time_cost_record()
{
char timenow[32] = {};
time_cost_record_tool::make_time_now(timenow,32);
time_cost_record_tool::output_str((m_strFormat + "-BEGIN:" + timenow + "...\n").c_str());
begin_timing();
}
void time_cost_record::end_time_cost_record()
{
end_timing();
char strFormat_buf[1024] = {};
format_str(strFormat_buf, 1024, (m_strFormat + "-END : %12.6fms.\n").c_str(), m_cost_ms);
time_cost_record_tool::output_str(strFormat_buf);
}
void time_cost_record::begin_timing()
{
#if defined (__linux)
gettimeofday(&m_t1, NULL);
#elif defined (_WIN32)
QueryPerformanceFrequency(&m_tc);
QueryPerformanceCounter(&m_t1);
#endif
}
void time_cost_record::end_timing()
{
#if defined (__linux)
gettimeofday(&m_t2, NULL);
m_cost_ms += (m_t2.tv_sec - m_t1.tv_sec) * 1000 + (m_t2.tv_usec - m_t1.tv_usec) / double(1000);
#elif defined (_WIN32)
QueryPerformanceCounter(&m_t2);
m_cost_ms += ((m_t2.QuadPart - m_t1.QuadPart)*1000.0) / m_tc.QuadPart;
#endif
}
///////////////////////////////////////////////////////////////////
time_cost_record_group::time_cost_record_group(const char *strFormat)
: m_strFormat(strFormat)
, m_nFormatLen(0)
{
}
time_cost_record_group::~time_cost_record_group(void)
{
for (std::map<std::string, time_cost_record*>::iterator it = m_maptests.begin(); it != m_maptests.end(); ++it)
{
delete it->second;
}
}
void time_cost_record_group::begin_time_cost_record_group()
{
char timenow[32] = {};
time_cost_record_tool::make_time_now(timenow, 32);
time_cost_record_tool::output_str((m_strFormat + "-BEGIN:" + timenow + "...\n").c_str());
}
void time_cost_record_group::end_time_cost_record_group()
{
char strFormat_buf[1024] = {};
for (std::vector<std::string>::iterator it = m_vctgroups.begin(); it != m_vctgroups.end(); ++it)
{
format_str(strFormat_buf, 1024, (m_maptests[*it]->m_strFormat + std::string(m_nFormatLen - m_maptests[*it]->m_strFormat.length(), ' ') + ":%12.6fms.\n").c_str(), m_maptests[*it]->m_cost_ms);
time_cost_record_tool::output_str(strFormat_buf);
}
format_str(strFormat_buf, 1024, "%s", (m_strFormat + "-END.\n").c_str());
time_cost_record_tool::output_str(strFormat_buf);
}
void time_cost_record_group::begin_time_cost_record_item(const char *strItem, const char *strFormat, ...)
{
std::map<std::string, time_cost_record*>::iterator itf = m_maptests.find(strItem);
if (itf == m_maptests.end())
{
m_vctgroups.push_back(strItem);
char strFormat_buf[1024] = {};
va_list args;
va_start(args, strFormat);
vformat_str(strFormat_buf, 1024, strFormat, args);
va_end(args);
m_nFormatLen = _max(m_nFormatLen, strlen(strFormat_buf) + 2);
itf = m_maptests.insert(std::make_pair(strItem, new time_cost_record((std::string(" ") + strFormat_buf).c_str()))).first;
}
itf->second->begin_timing();
}
void time_cost_record_group::end_time_cost_record_item(const char *strItem)
{
m_maptests[strItem]->end_timing();
}
///////////////////////////////////////////////////////////////////
time_cost_record_semi_auto::time_cost_record_semi_auto(const char *strFormat, ...)
{
char strFormat_buf[1024] = {};
va_list args;
va_start(args, strFormat);
vformat_str(strFormat_buf, 1024, strFormat, args);
va_end(args);
m_instance = new time_cost_record(strFormat_buf);
}
void time_cost_record_semi_auto::begin_time_cost_record_semi_auto()
{
m_instance->begin_time_cost_record();
}
time_cost_record_semi_auto::~time_cost_record_semi_auto(void)
{
m_instance->end_time_cost_record();
delete m_instance;
}
///////////////////////////////////////////////////////////////////
time_cost_record_raii::time_cost_record_raii(const char *strFormat, ...)
{
char strFormat_buf[1024] = {};
va_list args;
va_start(args, strFormat);
vformat_str(strFormat_buf, 1024, strFormat, args);
va_end(args);
m_instance = new time_cost_record(strFormat_buf);
m_instance->begin_time_cost_record();
}
time_cost_record_raii::~time_cost_record_raii(void)
{
m_instance->end_time_cost_record();
delete m_instance;
}
///////////////////////////////////////////////////////////////////
time_cost_record_group_raii::time_cost_record_group_raii(const char *strFormat, ...)
{
char strFormat_buf[1024] = {};
va_list args;
va_start(args, strFormat);
vformat_str(strFormat_buf, 1024, strFormat, args);
va_end(args);
m_instance = new time_cost_record_group(strFormat_buf);
m_instance->begin_time_cost_record_group();
}
time_cost_record_group_raii::~time_cost_record_group_raii(void)
{
m_instance->end_time_cost_record_group();
delete m_instance;
}
time_cost_record_group_item_raii::time_cost_record_group_item_raii(time_cost_record_group *group, const char *strItem, const char *strFormat, ...)
{
if (group)
{
m_group = group;
m_strItem = strItem;
std::map<std::string, time_cost_record*>::iterator itf = group->m_maptests.find(strItem);
if (itf == group->m_maptests.end())
{
group->m_vctgroups.push_back(strItem);
char strFormat_buf[1024] = {};
va_list args;
va_start(args, strFormat);
vformat_str(strFormat_buf, 1024, strFormat, args);
va_end(args);
group->m_nFormatLen = _max(group->m_nFormatLen, strlen(strFormat_buf) + 2);
itf = group->m_maptests.insert(std::make_pair(strItem, new time_cost_record((std::string(" ") + strFormat_buf).c_str()))).first;
}
itf->second->begin_timing();
}
}
time_cost_record_group_item_raii::~time_cost_record_group_item_raii()
{
if (m_group)
{
m_group->m_maptests[m_strItem]->end_timing();
}
}
使用:<main.cpp>
#include "time_cost_record.h"
#include <stdlib.h>
#include <vector>
#include <map>
#include <set>
#include <time.h>
#define datacount 100000
int intarray[datacount] = {};
void test()
{
TimeCostRecordAuto(test, "test()");
TimeCostRecordSemiAuto(test2, "container free");
TimeCostRecordBegin(test0, "container declare");
std::vector<int> v1;
std::set<int> s1;
TimeCostRecordEnd(test0);
TimeCostRecordGroupBegin(test1, "container fill data count:%d", datacount);
for (int i = 0; i < datacount; ++i)
{
{
TimeCostRecordGroupItemAuto(test1, test_1_1, "vector<int> fill data");
v1.push_back(intarray[i]);
}
{
TimeCostRecordGroupItemAuto(test1, test_1_2, "set<int> fill data");
s1.insert(intarray[i]);
}
}
TimeCostRecordGroupEnd(test1);
TimeCostRecordSemiAutoBegin(test2);
}
int main()
{
srand(time(NULL));
for (int i = 0; i < datacount; ++i)
{
intarray[i] = i;
}
for (int i = 0; i < datacount * 2; ++i)
{
int idx1 = i%datacount;
int idx2 = rand() % datacount;
if (idx1 != idx2)
{
int tmp = intarray[idx1];
intarray[idx1] = intarray[idx2];
intarray[idx2] = tmp;
}
}
test();
return 1;
}
運行結果:
test()-BEGIN:11:21:42:001...
container declare-BEGIN:11:21:42:001...
container declare-END : 0.004162ms.
container fill data count:100000-BEGIN:11:21:42:002...
vector<int> fill data: 245.691362ms.
set<int> fill data: 1333.155098ms.
container fill data count:100000-END.
container free-BEGIN:11:21:45:040...
container free-END : 492.647772ms.
test()-END : 3531.906508ms.
備註:
gettimeofday只能獲得微妙級的精度,所以以上的時間測試程序linux版雖然小數點保留到毫秒後六位,實際只有三位小數點有效。
可以使用另外一個函數:clock_gettime,來達到測試納秒級時間的目的。
附上man鏈接: