<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef TOOLS_TIMER_ARRAY_H
#define TOOLS_TIMER_ARRAY_H
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <unistd.h>
#include <assert.h>
#include <omp.h>
class TimerArray
{
private:
struct timespec m_tplast;
unsigned int m_tmcurr;
std::vector<struct timespec> m_tpvector;
public:
static const bool is_real = true;
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:
static const bool is_real = false;
inline TimerArrayDummy(unsigned int )
{ }
inline void clear()
{ }
inline void start(unsigned )
{ }
inline void stop()
{ }
inline void change(unsigned int )
{ }
inline double get(unsigned int )
{
return 0;
}
inline double get_sum() const
{
return 0;
}
};
class TimerArrayMT
{
private:
struct ThreadInfo
{
struct timespec m_tplast;
unsigned int m_tmcurr;
unsigned char m_filler[64 - sizeof(struct timespec) - sizeof(unsigned int)];
} __attribute__((packed));
std::vector<struct timespec> m_timers;
std::vector<ThreadInfo> m_thread;
public:
static const bool is_real = true;
TimerArrayMT(unsigned ntimers)
: m_timers(ntimers)
{ }
void start(unsigned nthreads)
{
struct timespec tp;
memset(&tp, 0, sizeof(tp));
std::fill(m_timers.begin(), m_timers.end(), tp);
if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
perror("Could not clock_gettime(CLOCK_MONOTONIC)");
}
m_thread.resize(nthreads);
for (size_t i = 0; i < m_thread.size(); ++i) {
m_thread[i].m_tplast = tp;
m_thread[i].m_tmcurr = 0;
}
}
void stop()
{
for (size_t t = 0; t < m_thread.size(); ++t) {
change(0, t);
}
}
inline void change(unsigned int tm, unsigned int tid)
{
assert(tm < m_timers.size());
assert(tid < m_thread.size());
struct timespec tpnow;
if (clock_gettime(CLOCK_MONOTONIC, &tpnow)) {
perror("Could not clock_gettime(CLOCK_MONOTONIC)");
}
ThreadInfo& ti = m_thread[tid];
#pragma omp atomic
m_timers[ ti.m_tmcurr ].tv_sec += (tpnow.tv_sec - ti.m_tplast.tv_sec);
#pragma omp atomic
m_timers[ ti.m_tmcurr ].tv_nsec += tpnow.tv_nsec - ti.m_tplast.tv_nsec;
ti.m_tplast = tpnow;
ti.m_tmcurr = tm;
}
inline void change(unsigned int tm)
{
return change(tm, omp_get_thread_num());
}
inline unsigned int get_tmcurr(unsigned int tid)
{
assert(tid < m_thread.size());
return m_thread[tid].m_tmcurr;
}
inline unsigned int get_tmcurr()
{
return get_tmcurr(omp_get_thread_num());
}
inline double get(unsigned int tm) const
{
assert(tm < m_timers.size());
return (m_timers[tm].tv_sec + m_timers[tm].tv_nsec / 1e9);
}
inline double get_sum() const
{
double sum = 0;
for (size_t i = 0; i < m_timers.size(); ++i)
sum += get(i);
return sum;
}
};
class ScopedTimerKeeperMT
{
protected:
TimerArrayMT& m_ta;
unsigned int m_tmprev;
public:
ScopedTimerKeeperMT(TimerArrayMT& ta, unsigned int tm)
: m_ta(ta),
m_tmprev(ta.get_tmcurr())
{
m_ta.change(tm);
}
~ScopedTimerKeeperMT()
{
m_ta.change(m_tmprev);
}
};
class ScopedTimerKeeperDummy
{
public:
template <typename Whatever>
ScopedTimerKeeperDummy(Whatever , unsigned int )
{
}
};
#endif