您的位置:首页 > 运维架构

利用OpenMP提升效率

2011-03-28 00:07 399 查看
// 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 <list>
#include <string>
#include <vector>
#include <fstream>

// 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<std::string> m_lFileNameList;
//static std::ofstream m_fs;
static std::list<Statistic*> 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<std::string>  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<Accumulative*>   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 <omp.h>
#include "Statistic.h"
#include <algorithm>
#include <iostream>
#include <stdarg.h>
#include <cstring>

// Static Class Members
std::list<std::string> Statistic::m_lFileNameList;
std::list<Statistic*> 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<std::string>::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<Statistic*>::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<std::string>::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<Accumulative*>::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 <omp.h>
#include <iostream>
#include <windows.h>
#include "Statistic.h"
#include <ctime>

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. 感觉改进一下程序的话,性能还可以有所提升!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: