Rational purify trial性能テスト——(1)

9166 ワード

  • quantifyと単純コードブロックテスト
  • ここ数日、プログラムの性能をテストするのに忙しくて、rationalのquantifyツールに基づいて性能テストを行って、exe、dllファイルをテストすることができて、やはりとても良くて、ibmの公式サイトでダウンロードすることができて、あまり大きくありません.trial版のため、データを保存していません.
     
  • <1>EXE対応、DLL分析
  • <2>Line,function,time分析
  • をサポート
  • <3>はマルチスレッド解析をサポートし、独立してスレッド
  • を解析することができる.
  • <4>結果をグラフィック化し、ツリー呼び出し結果をサポートする.サポート属性リスト方式
  •  
    以前parasoftのテストツールを使ったことがありますが、覚えていません.そのツールはいいと思いました.
     
    quantifyはライン、function、codeを選択できますが、一般的にラインを選択すればいいです.
     
     
    このようなテストツールは、細粒度のテスト状況に基づいて、より直観的または有効な分析論理処理部分ができず、ミクロ分析と考えられる.マクロ解析プログラムのコードブロックも必要です.そのコードブロックの実行回数、時間などがかかります.
     
    Windowsの下の簡単なテストプログラムのコードブロックを書いて、論理からプログラムの性能のソースコードを分析するために交換します;Linuxをサポートする必要がある場合は、タイミング関数を変更すればいいです.
     
    st_stat.h
    #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;}
    	int 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;
    	}
    
    	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) \
    struct st_##name##_test: Runnable { \
    	st_##name##_test(): Runnable(#name) { \
    	test_suite::get_instance().addTest(this); \
    	} \
    } name##_test_instance
    
    #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"st_stat.h"
    
    #ifdef _WIN32
    #include<windows.h>
    void call_stat_begin(st_stat*pstat)
    {
    	pstat->call_count++;
    	LARGE_INTEGER large_integer;
    	BOOL bRet = ::QueryPerformanceCounter(&large_integer);
    	_ASSERT(bRet);
    	pstat->start = large_integer;
    }
    void call_stat_end(st_stat*pstat)
    {
    	LARGE_INTEGER large_integer;
    	BOOL bRet = ::QueryPerformanceCounter(&large_integer);
    	_ASSERT(bRet);
    	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
    "); 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(),"w+"); } else { fp=fopen("test_performance.csv","w+"); } 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

     
    使い方も簡単
    開始時:
    STAT_GLOBAL_INIT(「ファイルパス」);1回実行
     
    終了時:
    STAT_GLOBAL_FINISH()
    この2つのマクロ、特に最後のマクロは、最適化された後、この呼び出しを省略し、INITと維持するために加算されます.
    再最適化する場合、INITとFINISHはデフォルトで省略できるので、より簡潔明瞭になります.
     
    次のように呼び出されます.
    STAT_TEST_BEGIN(「テスト名」);
    XXXXXX;テストコード
    STAT_TEST_END(「テスト名」);
     
  • 結果分析
  • 初歩的なQuantifyテストの結果、私の既存のプログラムは以下の問題を得た.
    (1)std:string構造と破棄、時間がかかりすぎる
    (2)mallocとdeleteの呼び出し回数が多すぎて時間がかかる
    そのため、初歩的にミクロから見ると、主に頻繁な文字列操作であり、小さなオブジェクトの分配回収もある.
    基本的にシナリオを決定できます.処理文字列を最適化する必要があり、メモリプールを使用して小さなオブジェクトを管理する必要があります.
     
    プログラム論理テストの結果に基づいて:
     
     
    関数名
    呼び出し回数
    呼び出し時間Performance Counter
    start Tick Count=16480171 ms
     
     AddLineGraphToMemory
    2043768
    842106440
    AddRegionGraphToMemory
    317901
    1462981839
    GetShapeFeatureValue
    8739066
    0
     
     
     
    LINE_切り取り
    2043768
    359172490
    OutPutReulstFile
    70
    347857107
    REGION_切り取り
    274746
    -985524651
    ReadEveryShapeFile
    3702
    1332493360
    ReadEveryTabFile
    249
    1898886781
     
    上の論理マクロテスト結果、REGION_カットとAddRegionGraphToMemoryの時間がかかりすぎて、この論理は追加の配慮が必要です.へへへ!
     
  • 次:
  • (1)このテストコードを豊富にして、ユニットテストをサポートさせて、ある関数をテストすることができます.
    (2)バグを修正し、時間が長すぎると負数が出る