netgen/libsrc/core/profiler.hpp

351 lines
9.3 KiB
C++
Raw Normal View History

2019-01-03 19:54:50 +05:00
#ifndef NETGEN_CORE_PROFILER_HPP
#define NETGEN_CORE_PROFILER_HPP
#include <array>
2019-01-03 19:54:50 +05:00
#include <chrono>
2020-11-19 00:20:35 +05:00
#include <functional>
2019-01-03 19:54:50 +05:00
#include <string>
2021-05-30 21:32:42 +05:00
#include "array.hpp"
2019-01-03 19:54:50 +05:00
#include "logging.hpp"
#include "paje_trace.hpp"
2021-05-30 21:32:42 +05:00
#include "taskmanager.hpp"
2019-01-03 19:54:50 +05:00
#include "utils.hpp"
namespace ngcore
{
class NgProfiler
{
public:
/// maximal number of timers
enum { SIZE = 8*1024 };
struct TimerVal
{
TimerVal() = default;
double tottime = 0.0;
2019-10-01 16:18:24 +05:00
TTimePoint starttime=0;
2019-01-03 19:54:50 +05:00
double flops = 0.0;
double loads = 0.0;
double stores = 0.0;
long count = 0;
std::string name = "";
int usedcounter = 0;
};
2019-01-07 15:26:46 +05:00
NGCORE_API static std::vector<TimerVal> timers;
2019-01-03 19:54:50 +05:00
NGCORE_API static TTimePoint * thread_times;
NGCORE_API static TTimePoint * thread_flops;
2019-01-16 18:33:48 +05:00
NGCORE_API static std::shared_ptr<Logger> logger;
NGCORE_API static std::array<size_t, NgProfiler::SIZE> dummy_thread_times;
NGCORE_API static std::array<size_t, NgProfiler::SIZE> dummy_thread_flops;
2019-01-03 19:54:50 +05:00
private:
NGCORE_API static std::string filename;
2019-01-03 19:54:50 +05:00
public:
NgProfiler();
~NgProfiler();
NgProfiler(const NgProfiler &) = delete;
NgProfiler(NgProfiler &&) = delete;
void operator=(const NgProfiler &) = delete;
void operator=(NgProfiler &&) = delete;
static void SetFileName (const std::string & afilename) { filename = afilename; }
/// create new timer, use integer index
NGCORE_API static int CreateTimer (const std::string & name);
NGCORE_API static void Reset ();
/// start timer of index nr
static void StartTimer (int nr)
{
2019-10-01 16:18:24 +05:00
timers[nr].starttime = GetTimeCounter(); timers[nr].count++;
2019-01-03 19:54:50 +05:00
}
/// stop timer of index nr
static void StopTimer (int nr)
{
2019-10-01 16:18:24 +05:00
timers[nr].tottime += (GetTimeCounter()-timers[nr].starttime)*seconds_per_tick;
2019-01-03 19:54:50 +05:00
}
static void StartThreadTimer (size_t nr, size_t tid)
{
2019-01-07 15:26:46 +05:00
thread_times[tid*SIZE+nr] -= GetTimeCounter(); // NOLINT
2019-01-03 19:54:50 +05:00
}
static void StopThreadTimer (size_t nr, size_t tid)
{
2019-01-07 15:26:46 +05:00
thread_times[tid*SIZE+nr] += GetTimeCounter(); // NOLINT
2019-01-03 19:54:50 +05:00
}
static void AddThreadFlops (size_t nr, size_t tid, size_t flops)
{
2019-01-07 15:26:46 +05:00
thread_flops[tid*SIZE+nr] += flops; // NOLINT
2019-01-03 19:54:50 +05:00
}
/// if you know number of flops, provide them to obtain the MFlop - rate
static void AddFlops (int nr, double aflops) { timers[nr].flops += aflops; }
static void AddLoads (int nr, double aloads) { timers[nr].loads += aloads; }
static void AddStores (int nr, double astores) { timers[nr].stores += astores; }
static int GetNr (const std::string & name)
{
for (int i = SIZE-1; i >= 0; i--)
if (timers[i].name == name)
return i;
return -1;
}
static double GetTime (int nr)
{
return timers[nr].tottime;
}
static double GetTime (const std::string & name)
{
for (int i = SIZE-1; i >= 0; i--)
if (timers[i].name == name)
return GetTime (i);
return 0;
}
static long int GetCounts (int nr)
{
return timers[nr].count;
}
static double GetFlops (int nr)
{
return timers[nr].flops;
}
/// change name
static void SetName (int nr, const std::string & name) { timers[nr].name = name; }
static std::string GetName (int nr) { return timers[nr].name; }
/// print profile
2019-01-11 14:34:07 +05:00
NGCORE_API static void Print (FILE * prof);
2019-01-07 15:26:46 +05:00
class RegionTimer
{
int nr;
public:
/// start timer
RegionTimer (int anr) : nr(anr) { NgProfiler::StartTimer(nr); }
/// stop timer
~RegionTimer () { NgProfiler::StopTimer(nr); }
RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete;
RegionTimer(RegionTimer &&) = delete;
void operator=(const RegionTimer &) = delete;
void operator=(RegionTimer &&) = delete;
};
2019-01-03 19:54:50 +05:00
};
template<bool DO_TRACING=true, bool DO_TIMING=true>
class Timer
2019-01-03 19:54:50 +05:00
{
int timernr;
public:
Timer (const std::string & name)
2019-01-03 19:54:50 +05:00
{
timernr = NgProfiler::CreateTimer (name);
}
void SetName (const std::string & name)
{
NgProfiler::SetName (timernr, name);
}
void Start ()
{
Start(TaskManager::GetThreadId());
2019-01-03 19:54:50 +05:00
}
void Stop ()
{
Stop(TaskManager::GetThreadId());
}
void Start (int tid)
{
if(tid==0)
{
if constexpr(DO_TIMING)
NgProfiler::StartTimer (timernr);
if constexpr(DO_TRACING)
if(trace) trace->StartTimer(timernr);
}
else
{
if constexpr(DO_TIMING)
NgProfiler::StartThreadTimer(timernr, tid);
if constexpr(DO_TRACING)
trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
}
void Stop (int tid)
{
if(tid==0)
{
if constexpr(DO_TIMING)
NgProfiler::StopTimer (timernr);
if constexpr(DO_TRACING)
if(trace) trace->StopTimer(timernr);
}
else
{
if constexpr(DO_TIMING)
NgProfiler::StopThreadTimer(timernr, tid);
if constexpr(DO_TRACING)
trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
2019-01-03 19:54:50 +05:00
}
void AddFlops (double aflops)
{
if constexpr(DO_TIMING)
2019-01-03 19:54:50 +05:00
NgProfiler::AddFlops (timernr, aflops);
}
double GetTime () { return NgProfiler::GetTime(timernr); }
long int GetCounts () { return NgProfiler::GetCounts(timernr); }
double GetMFlops ()
{ return NgProfiler::GetFlops(timernr)
/ NgProfiler::GetTime(timernr) * 1e-6; }
operator int () { return timernr; }
};
/**
Timer object.
Start / stop timer at constructor / destructor.
*/
template<bool DO_TRACING, bool DO_TIMING>
2019-01-03 19:54:50 +05:00
class RegionTimer
{
Timer<DO_TRACING, DO_TIMING> & timer;
int tid;
2019-01-03 19:54:50 +05:00
public:
/// start timer
RegionTimer (Timer<DO_TRACING, DO_TIMING> & atimer) : timer(atimer)
{
tid = TaskManager::GetThreadId();
timer.Start(tid);
}
2019-01-03 19:54:50 +05:00
/// stop timer
~RegionTimer () { timer.Stop(tid); }
2019-01-03 19:54:50 +05:00
RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete;
2019-01-07 15:26:46 +05:00
RegionTimer(RegionTimer &&) = delete;
2019-01-03 19:54:50 +05:00
void operator=(const RegionTimer &) = delete;
void operator=(RegionTimer &&) = delete;
};
class ThreadRegionTimer
{
size_t nr;
size_t tid;
public:
/// start timer
ThreadRegionTimer (size_t _nr, size_t _tid) : nr(_nr), tid(_tid)
{ NgProfiler::StartThreadTimer(nr, tid); }
/// stop timer
~ThreadRegionTimer ()
{ NgProfiler::StopThreadTimer(nr, tid); }
ThreadRegionTimer() = delete;
ThreadRegionTimer(ThreadRegionTimer &&) = delete;
ThreadRegionTimer(const ThreadRegionTimer &) = delete;
void operator=(const ThreadRegionTimer &) = delete;
void operator=(ThreadRegionTimer &&) = delete;
};
class RegionTracer
{
int nr;
int thread_id;
int type;
2019-01-03 19:54:50 +05:00
public:
static constexpr int ID_JOB = PajeTrace::Task::ID_JOB;
static constexpr int ID_NONE = PajeTrace::Task::ID_NONE;
static constexpr int ID_TIMER = PajeTrace::Task::ID_TIMER;
RegionTracer() = delete;
RegionTracer(RegionTracer &&) = delete;
RegionTracer(const RegionTracer &) = delete;
void operator=(const RegionTracer &) = delete;
void operator=(RegionTracer &&) = delete;
/// start trace
RegionTracer (int athread_id, int region_id, int id_type = ID_NONE, int additional_value = -1 )
: thread_id(athread_id)
{
if (trace)
trace->StartTask (athread_id, region_id, id_type, additional_value);
type = id_type;
nr = region_id;
2019-01-03 19:54:50 +05:00
}
/// start trace with timer
template<bool DO_TRACING, bool DO_TIMING>
RegionTracer (int athread_id, Timer<DO_TRACING, DO_TIMING> & timer, int additional_value = -1 )
2019-01-03 19:54:50 +05:00
: thread_id(athread_id)
{
nr = timer;
type = ID_TIMER;
2019-01-03 19:54:50 +05:00
if (trace)
trace->StartTask (athread_id, nr, type, additional_value);
2019-01-03 19:54:50 +05:00
}
/// stop trace
~RegionTracer ()
{
if (trace)
trace->StopTask (thread_id, nr, type);
2019-01-03 19:54:50 +05:00
}
};
// Helper function for timings
// Run f() at least min_iterations times until max_time seconds elapsed
// returns minimum runtime for a call of f()
template<typename TFunc>
double RunTiming( TFunc f, double max_time = 0.5, int min_iterations = 10 )
{
// Make sure the whole test run does not exceed maxtime
double tend = WallTime()+max_time;
// warmup
f();
double tres = std::numeric_limits<double>::max();
int iteration = 0;
while(WallTime()<tend || iteration++ < min_iterations)
{
double t = -WallTime();
f();
t += WallTime();
tres = std::min(tres, t);
}
return tres;
}
} // namespace ngcore
// Helper macro to easily add multiple timers in a function for profiling
// Usage: NETGEN_TIMER_FROM_HERE("my_timer_name")
// Effect: define static Timer and RegionTimer with given name and line number
#define NETGEN_TOKEN_CONCAT(x, y) x ## y
#define NETGEN_TOKEN_CONCAT2(x, y) NETGEN_TOKEN_CONCAT(x, y)
#define NETGEN_TIMER_FROM_HERE(name) \
static Timer NETGEN_TOKEN_CONCAT2(timer_, __LINE__)( string(name)+"_"+ToString(__LINE__)); \
RegionTimer NETGEN_TOKEN_CONCAT2(rt_,__LINE__)(NETGEN_TOKEN_CONCAT2(timer_,__LINE__));
2019-01-03 19:54:50 +05:00
#endif // NETGEN_CORE_PROFILER_HPP