`

性能测试——(2)基于windows下的测试宏

阅读更多
#ifndef STAT_H
#define STAT_H
#include<map>
#include<string>
using namespace std;

/***
wx,取消原有用宏方式,但测试函数的开销可能会增加测试的精度
**/
struct st_stat{
public:
	st_stat():call_count(0),time(0){}
	LARGE_INTEGER start;
	LARGE_INTEGER end;
	int call_count;
	__int64 time;
};
/**测试函数性能或者代码块的
*/
class Runnable
{
public:
	explicit Runnable(const std::string& name): _name(name) {}  
	~Runnable() {}

	const std::string& name() const { return _name; }    

	inline void begin() ;
	inline void end() ;
	void diff_time(LONGLONG diff)
	{
		stat.time -=  (stat.end.QuadPart-diff);
	}
	int getCallCount(){return stat.call_count;}
	__int64 getCallTime(){return stat.time;}
	st_stat stat;
private:
	std::string _name;

};


class test_suite
{
public:
	static test_suite& get_instance()
	{
		static test_suite me;
		return me;
	}
~test_suite(){if(fp) fclose(fp);fp=NULL;
}

	void setWorkingDir(const std::string& val) { _working_dir = val; }
	const std::string& getWorkingDir() const { return _working_dir; }

	void setTestFilter(const std::string& val) { _test_filter = val; }
	const std::string& getTestFilter() const { return _test_filter; }
	void addTest(Runnable* test) { test_vec.insert(pair<string,Runnable*>(test->name(),test)); }
	void func_begin(const std::string &name);
	void func_end(const std::string &name);

	void init(const std::string &dir);
	void finish();
private:
	test_suite():fp(NULL),_working_dir(),_test_filter(){}

	void printHeading();
	void printFooter();
	void printError(const std::string&msg);

	std::string _working_dir;
	std::string _test_filter;
	typedef std::map<std::string,Runnable*> MAP;
	typedef MAP::iterator IT;
	typedef MAP::const_iterator const_it;
	 MAP test_vec;//所有需要测试的函数列表
	 
	std::vector<Runnable*> none_init_vec;//没有初始化的,需要new对象,因此最后需要释放
	FILE *fp;
};

void call_stat_begin(st_stat*pstat);
void call_stat_end(st_stat*pstat);

#if defined ST_TEST_PERFORMANCE
#define STAT_TEST_INIT(name) \
struct st_##name##_test: Runnable { \
	st_##name##_test(): Runnable(#name) { \
	test_suite::get_instance().addTest(this); \
	} \
} name##_test_instance

#define STAT_TEST_BEGIN(name) \
	test_suite::get_instance().func_begin(#name)

#define STAT_TEST_END(name) \
	test_suite::get_instance().func_end(#name)


#define STAT_GLOBAL_INIT(fileDir) test_suite::get_instance().init(fileDir);
#define STAT_GLOBAL_FINISH() test_suite::get_instance().finish();
#else
	#define STAT_TEST_INIT(name) 

#define STAT_TEST_BEGIN(name) (void*)(0)

#define STAT_TEST_END(name) (void*)(0)

#define STAT_GLOBAL_INIT(fileDir) 
#define STAT_GLOBAL_FINISH() (void*)(0)
#endif
#endif

st_stat.cpp 文件

 

#include"stdafx.h"
#include"st_stat.h"

#ifdef _WIN32
#include<windows.h>
void call_stat_begin(st_stat*pstat)
{
	pstat->call_count++;
	LARGE_INTEGER large_integer;
	DWORD mask = 1;
	//DWORD_PTR oldmask = ::SetThreadAffinityMask(::GetCurrentThread(),mask);//特别注意,在准确测试时候是需要设置cpu亲和性,否则多核情况下不准确,这里都注释掉
	BOOL bRet = ::QueryPerformanceCounter(&large_integer);

	//::SetThreadAffinityMask(::GetCurrentThread(),oldmask);
	_ASSERT(bRet);

	pstat->start = large_integer;
}
void call_stat_end(st_stat*pstat)
{
	DWORD mask = 1;
	//DWORD_PTR oldmask = ::SetThreadAffinityMask(::GetCurrentThread(),mask);
	LARGE_INTEGER large_integer;
	BOOL bRet = ::QueryPerformanceCounter(&large_integer);
	_ASSERT(bRet);
	//::SetThreadAffinityMask(::GetCurrentThread(),oldmask);
	pstat->end = large_integer;
	pstat->time += pstat->end.QuadPart-pstat->start.QuadPart;
}

void Runnable::begin()
{
	::call_stat_begin(&stat);

}
void  Runnable::end()
{
	call_stat_end(&stat);
}

void test_suite::func_begin(const std::string & name)
{
	// Run test initializers
	const_it it = test_vec.find(name);
	if(it!=test_vec.end())
	{
		LARGE_INTEGER large_integer;
		BOOL bRet = ::QueryPerformanceCounter(&large_integer);
		_ASSERT(bRet);
		(*it).second->begin();
		return;
	}
	Runnable *pTest = new Runnable(name);
	test_vec.insert(pair<string,Runnable*>(name,pTest));
	none_init_vec.push_back(pTest);
	pTest->begin();
}

void test_suite::func_end(const std::string & name)
{
	// Run test initializers
	const_it it = test_vec.find(name);
	if(it!=test_vec.end())
	{
		LARGE_INTEGER large_integer;
		BOOL bRet = ::QueryPerformanceCounter(&large_integer);
		_ASSERT(bRet);
		(*it).second->end();
		(*it).second->diff_time(large_integer.QuadPart);

	}
	//printError(name);
	/*vector<Runnable*>::iterator it = test_vec.begin();
	for (; it != test_vec.end(); ++it)
	{
	if ((*it)->name()==name)
	{
	LARGE_INTEGER large_integer;
	BOOL bRet = ::QueryPerformanceCounter(&large_integer);
	_ASSERT(bRet);
	(*it)->end();
	(*it)->diff_time(large_integer.QuadPart);
	}
	}*/

}
void test_suite::printHeading()
{
	if(fp)
	{

		fprintf(fp,"函数名,调用次数,调用时间PerformanceCounter\n");
		fprintf(fp,"start Tick Count=%d ms\r ",::GetTickCount());
	}
}
void test_suite::printFooter()
{
	if(fp)
	{
		fprintf(fp,"end Tick Count=%d ms\r",::GetTickCount());
	}
}
void test_suite:: init(const std::string &dir){
	setWorkingDir(dir);
	if(fp)
	{
		fclose(fp);
		fp = NULL;
	}
	if(getWorkingDir().size()>0)
	{	
		std::string filePath(dir);
		filePath.append("test_performance.csv");

		fp=fopen(filePath.c_str(),"a+");
	}
	else
	{
		fp=fopen("test_performance.csv","a+");
	}

	printHeading();
}
void test_suite::finish()
{

	if(fp)
	{
		for(IT it = test_vec.begin();it!=test_vec.end();it++)
		{
			fprintf(fp,"%s,%d,%I64d\r",it->second->name().c_str(),it->second->getCallCount(),it->second->getCallTime());
		}
	}
	if(fp) 
	{
		fclose(fp);
		fp =NULL;
	}
	std::vector<Runnable*>::iterator it = none_init_vec.begin();
	for(;it !=none_init_vec.end();it++)
	{
		if(*it!=NULL)
		{
			delete *it;
			*it=NULL;
		}
	}
}
void test_suite::printError(const std::string&msg)
{
	if(fp)
	{
		fprintf(fp,"%s",msg.c_str());
	}
}
#endif

 

这个是在上一篇改进下实现的,基于C++实现,不需要定义变量

使用方式:

(1)需要打开测试宏,可以在C++工程宏定义中定义ST_TEST_PERFORMANCE

(2)测试函数f,如下即可

 

bool CCompile::OutPutReulstFile()
{
	STAT_TEST_BEGIN(OutPutReulstFile);//宏定义里面是测试名称,名称同C语言规范,最好是用函数名

//原有函数体;
	STAT_TEST_END(OutPutReulstFile);//与begin对应即可

return 0;
}

 

 (3)程序启动时调用STAT_GLOBAL_INIT(".")

在进程中退出前,或者需要打印出结果的地方,调用STAT_GLOBAL_FINISH();否则不会生成测试结果文件

  • STAT_GLOBAL_INIT(string );用于初始化文件路径,打开文件句柄
  • STAT_GLOBAL_FINISH();用于关闭文件句柄,清空测试内存

这样会以追加+a方式生成一个文件,test_performance.csv;可以指定文件生成路径。进程正常退出,默认会生成该文件。

 

目前不支持多线程!!!!!这个要十分小心,确保所测试的模块只有一个线程调用。

分享到:
评论

相关推荐

    cocos2d-x泡泡龙例——VS版

    在移动开发领域,cocos2d-x是一个广泛使用的2D游戏开发框架,它基于C++,支持跨平台开发,包括iOS、Android以及Windows等多个操作系统。本教程将详细介绍如何在Visual Studio 2010环境下,利用cocos2d-x构建一款经典...

    华东VCT——SYS

    VCT——SYS中可能包含了定制的VC项目模板、宏定义、库函数以及对Windows API的扩展,使得开发者在编写C++代码时能更好地适应华东地区的系统环境。VC的特性,如性能优化、内存管理以及对Windows操作系统的深度集成,...

    很好的日志记录类,VS2010 MFC写的log4z日志类测试.zip

    《深入解析:基于VS2010 MFC的日志记录类——log4z》 在软件开发中,日志记录是不可或缺的一部分,它能够帮助开发者追踪程序运行过程中的错误、调试问题以及监控系统状态。本篇文章将围绕"VS2010 MFC写的log4z日志...

    qtwinmigrate-2.8-opensource

    Qt以其强大的功能、丰富的库支持和美观的GUI设计而闻名,而MFC则是微软为Windows应用程序开发提供的C++库,基于Windows API。在某些情况下,开发者可能需要将现有的MFC项目迁移到Qt环境,或者相反,将Qt项目集成到...

    vc教程入门-----真正的程序员用Visual C++

    1. **框架类**:MFC中的类大部分是基于Windows API设计的,如CWinApp、CWnd、CButton等,它们提供了对窗口、按钮等控件的封装。 2. **消息映射**:MFC使用消息映射机制,将Windows消息与成员函数关联,简化了事件...

    外国蒙特卡洛算法 包含C# 和 C 版本

    C#中的`NUnit`和C语言的`gcc`自带的`assert()`宏可以辅助进行测试。 10. **可视化**:为了更好地理解模拟过程和结果,可以使用C#的`System.Windows.Forms.DataVisualization.Charting`库或C语言的`gnuplot`等工具...

    MFC设计 汽车客运公司售票系统

    **汽车客运公司售票系统——基于MFC的实现** 在信息技术高度发达的今天,各种软件系统已经深入到各行各业,包括交通管理领域。汽车客运公司售票系统是这类应用的一个实例,它利用计算机技术,实现了对汽车票务的...

    stm32cubeide 1.12.1 自动补全代码-亲测试可用

    在1.12.1这个版本中,STM32CubeIDE引入了一个重要的特性——自动补全代码功能。 自动补全代码是现代IDE中的一个核心功能,它能够提高程序员的编写效率,减少错误。在STM32CubeIDE 1.12.1中,这一功能意味着用户在...

    课程设计----通讯录(C++)

    【课程设计——通讯录(C++)——基于MFC】是一项常见的编程实践任务,旨在让学生掌握面向对象编程和用户界面设计的基本技能。MFC(Microsoft Foundation Classes)是微软提供的一套C++库,用于简化Windows应用程序...

    学生成绩管理系统

    Visual C++6.0是Microsoft公司推出的一款强大的C++开发工具,它集成了编译器、调试器以及各种辅助开发工具,支持Windows API,提供了直观的图形用户界面(GUI)设计工具——MFC(Microsoft Foundation Classes),...

    EditPlus 2整理信箱的工具

    【2】 正则表达式应用——数字替换----------------------------Microshaoft@CCF,jiuk2k@CCF 【3】 正则表达式应用——删除每一行行尾的指定字符 【4】 正则表达式应用——替换带有半角括号的多行 【5】 正则表达式...

    MasmforWindows_2015_XiaZaiBa.zip

    MasmforWindows_2015作为2015年版本,集成了编译、调试等功能,使得在Windows环境下编写和测试汇编代码变得更加简便。 首先,集成环境的便利性是MasmforWindows的一大亮点。它将代码编辑器、编译器和调试器整合在一...

    notepad 初学VC++MFC 应用

    MFC是一个基于C++的对象导向框架,它将Windows的消息机制、窗口、控件等抽象为类,让开发者可以通过继承和对象实例化的方式来实现Windows程序。例如,CWinApp是MFC中的应用类,它是每个MFC应用程序的基础,负责应用...

    editplus 代码编辑器html c++ jsp css

    —————————————————— 文章或者技巧及原始作者或出处: 正则表达式类 【1】 正则表达式应用——替换指定内容到行尾 【2】 正则表达式应用——数字替换—————————-Microshaoft,jiuk2k 【3】...

    MFC框架下的外挂程序

    本主题聚焦于"MFC框架下的外挂程序",即如何利用MFC库来创建一个能够在运行时与主应用程序交互的外部模块——外挂程序。外挂程序通常用于扩展或修改主程序的功能,而无需对主程序代码进行修改。 外挂程序通常采用...

    VBIC卡管理系统(源代码+系统+中英文翻译+答辩PPT).rar

    它是向评审团或教师展示项目成果的关键工具,通常包含项目背景、目标、技术实现、性能测试和未来展望等内容。通过PPT,用户可以快速了解整个项目的概览和重点。 总的来说,"VBIC卡管理系统"是一个全面的VBA学习资源...

    Editplus 3[1].0

    【2】 正则表达式应用——数字替换----------------------------Microshaoft@CCF,jiuk2k@CCF 【3】 正则表达式应用——删除每一行行尾的指定字符 【4】 正则表达式应用——替换带有半角括号的多行 【5】 正则表达式...

    vc++教程

    - 性能监控与测试。 **知识点17:构建ActiveX控件** - **描述**:指导如何开发自己的ActiveX控件。 - **核心内容**: - 控件的生命周期管理; - 设计时与运行时的行为差异; - 控件的注册与部署; - 与宿主...

    红外遥控及点阵显示器件的应用-C语言版

    ### 红外遥控及点阵显示器件的应用——C语言版 #### 1. 软件介绍 ##### 1.1 Proteus软件介绍 Proteus ISIS是英国Labcenter公司开发的一款强大的电路分析与实物仿真软件。它支持在Windows操作系统上运行,能够仿真...

Global site tag (gtag.js) - Google Analytics