Merge branch 'parallel_timing' into 'master'

Thread-safe Timer

See merge request jschoeberl/netgen!392
This commit is contained in:
Joachim Schöberl 2021-06-11 17:03:57 +00:00
commit 44d7207380
5 changed files with 129 additions and 84 deletions

View File

@ -85,8 +85,7 @@ namespace ngcore
for(auto & ltask : tasks) for(auto & ltask : tasks)
for(auto & task : ltask) for(auto & task : ltask)
{ {
task.start_time -= start_time; task.time -= start_time;
task.stop_time -= start_time;
} }
for(auto & job : jobs) for(auto & job : jobs)
{ {
@ -635,23 +634,31 @@ namespace ngcore
value_id = job_task_map[jobs[t.id-1].type]; value_id = job_task_map[jobs[t.id-1].type];
if(trace_thread_counter) if(trace_thread_counter)
{ {
paje.AddVariable( t.start_time, variable_type_active_threads, container_jobs, 1.0 ); if(t.is_start)
paje.SubVariable( t.stop_time, variable_type_active_threads, container_jobs, 1.0 ); paje.AddVariable( t.time, variable_type_active_threads, container_jobs, 1.0 );
else
paje.SubVariable( t.time, variable_type_active_threads, container_jobs, 1.0 );
} }
if(trace_threads) if(trace_threads)
{ {
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true ); if(t.is_start)
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] ); paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true );
else
paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] );
} }
break; break;
case Task::ID_TIMER: case Task::ID_TIMER:
value_id = timer_aliases[t.id]; value_id = timer_aliases[t.id];
paje.PushState( t.start_time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true ); if(t.is_start)
paje.PopState( t.stop_time, state_type_timer, thread_aliases[t.thread_id] ); paje.PushState( t.time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true );
else
paje.PopState( t.time, state_type_timer, thread_aliases[t.thread_id] );
break; break;
default: default:
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false ); if(t.is_start)
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] ); paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false );
else
paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] );
break; break;
} }
} }

View File

