// Statistic.h
// Function: sample statistic and acculative statistic
// Author: Qi Huaheng
// Create: 2010.08.35
// Copyright © 2010 - 2012 Qi Huaheng. All Rights Reserved
#ifndef STATISTIC_H_INCLUDED #define STATISTIC_H_INCLUDED #include #include #include #include // macro definition #define MAX_SIZE 128 // Abstract Base Statistic Class Definition class Statistic { protected: std::string m_sStatName; std::string m_sStatFileName; bool m_bEnable; std::ofstream m_fs; static std::list m_lFileNameList; //static std::ofstream m_fs; static std::list m_lStatList; public: Statistic(); Statistic(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName = ""); virtual ~Statistic(); void setEnable(bool bEnable) { m_bEnable = bEnable; } void setStatName(const std::string sStatName); void setStatFileName(const std::string sFileName); virtual void createStatFile(const std::string sFileName, const std::string sTitle); // pure virtual function virtual void record(char* str, ...) = 0; virtual void writeFile() = 0; static void flushAllStatistic(); }; class Sample : public Statistic { protected: std::list m_lSampleValues; public: Sample(); Sample(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName = ""); ~Sample(); void record(char* str, ...); void writeFile(); }; class Accumulative; class StatGroup : public Statistic { protected: std::vector m_vAccGroup; public: StatGroup(); StatGroup(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName = ""); ~StatGroup(); void pushInGroup(int num, ...); void record(char* str, ...) {} // this function is useless. void writeFile(); }; class Accumulative { protected: double m_dValue; bool m_bEnable; public: Accumulative():m_dValue(0), m_bEnable(false) {} Accumulative(bool bEnable):m_dValue(0), m_bEnable(bEnable) {} ~Accumulative() {} void setValue(double dValue) { m_dValue = dValue; } double getValue() { return m_dValue; } void record(double dValue) { if(m_bEnable) m_dValue += dValue; } void reset() { m_dValue = 0; } }; #endif // STATISTIC_H_INCLUDED
// Statistic.cpp
// Function: sample statistic and acculative statistic
// Author: Qi Huaheng
// Create: 2010.08.35
// Copyright © 2010 - 2012 Qi Huaheng. All Rights Reserved
/** * Statistic.cpp * The implementation of Statistic Function * * Author: Qi Huaheng * Date: 2010-11-20 * Version: v0.0 * */ #pragma warning(disable: 4786) #include #include "Statistic.h" #include #include #include #include // Static Class Members std::list Statistic::m_lFileNameList; std::list Statistic::m_lStatList; //std::ofstream Statistic::m_fs; // Class Implementation Statistic::Statistic() { m_sStatName = "unknown"; m_sStatFileName = "default.txt"; m_bEnable = false; #pragma omp critical (stat) { m_lStatList.push_back(this); } } Statistic::Statistic(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName) { if(!bEnable) { return; } m_bEnable = bEnable; // set statistic name setStatName(sStatName); #pragma omp critical (stat) { // create statistic file createStatFile(sStatFileName, sTitle); m_lStatList.push_back(this); } } Statistic::~Statistic() { #pragma omp critical (stat) { // close file if (m_fs.is_open()) { m_fs.close(); } // do some clean-up if(this != NULL) { delete this; m_lStatList.remove(this); } } } void Statistic::setStatName(const std::string sStatName) { // set statistic name if(sStatName.empty()) m_sStatName = "unknown"; else m_sStatName = sStatName; } void Statistic::setStatFileName(const std::string sFileName) { // set statistic file name if(sFileName.empty()) m_sStatFileName = "default.txt"; else m_sStatFileName = sFileName; } void Statistic::createStatFile(const std::string sFileName, const std::string sTitle) { // set statistic file name setStatFileName(sFileName); // judge whether open file or not if (m_fs.is_open()) { m_fs.close(); } // open statistic files std::list::iterator iter; iter = std::find(m_lFileNameList.begin(), m_lFileNameList.end(), m_sStatFileName); if(iter == m_lFileNameList.end()) { m_fs.open(m_sStatFileName.c_str(), std::ios::out); if(!m_fs.is_open()) { std::cerr << "Unable to create statistic file! Exit now.../n"; exit(0); } //outStream << m_sStatName << "/t" << sTitle << "/n"; m_fs << sTitle << std::endl; } else { m_fs.open(m_sStatFileName.c_str(), std::ios::app); if(!m_fs.is_open()) { std::cerr << "Unable to open statistic file! Exit now.../n"; exit(0); } } m_fs.flush(); } void Statistic::flushAllStatistic() { if(!m_lStatList.empty()) { for(std::list::iterator iter = m_lStatList.begin(); iter != m_lStatList.end(); iter++) { if(*iter != NULL) (*iter)->writeFile(); } } } /**-----------------------------------------------------------------**/ Sample::Sample():Statistic() {} Sample::Sample(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName) :Statistic(bEnable, sStatName, sTitle, sStatFileName) {} Sample::~Sample() { #pragma omp critical (stat) { if (m_fs.is_open()) { m_fs.close(); } m_lStatList.remove(this); } } void Sample::record(char* str, ...) { if(!m_bEnable) { return; } char cValue[MAX_SIZE]; memset(cValue, 0, MAX_SIZE); std::string sValue; va_list va; va_start(va, str); while((*str) != '/0') { if(*str == '%') { str++; if(*str == 'd') sprintf_s(cValue, "%d", va_arg(va, int)); else if(*str == 'f') sprintf_s(cValue, "%f", va_arg(va, double)); else if(*str == 'e') sprintf_s(cValue, "%d", va_arg(va, int)); else if(*str == 'b') sprintf_s(cValue, "%d", va_arg(va, int)); sValue += cValue; sValue += "/t"; } str++; } va_end(va); m_lSampleValues.push_back(sValue); #pragma omp critical (size) { if (m_lSampleValues.size() == 100) { writeFile(); } } } void Sample::writeFile() { if(!m_bEnable) { return; } // output statistic stream #pragma omp critical (record) { std::list::iterator iter; for(iter = m_lSampleValues.begin(); iter != m_lSampleValues.end(); iter++) { m_fs << m_sStatName << "/t" << *iter << std::endl; m_fs.flush(); } } // empty list m_lSampleValues.clear(); } /**------------------------------------------------------------------**/ StatGroup::StatGroup():Statistic() {} StatGroup::StatGroup(bool bEnable, const std::string sStatName, const std::string sTitle, const std::string sStatFileName) :Statistic(bEnable, sStatName, sTitle, sStatFileName) {} StatGroup::~StatGroup() { for (int i = 0; i < m_vAccGroup.size(); ++i) { if (m_vAccGroup[i]) { delete m_vAccGroup[i]; m_vAccGroup[i] = NULL; } } m_vAccGroup.clear(); #pragma omp critical (stat) { if (m_fs.is_open()) { m_fs.close(); } m_lStatList.remove(this); } } void StatGroup::pushInGroup(int num, ...) { va_list va; va_start(va, num); for(int i = 0; i < num; i++) { Accumulative* pAcc = va_arg(va, Accumulative*); if (pAcc != NULL) m_vAccGroup.push_back(pAcc); } va_end(va); } void StatGroup::writeFile() { if(!m_bEnable) { return; } // output record #pragma omp critical (record) { std::streamsize old = m_fs.precision(16); m_fs << m_sStatName << "/t"; std::vector::iterator iter; for(iter = m_vAccGroup.begin(); iter != m_vAccGroup.end(); iter++) { m_fs << (*iter)->getValue() << "/t"; (*iter)->reset(); } m_fs << std::endl; m_fs.flush(); m_fs.precision(old); } }
//main.cpp
#pragma warning(disable: 4786) #include #include #include #include "Statistic.h" #include using namespace std; #define BAD_ALLOCATE {std::cerr << "memory allocating fail. exit now.../n"; exit(0);} int main(int argc, char* argv[]) { cout << omp_get_num_procs() << endl; cout << "Begin program of testing statistic class/n"; // test statistic code // create statistic objects Sample* pS1 = new Sample(true, "S1", "Sample/tA/tB/tC/tD", "sample_1.txt"); Sample* pS11 = new Sample(true, "S2", "Sample/tA/tB/tC/tD", "sample_1.txt"); Sample* pS2 = new Sample(true, "2A", "Sample/tE/tF/tG/tH/tI", "sample_2.txt"); StatGroup* pG1 = new StatGroup(true, "S1", "StatGroup/tA/tB", "group_1.txt"); StatGroup* pG11 = new StatGroup(true, "S2", "StatGroup/tA/tB", "group_1.txt"); StatGroup* pG2 = new StatGroup(true, "2A", "StatGroup/tA/tB/tC", "group_2.txt"); Accumulative* pA10 = new Accumulative(true); Accumulative* pA11 = new Accumulative(true); Accumulative* pA20 = new Accumulative(true); Accumulative* pA21 = new Accumulative(true); Accumulative* pA22 = new Accumulative(true); // check memory allocation if (pS1 == NULL) BAD_ALLOCATE; if (pS11 == NULL) BAD_ALLOCATE; if (pS2 == NULL) BAD_ALLOCATE; if (pG1 == NULL) BAD_ALLOCATE; if (pG11 == NULL) BAD_ALLOCATE; if (pG2 == NULL) BAD_ALLOCATE; if (pA10 == NULL) BAD_ALLOCATE; if (pA11 == NULL) BAD_ALLOCATE; if (pA20 == NULL) BAD_ALLOCATE; if (pA21 == NULL) BAD_ALLOCATE; if (pA22 == NULL) BAD_ALLOCATE; // push group pG1->pushInGroup(2, pA10, pA11); pG11->pushInGroup(2, pA10, pA11); pG2->pushInGroup(3, pA20, pA21, pA22); // statistic long start = clock(); //#pragma omp parallel for for(int i = 0; i < 100; i++) { #pragma omp parallel for for(int j = 0; j < 10000; j++) { pS1->record("%d %d %f %f", i, j, i*2.3, j*4.6); pS11->record("%d %d %f %f", 2*i, 3*j, i*3.4, j*7.7); pS2->record("%d %f %d %f %f", i, i*1.1, j, j*8.1, i*1.1+i*2.4); pA10->record(i); pA11->record(j); pA20->record(i+2.0); pA21->record(j+2.0); pA22->record(i+j+2.0); } } cout << clock()-start << endl; // output statistic files pS1->writeFile(); pS11->writeFile(); pS2->writeFile(); pG1->writeFile(); pG11->writeFile(); pG2->writeFile(); // end program cout << "End testing.../n" << endl; return 0; }
output:
----------------------------------
Single thread:
debug --- 131750 tick
release --- 44710 tick
OpenMP:
debug --- 42340 tick
release --- 10935
可见开启OpenMP后,性能提升了3倍多,哈哈哈,太棒了。
----------------------------------
P.S. 感觉改进一下程序的话,性能还可以有所提升!