From a11294baf0889362d4072e574f689e73a8e3f8b4 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Jun 2021 09:51:23 +0200 Subject: [PATCH 1/4] inline GetThreadI() (except on Windows, no dllexport for thread_local variables supported) --- libsrc/core/taskmanager.cpp | 6 ++---- libsrc/core/taskmanager.hpp | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index 1d88b766..9274fb97 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -35,11 +35,7 @@ namespace ngcore int TaskManager :: num_threads = 1; - // #ifndef __clang__ thread_local int TaskManager :: thread_id = 0; - // #else - // __thread int TaskManager :: thread_id; - // #endif const function * TaskManager::func; const function * TaskManager::startup_function = nullptr; @@ -174,10 +170,12 @@ namespace ngcore num_threads = 1; } +#ifdef WIN32 int TaskManager :: GetThreadId() { return thread_id; } +#endif void TaskManager :: StartWorkers() { diff --git a/libsrc/core/taskmanager.hpp b/libsrc/core/taskmanager.hpp index 27de9090..8d2886b1 100644 --- a/libsrc/core/taskmanager.hpp +++ b/libsrc/core/taskmanager.hpp @@ -78,12 +78,11 @@ namespace ngcore - // #ifndef __clang__ +#ifdef WIN32 // no exported thread_local in dlls on Windows static thread_local int thread_id; - // #else - // static __thread int thread_id; - // #endif - +#else + NGCORE_API static thread_local int thread_id; +#endif NGCORE_API static bool use_paje_trace; public: @@ -102,11 +101,15 @@ namespace ngcore void ResumeWorkers() { sleep = false; } 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; } - NGCORE_API static int GetNumThreads() { return num_threads; } + static int GetNumThreads() { return num_threads; } +#ifdef WIN32 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; } From c5639a5706ea567da4b87335c2f09cc20ab7e2b8 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Jun 2021 09:52:58 +0200 Subject: [PATCH 2/4] Thread-safe Timer - use template arguments instead of run-time variable 'priority' - change in paje interface for tracing --- libsrc/core/paje_trace.cpp | 27 +++++++----- libsrc/core/paje_trace.hpp | 17 +++----- libsrc/core/profiler.hpp | 87 ++++++++++++++++++++++++++------------ 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 56fb0c12..eb0dd06d 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -85,8 +85,7 @@ namespace ngcore for(auto & ltask : tasks) for(auto & task : ltask) { - task.start_time -= start_time; - task.stop_time -= start_time; + task.time -= start_time; } for(auto & job : jobs) { @@ -635,23 +634,31 @@ namespace ngcore value_id = job_task_map[jobs[t.id-1].type]; if(trace_thread_counter) { - paje.AddVariable( t.start_time, variable_type_active_threads, container_jobs, 1.0 ); - paje.SubVariable( t.stop_time, variable_type_active_threads, container_jobs, 1.0 ); + if(t.is_start) + 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) { - paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true ); - paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] ); + if(t.is_start) + 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; case Task::ID_TIMER: 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 ); - paje.PopState( t.stop_time, state_type_timer, thread_aliases[t.thread_id] ); + if(t.is_start) + 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; default: - paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false ); - paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] ); + if(t.is_start) + 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; } } diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 5444a96c..c85c040f 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -79,8 +79,8 @@ namespace ngcore int additional_value; - TTimePoint start_time; - TTimePoint stop_time; + TTimePoint time; + bool is_start; static constexpr int ID_NONE = -1; static constexpr int ID_JOB = 1; @@ -178,23 +178,16 @@ namespace ngcore if(unlikely(tasks[thread_id].size() == max_num_events_per_thread)) StopTracing(); 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; } - 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(task_num>=0) - tasks[thread_id][task_num].stop_time = GetTimeCounter(); + tasks[thread_id].push_back( Task{thread_id, id, id_type, 0, GetTimeCounter(), false} ); } - 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) { if(!tracing_enabled) return; diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index 294928d3..e6795f69 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -149,13 +149,12 @@ namespace ngcore - class NGCORE_API Timer + template + class Timer { int timernr; - int priority; public: - Timer (const std::string & name, int apriority = 1) - : priority(apriority) + Timer (const std::string & name) { timernr = NgProfiler::CreateTimer (name); } @@ -165,21 +164,49 @@ namespace ngcore } void Start () { - if (priority <= 2) - NgProfiler::StartTimer (timernr); - if (priority <= 1) - if(trace) trace->StartTimer(timernr); + Start(TaskManager::GetThreadId()); } void Stop () { - if (priority <= 2) - NgProfiler::StopTimer (timernr); - if (priority <= 1) - if(trace) trace->StopTimer(timernr); + 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); + } } void AddFlops (double aflops) { - if (priority <= 2) + if constexpr(DO_TIMING) NgProfiler::AddFlops (timernr, aflops); } @@ -196,14 +223,21 @@ namespace ngcore Timer object. Start / stop timer at constructor / destructor. */ + template class RegionTimer { - Timer & timer; + Timer & timer; + int tid; public: /// start timer - RegionTimer (Timer & atimer) : timer(atimer) { timer.Start(); } + RegionTimer (Timer & atimer) : timer(atimer) + { + tid = TaskManager::GetThreadId(); + timer.Start(tid); + } + /// stop timer - ~RegionTimer () { timer.Stop(); } + ~RegionTimer () { timer.Stop(tid); } RegionTimer() = delete; RegionTimer(const RegionTimer &) = delete; @@ -235,6 +269,7 @@ namespace ngcore { int nr; int thread_id; + int type; public: static constexpr int ID_JOB = PajeTrace::Task::ID_JOB; static constexpr int ID_NONE = PajeTrace::Task::ID_NONE; @@ -251,28 +286,26 @@ namespace ngcore : thread_id(athread_id) { 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 - RegionTracer (int athread_id, Timer & timer, int additional_value = -1 ) + template + RegionTracer (int athread_id, Timer & timer, int additional_value = -1 ) : thread_id(athread_id) { + nr = timer; + type = ID_TIMER; if (trace) - nr = trace->StartTask (athread_id, static_cast(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 ~RegionTracer () { if (trace) - trace->StopTask (thread_id, nr); + trace->StopTask (thread_id, nr, type); } }; From 6f7543c7dc2964e89439ab7f70c336046f06ac23 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Jun 2021 10:08:06 +0200 Subject: [PATCH 3/4] Timer - convenience constructors to disable tracing and/or timing Examples: Timer t0("name"); Timer t1("name", NoTracing); Timer t2("name", NoTiming); Timer t3("name", NoTracing, NoTiming); Timer t4("name", NoTiming, NoTracing); --- libsrc/core/profiler.hpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index e6795f69..b8bd09e8 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -148,16 +148,42 @@ namespace ngcore }; + namespace detail { + struct NoTracing_t{}; + struct NoTiming_t{}; + } + + static detail::NoTracing_t NoTracing; + static detail::NoTiming_t NoTiming; template class Timer { int timernr; - public: - Timer (const std::string & name) + int Init( const std::string & name ) { - timernr = NgProfiler::CreateTimer (name); + return NgProfiler::CreateTimer (name); } + public: + Timer (const std::string & name) : timernr(Init(name)) + { } + + template> + Timer( const std::string & name, detail::NoTracing_t ) : timernr(Init(name)) + { } + + template> + Timer( const std::string & name, detail::NoTiming_t ) : timernr(Init(name)) + { } + + template> + Timer( const std::string & name, detail::NoTracing_t, detail::NoTiming_t ) : timernr(Init(name)) + { } + + template> + Timer( const std::string & name, detail::NoTiming_t, detail::NoTracing_t ) : timernr(Init(name)) + { } + void SetName (const std::string & name) { NgProfiler::SetName (timernr, name); From 1de1a1800e5709d35908fd331a1c70c516ededff Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 11 Jun 2021 12:01:38 +0200 Subject: [PATCH 4/4] Fix template argument deduction for Timer, remove ThreadRegionTimer --- libsrc/core/profiler.hpp | 101 +++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/libsrc/core/profiler.hpp b/libsrc/core/profiler.hpp index b8bd09e8..0b647d82 100644 --- a/libsrc/core/profiler.hpp +++ b/libsrc/core/profiler.hpp @@ -148,15 +148,25 @@ namespace ngcore }; + struct TNoTracing{ static constexpr bool do_tracing=false; }; + struct TTracing{ static constexpr bool do_tracing=true; }; + + struct TNoTiming{ static constexpr bool do_timing=false; }; + struct TTiming{ static constexpr bool do_timing=true; }; + namespace detail { - struct NoTracing_t{}; - struct NoTiming_t{}; + + template + constexpr bool is_tracing_type_v = std::is_same_v || std::is_same_v; + + template + constexpr bool is_timing_type_v = std::is_same_v || std::is_same_v; } - static detail::NoTracing_t NoTracing; - static detail::NoTiming_t NoTiming; + static TNoTracing NoTracing; + static TNoTiming NoTiming; - template + template class Timer { int timernr; @@ -165,74 +175,68 @@ namespace ngcore return NgProfiler::CreateTimer (name); } public: - Timer (const std::string & name) : timernr(Init(name)) - { } + static constexpr bool do_tracing = TTracing::do_tracing; + static constexpr bool do_timing = TTiming::do_timing; - template> - Timer( const std::string & name, detail::NoTracing_t ) : timernr(Init(name)) - { } + Timer (const std::string & name) : timernr(Init(name)) { } - template> - Timer( const std::string & name, detail::NoTiming_t ) : timernr(Init(name)) - { } + template, bool> = false> + Timer( const std::string & name, TTracing ) : timernr(Init(name)) { } - template> - Timer( const std::string & name, detail::NoTracing_t, detail::NoTiming_t ) : timernr(Init(name)) - { } + template, bool> = false> + Timer( const std::string & name, TTiming ) : timernr(Init(name)) { } - template> - Timer( const std::string & name, detail::NoTiming_t, detail::NoTracing_t ) : timernr(Init(name)) - { } + Timer( const std::string & name, TTracing, TTiming ) : timernr(Init(name)) { } void SetName (const std::string & name) { NgProfiler::SetName (timernr, name); } - void Start () + void Start () const { Start(TaskManager::GetThreadId()); } - void Stop () + void Stop () const { Stop(TaskManager::GetThreadId()); } - void Start (int tid) + void Start (int tid) const { if(tid==0) { - if constexpr(DO_TIMING) + if constexpr(do_timing) NgProfiler::StartTimer (timernr); - if constexpr(DO_TRACING) + if constexpr(do_tracing) if(trace) trace->StartTimer(timernr); } else { - if constexpr(DO_TIMING) + if constexpr(do_timing) NgProfiler::StartThreadTimer(timernr, tid); - if constexpr(DO_TRACING) - trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER); + if constexpr(do_tracing) + if(trace) trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER); } } - void Stop (int tid) + void Stop (int tid) const { if(tid==0) { - if constexpr(DO_TIMING) + if constexpr(do_timing) NgProfiler::StopTimer (timernr); - if constexpr(DO_TRACING) + if constexpr(do_tracing) if(trace) trace->StopTimer(timernr); } else { - if constexpr(DO_TIMING) + if constexpr(do_timing) NgProfiler::StopThreadTimer(timernr, tid); - if constexpr(DO_TRACING) - trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER); + if constexpr(do_tracing) + if(trace) trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER); } } void AddFlops (double aflops) { - if constexpr(DO_TIMING) + if constexpr(do_timing) NgProfiler::AddFlops (timernr, aflops); } @@ -249,14 +253,14 @@ namespace ngcore Timer object. Start / stop timer at constructor / destructor. */ - template + template class RegionTimer { - Timer & timer; + const TTimer & timer; int tid; public: /// start timer - RegionTimer (Timer & atimer) : timer(atimer) + RegionTimer (const TTimer & atimer) : timer(atimer) { tid = TaskManager::GetThreadId(); timer.Start(tid); @@ -272,25 +276,6 @@ namespace ngcore 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; @@ -317,8 +302,8 @@ namespace ngcore nr = region_id; } /// start trace with timer - template - RegionTracer (int athread_id, Timer & timer, int additional_value = -1 ) + template + RegionTracer (int athread_id, TTimer & timer, int additional_value = -1 ) : thread_id(athread_id) { nr = timer;