#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是一个广泛使用的2D游戏开发框架,它基于C++,支持跨平台开发,包括iOS、Android以及Windows等多个操作系统。本教程将详细介绍如何在Visual Studio 2010环境下,利用cocos2d-x构建一款经典...
VCT——SYS中可能包含了定制的VC项目模板、宏定义、库函数以及对Windows API的扩展,使得开发者在编写C++代码时能更好地适应华东地区的系统环境。VC的特性,如性能优化、内存管理以及对Windows操作系统的深度集成,...
《深入解析:基于VS2010 MFC的日志记录类——log4z》 在软件开发中,日志记录是不可或缺的一部分,它能够帮助开发者追踪程序运行过程中的错误、调试问题以及监控系统状态。本篇文章将围绕"VS2010 MFC写的log4z日志...
Qt以其强大的功能、丰富的库支持和美观的GUI设计而闻名,而MFC则是微软为Windows应用程序开发提供的C++库,基于Windows API。在某些情况下,开发者可能需要将现有的MFC项目迁移到Qt环境,或者相反,将Qt项目集成到...
1. **框架类**:MFC中的类大部分是基于Windows API设计的,如CWinApp、CWnd、CButton等,它们提供了对窗口、按钮等控件的封装。 2. **消息映射**:MFC使用消息映射机制,将Windows消息与成员函数关联,简化了事件...
C#中的`NUnit`和C语言的`gcc`自带的`assert()`宏可以辅助进行测试。 10. **可视化**:为了更好地理解模拟过程和结果,可以使用C#的`System.Windows.Forms.DataVisualization.Charting`库或C语言的`gnuplot`等工具...
**汽车客运公司售票系统——基于MFC的实现** 在信息技术高度发达的今天,各种软件系统已经深入到各行各业,包括交通管理领域。汽车客运公司售票系统是这类应用的一个实例,它利用计算机技术,实现了对汽车票务的...
在1.12.1这个版本中,STM32CubeIDE引入了一个重要的特性——自动补全代码功能。 自动补全代码是现代IDE中的一个核心功能,它能够提高程序员的编写效率,减少错误。在STM32CubeIDE 1.12.1中,这一功能意味着用户在...
【课程设计——通讯录(C++)——基于MFC】是一项常见的编程实践任务,旨在让学生掌握面向对象编程和用户界面设计的基本技能。MFC(Microsoft Foundation Classes)是微软提供的一套C++库,用于简化Windows应用程序...
Visual C++6.0是Microsoft公司推出的一款强大的C++开发工具,它集成了编译器、调试器以及各种辅助开发工具,支持Windows API,提供了直观的图形用户界面(GUI)设计工具——MFC(Microsoft Foundation Classes),...
【2】 正则表达式应用——数字替换----------------------------Microshaoft@CCF,jiuk2k@CCF 【3】 正则表达式应用——删除每一行行尾的指定字符 【4】 正则表达式应用——替换带有半角括号的多行 【5】 正则表达式...
MasmforWindows_2015作为2015年版本,集成了编译、调试等功能,使得在Windows环境下编写和测试汇编代码变得更加简便。 首先,集成环境的便利性是MasmforWindows的一大亮点。它将代码编辑器、编译器和调试器整合在一...
MFC是一个基于C++的对象导向框架,它将Windows的消息机制、窗口、控件等抽象为类,让开发者可以通过继承和对象实例化的方式来实现Windows程序。例如,CWinApp是MFC中的应用类,它是每个MFC应用程序的基础,负责应用...
—————————————————— 文章或者技巧及原始作者或出处: 正则表达式类 【1】 正则表达式应用——替换指定内容到行尾 【2】 正则表达式应用——数字替换—————————-Microshaoft,jiuk2k 【3】...
本主题聚焦于"MFC框架下的外挂程序",即如何利用MFC库来创建一个能够在运行时与主应用程序交互的外部模块——外挂程序。外挂程序通常用于扩展或修改主程序的功能,而无需对主程序代码进行修改。 外挂程序通常采用...
它是向评审团或教师展示项目成果的关键工具,通常包含项目背景、目标、技术实现、性能测试和未来展望等内容。通过PPT,用户可以快速了解整个项目的概览和重点。 总的来说,"VBIC卡管理系统"是一个全面的VBA学习资源...
【2】 正则表达式应用——数字替换----------------------------Microshaoft@CCF,jiuk2k@CCF 【3】 正则表达式应用——删除每一行行尾的指定字符 【4】 正则表达式应用——替换带有半角括号的多行 【5】 正则表达式...
- 性能监控与测试。 **知识点17:构建ActiveX控件** - **描述**:指导如何开发自己的ActiveX控件。 - **核心内容**: - 控件的生命周期管理; - 设计时与运行时的行为差异; - 控件的注册与部署; - 与宿主...
### 红外遥控及点阵显示器件的应用——C语言版 #### 1. 软件介绍 ##### 1.1 Proteus软件介绍 Proteus ISIS是英国Labcenter公司开发的一款强大的电路分析与实物仿真软件。它支持在Windows操作系统上运行,能够仿真...