<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef TOOLS_STATSFILE_H
#define TOOLS_STATSFILE_H
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <unistd.h>
#include <assert.h>
#include <omp.h>
class StatsCache
{
public:
typedef std::pair<std::string, std::string> strpair_type;
typedef std::vector<strpair_type> statsvec_type;
private:
statsvec_type m_statsvec;
std::string m_thiskey;
std::ostringstream m_curritem;
public:
void clear()
{
m_statsvec.clear();
m_thiskey.clear();
m_curritem.str("");
}
template <typename Type>
StatsCache& operator>> (const Type& t)
{
if (m_thiskey.size())
{
m_statsvec.push_back( strpair_type(m_thiskey, m_curritem.str()) );
m_thiskey.clear();
m_curritem.str("");
}
m_curritem << t;
return *this;
}
template <typename Type>
StatsCache& operator<< (const Type& t)
{
if (m_thiskey.size() == 0)
{
m_thiskey = m_curritem.str();
assert(m_thiskey.size() && "Key is empty!");
m_curritem.str("");
}
m_curritem << t;
return *this;
}
const statsvec_type& get_statsvec()
{
if (m_thiskey.size())
{
m_statsvec.push_back( strpair_type(m_thiskey, m_curritem.str()) );
m_thiskey.clear();
m_curritem.str("");
}
return m_statsvec;
}
};
class StatsWriter
{
private:
std::ofstream m_out;
unsigned int m_firstfield;
std::ostringstream m_line;
public:
StatsWriter(const char* filename)
{
m_out.open(filename, std::ios::app);
m_line << "RESULT\t";
char datetime[64];
time_t tnow = time(NULL);
strftime(datetime,sizeof(datetime),"%Y-%m-%d %H:%M:%S", localtime(&tnow));
m_line << "datetime=" << datetime;
char hostname[128];
gethostname(hostname, sizeof(hostname));
m_line << "\thost=" << hostname;
}
~StatsWriter()
{
m_out << m_line.str() << "\n";
std::cout << m_line.str() << "\n";
}
template <typename Type>
StatsWriter& operator>> (const Type& t)
{
m_firstfield = 1;
m_line << "\t" << t;
return *this;
}
template <typename Type>
StatsWriter& operator<< (const Type& t)
{
if (m_firstfield) {
m_line << "=";
m_firstfield = 0;
}
m_line << t;
return *this;
}
void append_stats(StatsCache& sc)
{
const StatsCache::statsvec_type& sm = sc.get_statsvec();
for (StatsCache::statsvec_type::const_iterator si = sm.begin();
si != sm.end(); ++si)
{
m_line << "\t" << si->first << "=" << si->second;
}
}
};
class SizeLogger
{
private:
std::ofstream m_logfile;
double m_begintime;
double m_endtime;
double m_avgcount;
double m_avgsum;
static inline double timestamp() {
return omp_get_wtime();
}
public:
SizeLogger(const char* logname)
: m_logfile(logname, std::ios::app),
m_begintime(0)
{
}
SizeLogger& operator<< (unsigned long value)
{
double thistime = timestamp();
if (m_begintime == 0)
{
m_begintime = m_endtime = thistime;
m_avgcount = 1;
m_avgsum = value;
}
else if (m_begintime - thistime > 0.01 || m_avgcount >= 1000)
{
m_logfile << std::setprecision(16) << ((m_begintime + m_endtime) / 2.0) << " "
<< std::setprecision(16) << (m_avgsum / m_avgcount) << " " << m_avgcount << "\n";
m_begintime = m_endtime = thistime;
m_avgcount = 1;
m_avgsum = value;
}
else
{
m_endtime = thistime;
m_avgcount++;
m_avgsum += value;
}
return *this;
}
~SizeLogger()
{
if (m_begintime != 0)
{
m_logfile << std::setprecision(16) << ((m_begintime + m_endtime) / 2.0) << " "
<< std::setprecision(16) << (m_avgsum / m_avgcount) << " " << m_avgcount << "\n";
}
}
};
template <clockid_t clk_id>
class MeasureTime
{
private:
struct timespec m_tp1, m_tp2;
public:
inline double resolution() const
{
struct timespec tp_res;
if (clock_getres(clk_id, &tp_res)) {
perror("Could not clock_getres()");
return -1;
}
return tp_res.tv_sec + tp_res.tv_nsec / 1e9;
}
inline void start()
{
if (clock_gettime(clk_id, &m_tp1)) {
perror("Could not clock_gettime()");
}
}
inline void stop()
{
if (clock_gettime(clk_id, &m_tp2)) {
perror("Could not clock_gettime()");
}
}
inline double delta()
{
return (m_tp2.tv_sec - m_tp1.tv_sec)
+ (m_tp2.tv_nsec - m_tp1.tv_nsec) / 1e9;
}
};
class TimerArray
{
private:
struct timespec m_tplast;
unsigned int m_tmcurr;
std::vector<struct timespec> m_tpvector;
public:
TimerArray(unsigned int timers)
{
m_tplast.tv_sec = m_tplast.tv_nsec = 0;
m_tpvector.resize(timers, m_tplast);
clear();
}
void clear()
{
m_tplast.tv_sec = m_tplast.tv_nsec = 0;
std::fill(m_tpvector.begin(), m_tpvector.end(), m_tplast);
m_tmcurr = 0;
if (clock_gettime(CLOCK_MONOTONIC, &m_tplast)) {
perror("Could not clock_gettime(CLOCK_MONOTONIC)");
}
}
inline void change(unsigned int tm)
{
assert(tm < m_tpvector.size());
struct timespec tpnow;
if (clock_gettime(CLOCK_MONOTONIC, &tpnow)) {
perror("Could not clock_gettime(CLOCK_MONOTONIC)");
}
m_tpvector[ m_tmcurr ].tv_sec += tpnow.tv_sec - m_tplast.tv_sec;
m_tpvector[ m_tmcurr ].tv_nsec += tpnow.tv_nsec - m_tplast.tv_nsec;
m_tplast = tpnow;
m_tmcurr = tm;
}
inline double get(unsigned int tm)
{
assert(tm < m_tpvector.size());
return (m_tpvector[tm].tv_sec + m_tpvector[tm].tv_nsec / 1e9);
}
};
class TimerArrayDummy
{
public:
TimerArrayDummy(unsigned int )
{
}
void clear()
{
}
inline void change(unsigned int )
{
}
inline double get(unsigned int )
{
return 0;
}
};
<pid>
struct SMapsInfo
{
size_t size, rss, pss;
size_t referenced, anonymous, locked;
void read()
{
size = rss = pss = 0;
referenced = anonymous = locked = 0;
std::ifstream in("/proc/self/smaps");
std::string line;
while ( std::getline(in, line) )
{
unsigned long mem_from, mem_to, mem_size;
char mem_info[65];
if (sscanf(line.c_str(), "%lx-%lx", &mem_from, &mem_to) == 2) {
}
else if (sscanf(line.c_str(), "%64[^:]: %lu kB", mem_info, &mem_size) == 2)
{
std::string info = mem_info;
if (info == "Size") size += mem_size;
else if (info == "Rss") rss += mem_size;
else if (info == "Pss") pss += mem_size;
else if (info == "Referenced") referenced += mem_size;
else if (info == "Anonymous") anonymous += mem_size;
else if (info == "Locked") locked += mem_size;
else {
}
}
}
}
};
static inline size_t smaps_delta(const size_t& start, const size_t& end)
{
if (end < start) return 0;
else return end - start;
}
static inline void smaps_delta_stats(StatsCache& stats, const SMapsInfo& start, const SMapsInfo& end)
{
stats >> "mem_size" << smaps_delta(start.size, end.size)
>> "mem_rss" << smaps_delta(start.rss, end.rss)
>> "mem_pss" << smaps_delta(start.pss, end.pss)
>> "mem_referenced" << smaps_delta(start.referenced, end.referenced)
>> "mem_anonymous" << smaps_delta(start.anonymous, end.anonymous)
>> "mem_locked" << smaps_delta(start.locked, end.locked);
}
#endif