@ -79,8 +79,8 @@ namespace ngcore
int additional_value; int additional_value;
TTimePoint start_time; TTimePoint time;
TTimePoint stop_time; bool is_start;
static constexpr int ID_NONE = -1; static constexpr int ID_NONE = -1;
static constexpr int ID_JOB = 1; static constexpr int ID_JOB = 1;
@ -178,23 +178,16 @@ namespace ngcore
if(unlikely(tasks[thread_id].size() == max_num_events_per_thread)) if(unlikely(tasks[thread_id].size() == max_num_events_per_thread))
StopTracing(); StopTracing();
int task_num = tasks[thread_id].size(); int task_num = tasks[thread_id].size();
tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter()} ); tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter(), true} );
return task_num; return task_num;
} }
void StopTask(int thread_id, int task_num) void StopTask(int thread_id, int id, int id_type = Task::ID_NONE)
{ {
if(!trace_threads && !trace_thread_counter) return; if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0) tasks[thread_id].push_back( Task{thread_id, id, id_type, 0, GetTimeCounter(), false} );
tasks[thread_id][task_num].stop_time = GetTimeCounter();
} }
void SetTask(int thread_id, int task_num, int additional_value) {
if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0)
tasks[thread_id][task_num].additional_value = additional_value;
}
void StartJob(int job_id, const std::type_info & type) void StartJob(int job_id, const std::type_info & type)
{ {
if(!tracing_enabled) return; if(!tracing_enabled) return;

View File

@ -148,38 +148,95 @@ namespace ngcore
}; };
struct TNoTracing{ static constexpr bool do_tracing=false; };
struct TTracing{ static constexpr bool do_tracing=true; };
class NGCORE_API Timer struct TNoTiming{ static constexpr bool do_timing=false; };
struct TTiming{ static constexpr bool do_timing=true; };
namespace detail {
template<typename T>
constexpr bool is_tracing_type_v = std::is_same_v<T, TNoTracing> || std::is_same_v<T, TTracing>;
template<typename T>
constexpr bool is_timing_type_v = std::is_same_v<T, TNoTiming> || std::is_same_v<T, TTiming>;
}
static TNoTracing NoTracing;
static TNoTiming NoTiming;
template<typename TTracing=TTracing, typename TTiming=TTiming>
class Timer
{ {
int timernr; int timernr;
int priority; int Init( const std::string & name )
public:
Timer (const std::string & name, int apriority = 1)
: priority(apriority)
{ {
timernr = NgProfiler::CreateTimer (name); return NgProfiler::CreateTimer (name);
} }
public:
static constexpr bool do_tracing = TTracing::do_tracing;
static constexpr bool do_timing = TTiming::do_timing;
Timer (const std::string & name) : timernr(Init(name)) { }
template<std::enable_if_t< detail::is_tracing_type_v<TTracing>, bool> = false>
Timer( const std::string & name, TTracing ) : timernr(Init(name)) { }
template<std::enable_if_t< detail::is_timing_type_v<TTiming>, bool> = false>
Timer( const std::string & name, TTiming ) : timernr(Init(name)) { }
Timer( const std::string & name, TTracing, TTiming ) : timernr(Init(name)) { }
void SetName (const std::string & name) void SetName (const std::string & name)
{ {
NgProfiler::SetName (timernr, name); NgProfiler::SetName (timernr, name);
} }
void Start () void Start () const
{ {
if (priority <= 2) Start(TaskManager::GetThreadId());
NgProfiler::StartTimer (timernr);
if (priority <= 1)
if(trace) trace->StartTimer(timernr);
} }
void Stop () void Stop () const
{ {
if (priority <= 2) Stop(TaskManager::GetThreadId());
NgProfiler::StopTimer (timernr); }
if (priority <= 1) void Start (int tid) const
if(trace) trace->StopTimer(timernr); {
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)
if(trace) trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
}
void Stop (int tid) const
{
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)
if(trace) trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
} }
void AddFlops (double aflops) void AddFlops (double aflops)
{ {
if (priority <= 2) if constexpr(do_timing)
NgProfiler::AddFlops (timernr, aflops); NgProfiler::AddFlops (timernr, aflops);
} }
@ -196,14 +253,21 @@ namespace ngcore
Timer object. Timer object.
Start / stop timer at constructor / destructor. Start / stop timer at constructor / destructor.
*/ */
template<typename TTimer>
class RegionTimer class RegionTimer
{ {
Timer & timer; const TTimer & timer;
int tid;
public: public:
/// start timer /// start timer
RegionTimer (Timer & atimer) : timer(atimer) { timer.Start(); } RegionTimer (const TTimer & atimer) : timer(atimer)
{
tid = TaskManager::GetThreadId();
timer.Start(tid);
}
/// stop timer /// stop timer
~RegionTimer () { timer.Stop(); } ~RegionTimer () { timer.Stop(tid); }
RegionTimer() = delete; RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete; RegionTimer(const RegionTimer &) = delete;
@ -212,29 +276,11 @@ namespace ngcore
void operator=(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 class RegionTracer
{ {
int nr; int nr;
int thread_id; int thread_id;
int type;
public: public:
static constexpr int ID_JOB = PajeTrace::Task::ID_JOB; static constexpr int ID_JOB = PajeTrace::Task::ID_JOB;
static constexpr int ID_NONE = PajeTrace::Task::ID_NONE; static constexpr int ID_NONE = PajeTrace::Task::ID_NONE;
@ -251,28 +297,26 @@ namespace ngcore
: thread_id(athread_id) : thread_id(athread_id)
{ {
if (trace) if (trace)
nr = trace->StartTask (athread_id, region_id, id_type, additional_value); trace->StartTask (athread_id, region_id, id_type, additional_value);
type = id_type;
nr = region_id;
} }
/// start trace with timer /// start trace with timer
RegionTracer (int athread_id, Timer & timer, int additional_value = -1 ) template<typename TTimer>
RegionTracer (int athread_id, TTimer & timer, int additional_value = -1 )
: thread_id(athread_id) : thread_id(athread_id)
{ {
nr = timer;
type = ID_TIMER;
if (trace) if (trace)
nr = trace->StartTask (athread_id, static_cast<int>(timer), ID_TIMER, additional_value); trace->StartTask (athread_id, nr, type, additional_value);
} }
/// set user defined value
void SetValue( int additional_value )
{
if (trace)
trace->SetTask( thread_id, nr, additional_value );
}
/// stop trace /// stop trace
~RegionTracer () ~RegionTracer ()
{ {
if (trace) if (trace)
trace->StopTask (thread_id, nr); trace->StopTask (thread_id, nr, type);
} }
}; };

View File

@ -35,11 +35,7 @@ namespace ngcore
int TaskManager :: num_threads = 1; int TaskManager :: num_threads = 1;
// #ifndef __clang__
thread_local int TaskManager :: thread_id = 0; thread_local int TaskManager :: thread_id = 0;
// #else
// __thread int TaskManager :: thread_id;
// #endif
const function<void(TaskInfo&)> * TaskManager::func; const function<void(TaskInfo&)> * TaskManager::func;
const function<void()> * TaskManager::startup_function = nullptr; const function<void()> * TaskManager::startup_function = nullptr;
@ -174,10 +170,12 @@ namespace ngcore
num_threads = 1; num_threads = 1;
} }
#ifdef WIN32
int TaskManager :: GetThreadId() int TaskManager :: GetThreadId()
{ {
return thread_id; return thread_id;
} }
#endif
void TaskManager :: StartWorkers() void TaskManager :: StartWorkers()
{ {

View File

@ -78,12 +78,11 @@ namespace ngcore
// #ifndef __clang__ #ifdef WIN32 // no exported thread_local in dlls on Windows
static thread_local int thread_id; static thread_local int thread_id;
// #else #else
// static __thread int thread_id; NGCORE_API static thread_local int thread_id;
// #endif #endif
NGCORE_API static bool use_paje_trace; NGCORE_API static bool use_paje_trace;
public: public:
@ -102,11 +101,15 @@ namespace ngcore
void ResumeWorkers() { sleep = false; } void ResumeWorkers() { sleep = false; }
NGCORE_API static void SetNumThreads(int amax_threads); NGCORE_API static void SetNumThreads(int amax_threads);
NGCORE_API static int GetMaxThreads() { return max_threads; } static int GetMaxThreads() { return max_threads; }
// static int GetNumThreads() { return task_manager ? task_manager->num_threads : 1; } // static int GetNumThreads() { return task_manager ? task_manager->num_threads : 1; }
NGCORE_API static int GetNumThreads() { return num_threads; } static int GetNumThreads() { return num_threads; }
#ifdef WIN32
NGCORE_API static int GetThreadId(); NGCORE_API static int GetThreadId();
NGCORE_API int GetNumNodes() const { return num_nodes; } #else
static int GetThreadId() { return thread_id; }
#endif
int GetNumNodes() const { return num_nodes; }
static void SetPajeTrace (bool use) { use_paje_trace = use; } static void SetPajeTrace (bool use) { use_paje_trace = use; }