性能檢查

頭文件<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鏈接:

https://linux.die.net/man/3/clock_gettime

發佈了33 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章